From f73ff8cfce18ab7a1cdfb7045aeded6a4ab81d56 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 6 Dec 2019 18:12:24 +0800 Subject: [PATCH 001/777] Add a new static library for mainline modules Add a network static library for common utilities. This library could be used by all mainline modules. Initially create LinkPropertiesUtils and MacAddressUtils. Bug: 139268426 Bug: 135998869 Bug: 138306002 Test: build lib pass atest NetworkStaticLibTests Change-Id: I8f79e4f836819ac83007acffb55103e5d69873e0 --- staticlibs/Android.bp | 37 ++++ staticlibs/jarjar-rules-shared.txt | 1 + .../android/net/util/LinkPropertiesUtils.java | 164 +++++++++++++++ .../android/net/util/MacAddressUtils.java | 137 +++++++++++++ staticlibs/tests/unit/Android.bp | 18 ++ staticlibs/tests/unit/AndroidManifest.xml | 28 +++ .../net/util/LinkPropertiesUtilsTest.java | 188 ++++++++++++++++++ .../android/net/util/MacAddressUtilsTest.java | 76 +++++++ 8 files changed, 649 insertions(+) create mode 100644 staticlibs/Android.bp create mode 100644 staticlibs/jarjar-rules-shared.txt create mode 100644 staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java create mode 100644 staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java create mode 100644 staticlibs/tests/unit/Android.bp create mode 100644 staticlibs/tests/unit/AndroidManifest.xml create mode 100644 staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java create mode 100644 staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp new file mode 100644 index 0000000000..ffc02c3cd5 --- /dev/null +++ b/staticlibs/Android.bp @@ -0,0 +1,37 @@ +// Copyright (C) 2019 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. + +// File group "net-utils-framework-common-srcs" is also compiled into android framework. +// Add jarjar rules here so that anything outside of framework could use this library +// directly. + +filegroup { + name: "net-utils-framework-common-srcs", + srcs: ["src_frameworkcommon/**/*.java"], + visibility: ["//frameworks/base"], +} + +java_library { + name: "net-utils-framework-common", + srcs: [":net-utils-framework-common-srcs" ], + jarjar_rules: "jarjar-rules-shared.txt", + visibility: [ + "//frameworks/base/packages/Tethering", + "//frameworks/opt/net/wifi", + "//frameworks/opt/net/ike", + "//frameworks/opt/telephony", + "//packages/modules/NetworkStack", + "//packages/modules/CaptivePortalLogin", + ] +} diff --git a/staticlibs/jarjar-rules-shared.txt b/staticlibs/jarjar-rules-shared.txt new file mode 100644 index 0000000000..4a2b653429 --- /dev/null +++ b/staticlibs/jarjar-rules-shared.txt @@ -0,0 +1 @@ +rule android.net.util.** com.android.net.module.util.@1 diff --git a/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java b/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java new file mode 100644 index 0000000000..59d88accc8 --- /dev/null +++ b/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2019 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.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.RouteInfo; +import android.text.TextUtils; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +/** + * Collection of link properties utilities. + */ +public final class LinkPropertiesUtils { + + /** + * @param The type of data to compare. + */ + public static class CompareResult { + public final List removed = new ArrayList<>(); + public final List added = new ArrayList<>(); + + public CompareResult() {} + + public CompareResult(@Nullable Collection oldItems, @Nullable Collection newItems) { + if (oldItems != null) { + removed.addAll(oldItems); + } + if (newItems != null) { + for (T newItem : newItems) { + if (!removed.remove(newItem)) { + added.add(newItem); + } + } + } + } + + @Override + public String toString() { + return "removed=[" + TextUtils.join(",", removed) + + "] added=[" + TextUtils.join(",", added) + + "]"; + } + } + + /** + * Compares the addresses in {@code left} LinkProperties with {@code right} + * LinkProperties, examining only addresses on the base link. + * + * @param left A LinkProperties with the old list of addresses. + * @param right A LinkProperties with the new list of addresses. + * @return the differences between the addresses. + */ + public static @NonNull CompareResult compareAddresses( + @Nullable LinkProperties left, @Nullable LinkProperties right) { + /* + * Duplicate the LinkAddresses into removed, we will be removing + * address which are common between mLinkAddresses and target + * leaving the addresses that are different. And address which + * are in target but not in mLinkAddresses are placed in the + * addedAddresses. + */ + return new CompareResult<>(left != null ? left.getLinkAddresses() : null, + right != null ? right.getLinkAddresses() : null); + } + + /** + * Compares {@code left} {@code LinkProperties} interface addresses against the {@code right}. + * + * @param left A LinkProperties. + * @param right LinkProperties to be compared with {@code left}. + * @return {@code true} if both are identical, {@code false} otherwise. + */ + public static boolean isIdenticalAddresses(@NonNull LinkProperties left, + @NonNull LinkProperties right) { + final Collection leftAddresses = left.getAddresses(); + final Collection rightAddresses = right.getAddresses(); + return (leftAddresses.size() == rightAddresses.size()) + ? leftAddresses.containsAll(rightAddresses) : false; + } + + /** + * Compares {@code left} {@code LinkProperties} DNS addresses against the {@code right}. + * + * @param left A LinkProperties. + * @param right A LinkProperties to be compared with {@code left}. + * @return {@code true} if both are identical, {@code false} otherwise. + */ + public static boolean isIdenticalDnses(@NonNull LinkProperties left, + @NonNull LinkProperties right) { + final Collection leftDnses = left.getDnsServers(); + final Collection rightDnses = right.getDnsServers(); + + final String leftDomains = left.getDomains(); + final String rightDomains = right.getDomains(); + if (leftDomains == null) { + if (rightDomains != null) return false; + } else { + if (!leftDomains.equals(rightDomains)) return false; + } + return (leftDnses.size() == rightDnses.size()) + ? leftDnses.containsAll(rightDnses) : false; + } + + /** + * Compares {@code left} {@code LinkProperties} HttpProxy against the {@code right}. + * + * @param left A LinkProperties. + * @param right A LinkProperties to be compared with {@code left}. + * @return {@code true} if both are identical, {@code false} otherwise. + */ + public static boolean isIdenticalHttpProxy(@NonNull LinkProperties left, + @NonNull LinkProperties right) { + return Objects.equals(left.getHttpProxy(), right.getHttpProxy()); + } + + /** + * Compares {@code left} {@code LinkProperties} interface name against the {@code right}. + * + * @param left A LinkProperties. + * @param right A LinkProperties to be compared with {@code left}. + * @return {@code true} if both are identical, {@code false} otherwise. + */ + public static boolean isIdenticalInterfaceName(@NonNull LinkProperties left, + @NonNull LinkProperties right) { + return TextUtils.equals(left.getInterfaceName(), right.getInterfaceName()); + } + + /** + * Compares {@code left} {@code LinkProperties} Routes against the {@code right}. + * + * @param left A LinkProperties. + * @param right A LinkProperties to be compared with {@code left}. + * @return {@code true} if both are identical, {@code false} otherwise. + */ + public static boolean isIdenticalRoutes(@NonNull LinkProperties left, + @NonNull LinkProperties right) { + final Collection leftRoutes = left.getRoutes(); + final Collection rightRoutes = right.getRoutes(); + return (leftRoutes.size() == rightRoutes.size()) + ? leftRoutes.containsAll(rightRoutes) : false; + } +} diff --git a/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java b/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java new file mode 100644 index 0000000000..53457893ca --- /dev/null +++ b/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java @@ -0,0 +1,137 @@ +/* + * Copyright 2019 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.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.MacAddress; + +import com.android.internal.util.BitUtils; +import com.android.internal.util.Preconditions; + +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Random; + +/** + * Collection of MAC address utilities. + */ +public final class MacAddressUtils { + + private static final long VALID_LONG_MASK = (1L << 48) - 1; + private static final long LOCALLY_ASSIGNED_MASK = longAddrFromByteAddr( + MacAddress.fromString("2:0:0:0:0:0").toByteArray()); + private static final long MULTICAST_MASK = longAddrFromByteAddr( + MacAddress.fromString("1:0:0:0:0:0").toByteArray()); + private static final long OUI_MASK = longAddrFromByteAddr( + MacAddress.fromString("ff:ff:ff:0:0:0").toByteArray()); + private static final long NIC_MASK = longAddrFromByteAddr( + MacAddress.fromString("0:0:0:ff:ff:ff").toByteArray()); + // Matches WifiInfo.DEFAULT_MAC_ADDRESS + private static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00"; + private static final int ETHER_ADDR_LEN = 6; + + /** + * @return true if this MacAddress is a multicast address. + */ + public static boolean isMulticastAddress(@NonNull MacAddress address) { + return (longAddrFromByteAddr(address.toByteArray()) & MULTICAST_MASK) != 0; + } + + /** + * Returns a generated MAC address whose 46 bits, excluding the locally assigned bit and the + * unicast bit, are randomly selected. + * + * The locally assigned bit is always set to 1. The multicast bit is always set to 0. + * + * @return a random locally assigned, unicast MacAddress. + */ + public static @NonNull MacAddress createRandomUnicastAddress() { + return createRandomUnicastAddress(null, new SecureRandom()); + } + + /** + * Returns a randomly generated MAC address using the given Random object and the same + * OUI values as the given MacAddress. + * + * The locally assigned bit is always set to 1. The multicast bit is always set to 0. + * + * @param base a base MacAddress whose OUI is used for generating the random address. + * If base == null then the OUI will also be randomized. + * @param r a standard Java Random object used for generating the random address. + * @return a random locally assigned MacAddress. + */ + public static @NonNull MacAddress createRandomUnicastAddress(@Nullable MacAddress base, + @NonNull Random r) { + long addr; + + if (base == null) { + addr = r.nextLong() & VALID_LONG_MASK; + } else { + addr = (longAddrFromByteAddr(base.toByteArray()) & OUI_MASK) + | (NIC_MASK & r.nextLong()); + } + addr |= LOCALLY_ASSIGNED_MASK; + addr &= ~MULTICAST_MASK; + MacAddress mac = MacAddress.fromBytes(byteAddrFromLongAddr(addr)); + if (mac.equals(DEFAULT_MAC_ADDRESS)) { + return createRandomUnicastAddress(base, r); + } + return mac; + } + + /** + * Convert a byte address to long address. + */ + public static long longAddrFromByteAddr(byte[] addr) { + Preconditions.checkNotNull(addr); + if (!isMacAddress(addr)) { + throw new IllegalArgumentException( + Arrays.toString(addr) + " was not a valid MAC address"); + } + long longAddr = 0; + for (byte b : addr) { + longAddr = (longAddr << 8) + BitUtils.uint8(b); + } + return longAddr; + } + + /** + * Convert a long address to byte address. + */ + public static byte[] byteAddrFromLongAddr(long addr) { + byte[] bytes = new byte[ETHER_ADDR_LEN]; + int index = ETHER_ADDR_LEN; + while (index-- > 0) { + bytes[index] = (byte) addr; + addr = addr >> 8; + } + return bytes; + } + + /** + * Returns true if the given byte array is a valid MAC address. + * A valid byte array representation for a MacAddress is a non-null array of length 6. + * + * @param addr a byte array. + * @return true if the given byte array is not null and has the length of a MAC address. + * + */ + public static boolean isMacAddress(byte[] addr) { + return addr != null && addr.length == ETHER_ADDR_LEN; + } +} diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp new file mode 100644 index 0000000000..4a51a8c2d3 --- /dev/null +++ b/staticlibs/tests/unit/Android.bp @@ -0,0 +1,18 @@ +//######################################################################## +// Build NetworkStaticLibTests package +//######################################################################## + +android_test { + name: "NetworkStaticLibTests", + certificate: "platform", + srcs: ["src/**/*.java","src/**/*.kt"], + test_suites: ["device-tests"], + static_libs: [ + "androidx.test.rules", + ], + libs: [ + "android.test.runner", + "android.test.base", + ], +} + diff --git a/staticlibs/tests/unit/AndroidManifest.xml b/staticlibs/tests/unit/AndroidManifest.xml new file mode 100644 index 0000000000..cc9e09ea76 --- /dev/null +++ b/staticlibs/tests/unit/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + diff --git a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java new file mode 100644 index 0000000000..6e06ee877b --- /dev/null +++ b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2019 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.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.net.InetAddresses; +import android.net.IpPrefix; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.ProxyInfo; +import android.net.RouteInfo; +import android.net.util.LinkPropertiesUtils.CompareResult; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; + +@RunWith(AndroidJUnit4.class) +public final class LinkPropertiesUtilsTest { + private static final IpPrefix PREFIX = new IpPrefix(toInetAddress("75.208.6.0"), 24); + private static final InetAddress V4_ADDR = toInetAddress("75.208.6.1"); + private static final InetAddress V6_ADDR = toInetAddress( + "2001:0db8:85a3:0000:0000:8a2e:0370:7334"); + private static final InetAddress DNS1 = toInetAddress("75.208.7.1"); + private static final InetAddress DNS2 = toInetAddress("69.78.7.1"); + + private static final InetAddress GATEWAY1 = toInetAddress("75.208.8.1"); + private static final InetAddress GATEWAY2 = toInetAddress("69.78.8.1"); + + private static final String IF_NAME = "wlan0"; + private static final LinkAddress V4_LINKADDR = new LinkAddress(V4_ADDR, 32); + private static final LinkAddress V6_LINKADDR = new LinkAddress(V6_ADDR, 128); + private static final RouteInfo RT_INFO1 = new RouteInfo(PREFIX, GATEWAY1, IF_NAME); + private static final RouteInfo RT_INFO2 = new RouteInfo(PREFIX, GATEWAY2, IF_NAME); + private static final String TEST_DOMAIN = "link.properties.com"; + + private static InetAddress toInetAddress(String addrString) { + return InetAddresses.parseNumericAddress(addrString); + } + + private LinkProperties createTestObject() { + final LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(IF_NAME); + lp.addLinkAddress(V4_LINKADDR); + lp.addLinkAddress(V6_LINKADDR); + lp.addDnsServer(DNS1); + lp.addDnsServer(DNS2); + lp.setDomains(TEST_DOMAIN); + lp.addRoute(RT_INFO1); + lp.addRoute(RT_INFO2); + lp.setHttpProxy(ProxyInfo.buildDirectProxy("test", 8888)); + return lp; + } + + @Test + public void testLinkPropertiesIdenticalEqual() { + final LinkProperties source = createTestObject(); + final LinkProperties target = new LinkProperties(source); + + assertTrue(LinkPropertiesUtils.isIdenticalInterfaceName(source, target)); + assertTrue(LinkPropertiesUtils.isIdenticalInterfaceName(target, source)); + + assertTrue(LinkPropertiesUtils.isIdenticalAddresses(source, target)); + assertTrue(LinkPropertiesUtils.isIdenticalAddresses(target, source)); + + assertTrue(LinkPropertiesUtils.isIdenticalDnses(source, target)); + assertTrue(LinkPropertiesUtils.isIdenticalDnses(target, source)); + + assertTrue(LinkPropertiesUtils.isIdenticalRoutes(source, target)); + assertTrue(LinkPropertiesUtils.isIdenticalRoutes(target, source)); + + assertTrue(LinkPropertiesUtils.isIdenticalHttpProxy(source, target)); + assertTrue(LinkPropertiesUtils.isIdenticalHttpProxy(target, source)); + + // Test different interface name. + target.setInterfaceName("lo"); + assertFalse(LinkPropertiesUtils.isIdenticalInterfaceName(source, target)); + assertFalse(LinkPropertiesUtils.isIdenticalInterfaceName(target, source)); + // Restore interface name + target.setInterfaceName(IF_NAME); + + // Compare addresses.size() not equals. + final LinkAddress testLinkAddr = new LinkAddress(toInetAddress("75.208.6.2"), 32); + target.addLinkAddress(testLinkAddr); + assertFalse(LinkPropertiesUtils.isIdenticalAddresses(source, target)); + assertFalse(LinkPropertiesUtils.isIdenticalAddresses(target, source)); + + // Currently, target contains V4_LINKADDR, V6_LINKADDR and testLinkAddr. + // Compare addresses.size() equals but contains different address. + target.removeLinkAddress(V4_LINKADDR); + assertEquals(source.getAddresses().size(), target.getAddresses().size()); + assertFalse(LinkPropertiesUtils.isIdenticalAddresses(source, target)); + assertFalse(LinkPropertiesUtils.isIdenticalAddresses(target, source)); + // Restore link address + target.addLinkAddress(V4_LINKADDR); + target.removeLinkAddress(testLinkAddr); + + // Compare size not equals. + target.addDnsServer(toInetAddress("75.208.10.1")); + assertFalse(LinkPropertiesUtils.isIdenticalDnses(source, target)); + assertFalse(LinkPropertiesUtils.isIdenticalDnses(target, source)); + + // Compare the same servers but target has different domains. + target.removeDnsServer(toInetAddress("75.208.10.1")); + target.setDomains("test.com"); + assertFalse(LinkPropertiesUtils.isIdenticalDnses(source, target)); + assertFalse(LinkPropertiesUtils.isIdenticalDnses(target, source)); + + // Test null domain. + target.setDomains(null); + assertFalse(LinkPropertiesUtils.isIdenticalDnses(source, target)); + assertFalse(LinkPropertiesUtils.isIdenticalDnses(target, source)); + // Restore domain + target.setDomains(TEST_DOMAIN); + + // Compare size not equals. + final RouteInfo testRoute = new RouteInfo(toInetAddress("75.208.7.1")); + target.addRoute(testRoute); + assertFalse(LinkPropertiesUtils.isIdenticalRoutes(source, target)); + assertFalse(LinkPropertiesUtils.isIdenticalRoutes(target, source)); + + // Currently, target contains RT_INFO1, RT_INFO2 and testRoute. + // Compare size equals but different routes. + target.removeRoute(RT_INFO1); + assertEquals(source.getRoutes().size(), target.getRoutes().size()); + assertFalse(LinkPropertiesUtils.isIdenticalRoutes(source, target)); + assertFalse(LinkPropertiesUtils.isIdenticalRoutes(target, source)); + // Restore route + target.addRoute(RT_INFO1); + target.removeRoute(testRoute); + + // Test different proxy. + target.setHttpProxy(ProxyInfo.buildDirectProxy("hello", 8888)); + assertFalse(LinkPropertiesUtils.isIdenticalHttpProxy(source, target)); + assertFalse(LinkPropertiesUtils.isIdenticalHttpProxy(target, source)); + + // Test null proxy. + target.setHttpProxy(null); + assertFalse(LinkPropertiesUtils.isIdenticalHttpProxy(source, target)); + assertFalse(LinkPropertiesUtils.isIdenticalHttpProxy(target, source)); + } + + @Test + public void testCompareAddresses() { + final LinkProperties source = createTestObject(); + final LinkProperties target = new LinkProperties(source); + final InetAddress addr1 = toInetAddress("75.208.6.2"); + final LinkAddress linkAddr1 = new LinkAddress(addr1, 32); + + CompareResult results = LinkPropertiesUtils.compareAddresses(source, target); + assertEquals(0, results.removed.size()); + assertEquals(0, results.added.size()); + + source.addLinkAddress(linkAddr1); + results = LinkPropertiesUtils.compareAddresses(source, target); + assertEquals(1, results.removed.size()); + assertEquals(linkAddr1, results.removed.get(0)); + assertEquals(0, results.added.size()); + + final InetAddress addr2 = toInetAddress("75.208.6.3"); + final LinkAddress linkAddr2 = new LinkAddress(addr2, 32); + + target.addLinkAddress(linkAddr2); + results = LinkPropertiesUtils.compareAddresses(source, target); + assertEquals(linkAddr1, results.removed.get(0)); + assertEquals(linkAddr2, results.added.get(0)); + } +} diff --git a/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java new file mode 100644 index 0000000000..ad63b3c9eb --- /dev/null +++ b/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2019 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.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.net.MacAddress; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public final class MacAddressUtilsTest { + + // Matches WifiInfo.DEFAULT_MAC_ADDRESS + private static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00"; + + @Test + public void testIsMulticastAddress() { + MacAddress[] multicastAddresses = { + // broadcast address + MacAddress.fromString("ff:ff:ff:ff:ff:ff"), + MacAddress.fromString("07:00:d3:56:8a:c4"), + MacAddress.fromString("33:33:aa:bb:cc:dd"), + }; + MacAddress[] unicastAddresses = { + // all zero address + MacAddress.fromString("00:00:00:00:00:00"), + MacAddress.fromString("00:01:44:55:66:77"), + MacAddress.fromString("08:00:22:33:44:55"), + MacAddress.fromString("06:00:00:00:00:00"), + }; + + for (MacAddress mac : multicastAddresses) { + String msg = mac.toString() + " expected to be a multicast address"; + assertTrue(msg, MacAddressUtils.isMulticastAddress(mac)); + } + for (MacAddress mac : unicastAddresses) { + String msg = mac.toString() + " expected not to be a multicast address"; + assertFalse(msg, MacAddressUtils.isMulticastAddress(mac)); + } + } + + @Test + public void testMacAddressRandomGeneration() { + final int iterations = 1000; + + for (int i = 0; i < iterations; i++) { + MacAddress mac = MacAddressUtils.createRandomUnicastAddress(); + String stringRepr = mac.toString(); + + assertTrue(stringRepr + " expected to be a locally assigned address", + mac.isLocallyAssigned()); + assertEquals(MacAddress.TYPE_UNICAST, mac.getAddressType()); + assertFalse(mac.equals(DEFAULT_MAC_ADDRESS)); + } + } +} From 05a9dfef78516100e4f9f52b2547ea65c148f696 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 11 Dec 2019 09:04:29 +0800 Subject: [PATCH 002/777] Add NetUtils to net static library This class includes network common utilities. Bug: 139268426 Bug: 135998869 Bug: 138306002 Bug: 143925787 Test: build lib pass atest NetworkStaticLibTests Change-Id: I1ffe723aa4ff2ed7bc46f34106701c91fe93032a --- .../android/net/util/NetUtils.java | 69 ++++++++++++ .../src/android/net/util/NetUtilsTest.java | 105 ++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 staticlibs/src_frameworkcommon/android/net/util/NetUtils.java create mode 100644 staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java diff --git a/staticlibs/src_frameworkcommon/android/net/util/NetUtils.java b/staticlibs/src_frameworkcommon/android/net/util/NetUtils.java new file mode 100644 index 0000000000..e0065904fb --- /dev/null +++ b/staticlibs/src_frameworkcommon/android/net/util/NetUtils.java @@ -0,0 +1,69 @@ +/* + * Copyright 2019 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.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.RouteInfo; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.util.Collection; + +/** + * Collection of network common utilities. + */ +public final class NetUtils { + + /** + * Check if IP address type is consistent between two InetAddress. + * @return true if both are the same type. False otherwise. + */ + public static boolean addressTypeMatches(@NonNull InetAddress left, + @NonNull InetAddress right) { + return (((left instanceof Inet4Address) && (right instanceof Inet4Address)) + || ((left instanceof Inet6Address) && (right instanceof Inet6Address))); + } + + /** + * Find the route from a Collection of routes that best matches a given address. + * May return null if no routes are applicable. + * @param routes a Collection of RouteInfos to chose from + * @param dest the InetAddress your trying to get to + * @return the RouteInfo from the Collection that best fits the given address + */ + @Nullable + public static RouteInfo selectBestRoute(@Nullable Collection routes, + @Nullable InetAddress dest) { + if ((routes == null) || (dest == null)) return null; + + RouteInfo bestRoute = null; + // pick a longest prefix match under same address type + for (RouteInfo route : routes) { + if (addressTypeMatches(route.getDestination().getAddress(), dest)) { + if ((bestRoute != null) + && (bestRoute.getDestination().getPrefixLength() + >= route.getDestination().getPrefixLength())) { + continue; + } + if (route.matches(dest)) bestRoute = route; + } + } + return bestRoute; + } +} diff --git a/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java new file mode 100644 index 0000000000..903e80d369 --- /dev/null +++ b/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2019 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.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import android.net.InetAddresses; +import android.net.IpPrefix; +import android.net.RouteInfo; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +public final class NetUtilsTest { + private static final InetAddress V4_ADDR1 = toInetAddress("75.208.7.1"); + private static final InetAddress V4_ADDR2 = toInetAddress("75.208.7.2"); + private static final InetAddress V6_ADDR1 = toInetAddress("2001:0db8:85a3::8a2e:0370:7334"); + private static final InetAddress V6_ADDR2 = toInetAddress("2001:0db8:85a3::8a2e:0370:7335"); + + private static final InetAddress V4_GATEWAY = toInetAddress("75.208.8.1"); + private static final InetAddress V6_GATEWAY = toInetAddress("fe80::6:0000:613"); + + private static InetAddress toInetAddress(String addr) { + return InetAddresses.parseNumericAddress(addr); + } + @Test + public void testAddressTypeMatches() { + assertTrue(NetUtils.addressTypeMatches(V4_ADDR1, V4_ADDR2)); + assertTrue(NetUtils.addressTypeMatches(V6_ADDR1, V6_ADDR2)); + assertFalse(NetUtils.addressTypeMatches(V4_ADDR1, V6_ADDR1)); + assertFalse(NetUtils.addressTypeMatches(V6_ADDR1, V4_ADDR1)); + } + + @Test + public void testSelectBestRoute() { + final List routes = new ArrayList<>(); + final InetAddress v4_dest = InetAddresses.parseNumericAddress("75.208.8.15"); + final InetAddress v6_dest = InetAddresses.parseNumericAddress("2001:db8:cafe::123"); + + RouteInfo route = NetUtils.selectBestRoute(null, v4_dest); + assertEquals(null, route); + route = NetUtils.selectBestRoute(routes, null); + assertEquals(null, route); + + route = NetUtils.selectBestRoute(routes, v4_dest); + assertEquals(null, route); + + final RouteInfo v4_expected = new RouteInfo(new IpPrefix("75.208.8.10/24"), + V4_GATEWAY, "wlan0"); + routes.add(v4_expected); + // "75.208.8.10/16" is not an expected result since it is not the longest prefix. + routes.add(new RouteInfo(new IpPrefix("75.208.8.10/16"), V4_GATEWAY, "wlan0")); + routes.add(new RouteInfo(new IpPrefix("75.208.7.32/24"), V4_GATEWAY, "wlan0")); + + final RouteInfo v6_expected = new RouteInfo(new IpPrefix("2001:db8:cafe::/64"), + V6_GATEWAY, "wlan0"); + routes.add(v6_expected); + // "2001:db8:cafe::123/32" is not an expected result since it is not the longest prefix. + routes.add(new RouteInfo(new IpPrefix("2001:db8:cafe::123/32"), V6_GATEWAY, "wlan0")); + routes.add(new RouteInfo(new IpPrefix("2001:db8:beef::/64"), V6_GATEWAY, "wlan0")); + + // Verify expected v4 route is selected + route = NetUtils.selectBestRoute(routes, v4_dest); + assertEquals(v4_expected, route); + + // Verify expected v6 route is selected + route = NetUtils.selectBestRoute(routes, v6_dest); + assertEquals(v6_expected, route); + + // Remove expected v4 route + routes.remove(v4_expected); + route = NetUtils.selectBestRoute(routes, v4_dest); + assertNotEquals(v4_expected, route); + + // Remove expected v6 route + routes.remove(v6_expected); + route = NetUtils.selectBestRoute(routes, v4_dest); + assertNotEquals(v6_expected, route); + } +} + From 935612ca6fae690bc77c6c4745b24d5a57205b0d Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 6 Jan 2020 20:01:12 +0800 Subject: [PATCH 003/777] Add DnsSdTxtRecord to common net static library Move DnsSdTxtRecord from framework to net-utils-framework-common for mainline support. Bug: 139268426 Bug: 135998869 Test: build lib pass atest FrameworksNetTests ./frameworks/opt/net/wifi/tests/wifitests/runtests.sh Change-Id: I16c37b1c0b70bd57f38bde1171bd7d84cf3fa9ce --- .../android/net/util/nsd/DnsSdTxtRecord.java | 325 ++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 staticlibs/src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java diff --git a/staticlibs/src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java b/staticlibs/src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java new file mode 100644 index 0000000000..81768f7ed1 --- /dev/null +++ b/staticlibs/src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java @@ -0,0 +1,325 @@ +/* -*- Mode: Java; tab-width: 4 -*- + * + * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * + * 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. + + To do: + - implement remove() + - fix set() to replace existing values + */ + +package android.net.util.nsd; + +import android.os.Parcelable; +import android.os.Parcel; + +import java.util.Arrays; + +/** + * This class handles TXT record data for DNS based service discovery as specified at + * http://tools.ietf.org/html/draft-cheshire-dnsext-dns-sd-11 + * + * DNS-SD specifies that a TXT record corresponding to an SRV record consist of + * a packed array of bytes, each preceded by a length byte. Each string + * is an attribute-value pair. + * + * The DnsSdTxtRecord object stores the entire TXT data as a single byte array, traversing it + * as need be to implement its various methods. + * @hide + * + */ +public class DnsSdTxtRecord implements Parcelable { + private static final byte mSeparator = '='; + + private byte[] mData; + + /** Constructs a new, empty TXT record. */ + public DnsSdTxtRecord() { + mData = new byte[0]; + } + + /** Constructs a new TXT record from a byte array in the standard format. */ + public DnsSdTxtRecord(byte[] data) { + mData = (byte[]) data.clone(); + } + + /** Copy constructor */ + public DnsSdTxtRecord(DnsSdTxtRecord src) { + if (src != null && src.mData != null) { + mData = (byte[]) src.mData.clone(); + } + } + + /** + * Set a key/value pair. Setting an existing key will replace its value. + * @param key Must be ascii with no '=' + * @param value matching value to key + */ + public void set(String key, String value) { + byte[] keyBytes; + byte[] valBytes; + int valLen; + + if (value != null) { + valBytes = value.getBytes(); + valLen = valBytes.length; + } else { + valBytes = null; + valLen = 0; + } + + try { + keyBytes = key.getBytes("US-ASCII"); + } + catch (java.io.UnsupportedEncodingException e) { + throw new IllegalArgumentException("key should be US-ASCII"); + } + + for (int i = 0; i < keyBytes.length; i++) { + if (keyBytes[i] == '=') { + throw new IllegalArgumentException("= is not a valid character in key"); + } + } + + if (keyBytes.length + valLen >= 255) { + throw new IllegalArgumentException("Key and Value length cannot exceed 255 bytes"); + } + + int currentLoc = remove(key); + if (currentLoc == -1) + currentLoc = keyCount(); + + insert(keyBytes, valBytes, currentLoc); + } + + /** + * Get a value for a key + * + * @param key + * @return The value associated with the key + */ + public String get(String key) { + byte[] val = this.getValue(key); + return val != null ? new String(val) : null; + } + + /** Remove a key/value pair. If found, returns the index or -1 if not found */ + public int remove(String key) { + int avStart = 0; + + for (int i=0; avStart < mData.length; i++) { + int avLen = mData[avStart]; + if (key.length() <= avLen && + (key.length() == avLen || mData[avStart + key.length() + 1] == mSeparator)) { + String s = new String(mData, avStart + 1, key.length()); + if (0 == key.compareToIgnoreCase(s)) { + byte[] oldBytes = mData; + mData = new byte[oldBytes.length - avLen - 1]; + System.arraycopy(oldBytes, 0, mData, 0, avStart); + System.arraycopy(oldBytes, avStart + avLen + 1, mData, avStart, + oldBytes.length - avStart - avLen - 1); + return i; + } + } + avStart += (0xFF & (avLen + 1)); + } + return -1; + } + + /** Return the count of keys */ + public int keyCount() { + int count = 0, nextKey; + for (nextKey = 0; nextKey < mData.length; count++) { + nextKey += (0xFF & (mData[nextKey] + 1)); + } + return count; + } + + /** Return true if key is present, false if not. */ + public boolean contains(String key) { + String s = null; + for (int i = 0; null != (s = this.getKey(i)); i++) { + if (0 == key.compareToIgnoreCase(s)) return true; + } + return false; + } + + /* Gets the size in bytes */ + public int size() { + return mData.length; + } + + /* Gets the raw data in bytes */ + public byte[] getRawData() { + return (byte[]) mData.clone(); + } + + private void insert(byte[] keyBytes, byte[] value, int index) { + byte[] oldBytes = mData; + int valLen = (value != null) ? value.length : 0; + int insertion = 0; + int newLen, avLen; + + for (int i = 0; i < index && insertion < mData.length; i++) { + insertion += (0xFF & (mData[insertion] + 1)); + } + + avLen = keyBytes.length + valLen + (value != null ? 1 : 0); + newLen = avLen + oldBytes.length + 1; + + mData = new byte[newLen]; + System.arraycopy(oldBytes, 0, mData, 0, insertion); + int secondHalfLen = oldBytes.length - insertion; + System.arraycopy(oldBytes, insertion, mData, newLen - secondHalfLen, secondHalfLen); + mData[insertion] = (byte) avLen; + System.arraycopy(keyBytes, 0, mData, insertion + 1, keyBytes.length); + if (value != null) { + mData[insertion + 1 + keyBytes.length] = mSeparator; + System.arraycopy(value, 0, mData, insertion + keyBytes.length + 2, valLen); + } + } + + /** Return a key in the TXT record by zero-based index. Returns null if index exceeds the total number of keys. */ + private String getKey(int index) { + int avStart = 0; + + for (int i=0; i < index && avStart < mData.length; i++) { + avStart += mData[avStart] + 1; + } + + if (avStart < mData.length) { + int avLen = mData[avStart]; + int aLen = 0; + + for (aLen=0; aLen < avLen; aLen++) { + if (mData[avStart + aLen + 1] == mSeparator) break; + } + return new String(mData, avStart + 1, aLen); + } + return null; + } + + /** + * Look up a key in the TXT record by zero-based index and return its value. + * Returns null if index exceeds the total number of keys. + * Returns null if the key is present with no value. + */ + private byte[] getValue(int index) { + int avStart = 0; + byte[] value = null; + + for (int i=0; i < index && avStart < mData.length; i++) { + avStart += mData[avStart] + 1; + } + + if (avStart < mData.length) { + int avLen = mData[avStart]; + int aLen = 0; + + for (aLen=0; aLen < avLen; aLen++) { + if (mData[avStart + aLen + 1] == mSeparator) { + value = new byte[avLen - aLen - 1]; + System.arraycopy(mData, avStart + aLen + 2, value, 0, avLen - aLen - 1); + break; + } + } + } + return value; + } + + private String getValueAsString(int index) { + byte[] value = this.getValue(index); + return value != null ? new String(value) : null; + } + + private byte[] getValue(String forKey) { + String s = null; + int i; + + for (i = 0; null != (s = this.getKey(i)); i++) { + if (0 == forKey.compareToIgnoreCase(s)) { + return this.getValue(i); + } + } + + return null; + } + + /** + * Return a string representation. + * Example : {key1=value1},{key2=value2}.. + * + * For a key say like "key3" with null value + * {key1=value1},{key2=value2}{key3} + */ + public String toString() { + String a, result = null; + + for (int i = 0; null != (a = this.getKey(i)); i++) { + String av = "{" + a; + String val = this.getValueAsString(i); + if (val != null) + av += "=" + val + "}"; + else + av += "}"; + if (result == null) + result = av; + else + result = result + ", " + av; + } + return result != null ? result : ""; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof DnsSdTxtRecord)) { + return false; + } + + DnsSdTxtRecord record = (DnsSdTxtRecord)o; + return Arrays.equals(record.mData, mData); + } + + @Override + public int hashCode() { + return Arrays.hashCode(mData); + } + + /** Implement the Parcelable interface */ + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeByteArray(mData); + } + + /** Implement the Parcelable interface */ + public static final @android.annotation.NonNull Creator CREATOR = + new Creator() { + public DnsSdTxtRecord createFromParcel(Parcel in) { + DnsSdTxtRecord info = new DnsSdTxtRecord(); + in.readByteArray(info.mData); + return info; + } + + public DnsSdTxtRecord[] newArray(int size) { + return new DnsSdTxtRecord[size]; + } + }; +} From 1fb6a3742ac81b08ba66c438443884b6942a236f Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 3 Jan 2020 20:35:55 +0800 Subject: [PATCH 004/777] Add net-utils-services-common library net-utils-services-common-srcs for files in src_servicescommon and library net-utils-services-common could be used in services.jar or modules. Bug: 138306002 Bug: 139268426 Test: atest FrameworksNetTests FrameworksTelephonyTests Change-Id: I5043a34100e9ef26148e3a0c1743363d063a3604 --- staticlibs/Android.bp | 21 +- .../android/net/NetworkFactory.java | 449 ++++++++++++++++++ 2 files changed, 467 insertions(+), 3 deletions(-) create mode 100644 staticlibs/src_servicescommon/android/net/NetworkFactory.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index ffc02c3cd5..5c851fd2f7 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -12,9 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -// File group "net-utils-framework-common-srcs" is also compiled into android framework. -// Add jarjar rules here so that anything outside of framework could use this library -// directly. +// 1. The "net-utils-framework-common" library is also compiled into the framework and placed on the +// boot classpath. It uses jarjar rules so that anything outside the framework can use this +// library directly. +// 2. The "net-utils-services-common" library is for use by modules and frameworks/base/services. +// It does not need to be jarjared because it is not placed on the bootclasspath. filegroup { name: "net-utils-framework-common-srcs", @@ -35,3 +37,16 @@ java_library { "//packages/modules/CaptivePortalLogin", ] } + +java_library { + name: "net-utils-services-common", + srcs: ["src_servicescommon/**/*.java"], + visibility: [ + "//frameworks/base/services", + "//frameworks/base/packages/Tethering", + "//frameworks/opt/net/wifi/service", + "//frameworks/opt/net/ike", + "//packages/modules/NetworkStack", + "//packages/modules/CaptivePortalLogin", + ], +} diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java new file mode 100644 index 0000000000..479a191fc4 --- /dev/null +++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2014 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 android.annotation.NonNull; +import android.content.Context; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.util.Log; +import android.util.SparseArray; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.Protocol; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * A NetworkFactory is an entity that creates NetworkAgent objects. + * The bearers register with ConnectivityService using {@link #register} and + * their factory will start receiving scored NetworkRequests. NetworkRequests + * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by + * overridden function. All of these can be dynamic - changing NetworkCapabilities + * or score forces re-evaluation of all current requests. + * + * If any requests pass the filter some overrideable functions will be called. + * If the bearer only cares about very simple start/stopNetwork callbacks, those + * functions can be overridden. If the bearer needs more interaction, it can + * override addNetworkRequest and removeNetworkRequest which will give it each + * request that passes their current filters. + * @hide + **/ +public class NetworkFactory extends Handler { + /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ + public static class SerialNumber { + // Guard used by no network factory. + public static final int NONE = -1; + // A hardcoded serial number for NetworkAgents representing VPNs. These agents are + // not created by any factory, so they use this constant for clarity instead of NONE. + public static final int VPN = -2; + private static final AtomicInteger sNetworkFactorySerialNumber = new AtomicInteger(1); + /** Returns a unique serial number for a factory. */ + public static final int nextSerialNumber() { + return sNetworkFactorySerialNumber.getAndIncrement(); + } + } + + private static final boolean DBG = true; + private static final boolean VDBG = false; + + private static final int BASE = Protocol.BASE_NETWORK_FACTORY; + /** + * Pass a network request to the bearer. If the bearer believes it can + * satisfy the request it should connect to the network and create a + * NetworkAgent. Once the NetworkAgent is fully functional it will + * register itself with ConnectivityService using registerNetworkAgent. + * If the bearer cannot immediately satisfy the request (no network, + * user disabled the radio, lower-scored network) it should remember + * any NetworkRequests it may be able to satisfy in the future. It may + * disregard any that it will never be able to service, for example + * those requiring a different bearer. + * msg.obj = NetworkRequest + * msg.arg1 = score - the score of the network currently satisfying this + * request. If this bearer knows in advance it cannot + * exceed this score it should not try to connect, holding the request + * for the future. + * Note that subsequent events may give a different (lower + * or higher) score for this request, transmitted to each + * NetworkFactory through additional CMD_REQUEST_NETWORK msgs + * with the same NetworkRequest but an updated score. + * Also, network conditions may change for this bearer + * allowing for a better score in the future. + * msg.arg2 = the ID of the NetworkProvider currently responsible for the + * NetworkAgent handling this request, or NetworkProvider.ID_NONE if none. + */ + public static final int CMD_REQUEST_NETWORK = BASE; + + /** + * Cancel a network request + * msg.obj = NetworkRequest + */ + public static final int CMD_CANCEL_REQUEST = BASE + 1; + + /** + * Internally used to set our best-guess score. + * msg.arg1 = new score + */ + private static final int CMD_SET_SCORE = BASE + 2; + + /** + * Internally used to set our current filter for coarse bandwidth changes with + * technology changes. + * msg.obj = new filter + */ + private static final int CMD_SET_FILTER = BASE + 3; + + private final Context mContext; + private final ArrayList mPreConnectedQueue = new ArrayList(); + private final String LOG_TAG; + + private final SparseArray mNetworkRequests = + new SparseArray(); + + private int mScore; + private NetworkCapabilities mCapabilityFilter; + + private int mRefCount = 0; + private Messenger mMessenger = null; + private NetworkProvider mProvider = null; + private int mProviderId; + + public NetworkFactory(Looper looper, Context context, String logTag, + NetworkCapabilities filter) { + super(looper); + LOG_TAG = logTag; + mContext = context; + mCapabilityFilter = filter; + } + + public void register() { + if (mProvider != null) { + Log.e(LOG_TAG, "Ignoring attempt to register already-registered NetworkFactory"); + return; + } + if (DBG) log("Registering NetworkFactory"); + + mProvider = new NetworkProvider(mContext, NetworkFactory.this.getLooper(), LOG_TAG) { + @Override + public void onNetworkRequested(@NonNull NetworkRequest request, int score, + int servingProviderId) { + handleAddRequest((NetworkRequest) request, score, servingProviderId); + } + + @Override + public void onRequestWithdrawn(@NonNull NetworkRequest request) { + handleRemoveRequest(request); + } + }; + + mMessenger = new Messenger(this); + mProviderId = ConnectivityManager.from(mContext).registerNetworkProvider(mProvider); + } + + public void unregister() { + if (mProvider == null) { + Log.e(LOG_TAG, "Ignoring attempt to unregister unregistered NetworkFactory"); + return; + } + if (DBG) log("Unregistering NetworkFactory"); + + ConnectivityManager.from(mContext).unregisterNetworkProvider(mProvider); + mProvider = null; + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case CMD_REQUEST_NETWORK: { + handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2); + break; + } + case CMD_CANCEL_REQUEST: { + handleRemoveRequest((NetworkRequest) msg.obj); + break; + } + case CMD_SET_SCORE: { + handleSetScore(msg.arg1); + break; + } + case CMD_SET_FILTER: { + handleSetFilter((NetworkCapabilities) msg.obj); + break; + } + } + } + + private class NetworkRequestInfo { + public final NetworkRequest request; + public int score; + public boolean requested; // do we have a request outstanding, limited by score + public int providerId; + + NetworkRequestInfo(NetworkRequest request, int score, int providerId) { + this.request = request; + this.score = score; + this.requested = false; + this.providerId = providerId; + } + + @Override + public String toString() { + return "{" + request + ", score=" + score + ", requested=" + requested + "}"; + } + } + + /** + * Add a NetworkRequest that the bearer may want to attempt to satisfy. + * @see #CMD_REQUEST_NETWORK + * + * @param request the request to handle. + * @param score the score of the NetworkAgent currently satisfying this request. + */ + // TODO : remove this method. It is a stopgap measure to help sheperding a number + // of dependent changes that would conflict throughout the automerger graph. Having this + // temporarily helps with the process of going through with all these dependent changes across + // the entire tree. + @VisibleForTesting + protected void handleAddRequest(NetworkRequest request, int score) { + handleAddRequest(request, score, NetworkProvider.ID_NONE); + } + + /** + * Add a NetworkRequest that the bearer may want to attempt to satisfy. + * @see #CMD_REQUEST_NETWORK + * + * @param request the request to handle. + * @param score the score of the NetworkAgent currently satisfying this request. + * @param servingProviderId the ID of the NetworkProvider that created the NetworkAgent + * currently satisfying this request. + */ + @VisibleForTesting + protected void handleAddRequest(NetworkRequest request, int score, int servingProviderId) { + NetworkRequestInfo n = mNetworkRequests.get(request.requestId); + if (n == null) { + if (DBG) { + log("got request " + request + " with score " + score + + " and providerId " + servingProviderId); + } + n = new NetworkRequestInfo(request, score, servingProviderId); + mNetworkRequests.put(n.request.requestId, n); + } else { + if (VDBG) { + log("new score " + score + " for existing request " + request + + " and providerId " + servingProviderId); + } + n.score = score; + n.providerId = servingProviderId; + } + if (VDBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); + + evalRequest(n); + } + + @VisibleForTesting + protected void handleRemoveRequest(NetworkRequest request) { + NetworkRequestInfo n = mNetworkRequests.get(request.requestId); + if (n != null) { + mNetworkRequests.remove(request.requestId); + if (n.requested) releaseNetworkFor(n.request); + } + } + + private void handleSetScore(int score) { + mScore = score; + evalRequests(); + } + + private void handleSetFilter(NetworkCapabilities netCap) { + mCapabilityFilter = netCap; + evalRequests(); + } + + /** + * Overridable function to provide complex filtering. + * Called for every request every time a new NetworkRequest is seen + * and whenever the filterScore or filterNetworkCapabilities change. + * + * acceptRequest can be overridden to provide complex filter behavior + * for the incoming requests + * + * For output, this class will call {@link #needNetworkFor} and + * {@link #releaseNetworkFor} for every request that passes the filters. + * If you don't need to see every request, you can leave the base + * implementations of those two functions and instead override + * {@link #startNetwork} and {@link #stopNetwork}. + * + * If you want to see every score fluctuation on every request, set + * your score filter to a very high number and watch {@link #needNetworkFor}. + * + * @return {@code true} to accept the request. + */ + public boolean acceptRequest(NetworkRequest request, int score) { + return true; + } + + private void evalRequest(NetworkRequestInfo n) { + if (VDBG) { + log("evalRequest"); + log(" n.requests = " + n.requested); + log(" n.score = " + n.score); + log(" mScore = " + mScore); + log(" n.providerId = " + n.providerId); + log(" mProviderId = " + mProviderId); + } + if (shouldNeedNetworkFor(n)) { + if (VDBG) log(" needNetworkFor"); + needNetworkFor(n.request, n.score); + n.requested = true; + } else if (shouldReleaseNetworkFor(n)) { + if (VDBG) log(" releaseNetworkFor"); + releaseNetworkFor(n.request); + n.requested = false; + } else { + if (VDBG) log(" done"); + } + } + + private boolean shouldNeedNetworkFor(NetworkRequestInfo n) { + // If this request is already tracked, it doesn't qualify for need + return !n.requested + // If the score of this request is higher or equal to that of this factory and some + // other factory is responsible for it, then this factory should not track the request + // because it has no hope of satisfying it. + && (n.score < mScore || n.providerId == mProviderId) + // If this factory can't satisfy the capability needs of this request, then it + // should not be tracked. + && n.request.networkCapabilities.satisfiedByNetworkCapabilities(mCapabilityFilter) + // Finally if the concrete implementation of the factory rejects the request, then + // don't track it. + && acceptRequest(n.request, n.score); + } + + private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) { + // Don't release a request that's not tracked. + return n.requested + // The request should be released if it can't be satisfied by this factory. That + // means either of the following conditions are met : + // - Its score is too high to be satisfied by this factory and it's not already + // assigned to the factory + // - This factory can't satisfy the capability needs of the request + // - The concrete implementation of the factory rejects the request + && ((n.score > mScore && n.providerId != mProviderId) + || !n.request.networkCapabilities.satisfiedByNetworkCapabilities( + mCapabilityFilter) + || !acceptRequest(n.request, n.score)); + } + + private void evalRequests() { + for (int i = 0; i < mNetworkRequests.size(); i++) { + NetworkRequestInfo n = mNetworkRequests.valueAt(i); + evalRequest(n); + } + } + + /** + * Post a command, on this NetworkFactory Handler, to re-evaluate all + * outstanding requests. Can be called from a factory implementation. + */ + protected void reevaluateAllRequests() { + post(() -> { + evalRequests(); + }); + } + + /** + * Can be called by a factory to release a request as unfulfillable: the request will be + * removed, and the caller will get a + * {@link ConnectivityManager.NetworkCallback#onUnavailable()} callback after this function + * returns. + * + * Note: this should only be called by factory which KNOWS that it is the ONLY factory which + * is able to fulfill this request! + */ + protected void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) { + post(() -> { + if (DBG) log("releaseRequestAsUnfulfillableByAnyFactory: " + r); + ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(r); + }); + } + + // override to do simple mode (request independent) + protected void startNetwork() { } + protected void stopNetwork() { } + + // override to do fancier stuff + protected void needNetworkFor(NetworkRequest networkRequest, int score) { + if (++mRefCount == 1) startNetwork(); + } + + protected void releaseNetworkFor(NetworkRequest networkRequest) { + if (--mRefCount == 0) stopNetwork(); + } + + public void setScoreFilter(int score) { + sendMessage(obtainMessage(CMD_SET_SCORE, score, 0)); + } + + public void setCapabilityFilter(NetworkCapabilities netCap) { + sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); + } + + @VisibleForTesting + protected int getRequestCount() { + return mNetworkRequests.size(); + } + + /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ + public int getSerialNumber() { + return mProviderId; + } + + public int getProviderId() { + return mProviderId; + } + + protected void log(String s) { + Log.d(LOG_TAG, s); + } + + public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); + pw.println(toString()); + pw.increaseIndent(); + for (int i = 0; i < mNetworkRequests.size(); i++) { + pw.println(mNetworkRequests.valueAt(i)); + } + pw.decreaseIndent(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - mProviderId=") + .append(mProviderId).append(", ScoreFilter=") + .append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests=") + .append(mNetworkRequests.size()).append(", refCount=").append(mRefCount) + .append("}"); + return sb.toString(); + } +} From 8e54f1a11d019f4e2368c75253e2bb540ab1c55b Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 14 Jan 2020 14:47:16 +0900 Subject: [PATCH 005/777] Add a net-utils-telephony-common library for NetworkFactory. A separate target is necessary for telephony as it needs to jarjar included classes. Test: atest FrameworksNetTests FrameworksWifiTests \ FrameworksTelephonyTests Bug: 138306002 Change-Id: I4b7f79fc43fe5820c94226662bee0216b61fc599 --- staticlibs/Android.bp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 5c851fd2f7..713a0d61d7 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -17,6 +17,11 @@ // library directly. // 2. The "net-utils-services-common" library is for use by modules and frameworks/base/services. // It does not need to be jarjared because it is not placed on the bootclasspath. +// 3. The "net-utils-telephony-common-srcs" filegroup is for use specifically by telephony, which +// places many of its classes, even non-API service classes, on the boot classpath. Any file that +// is added to this filegroup *must* have a corresponding jarjar rule in the telephony jarjar +// rules file. Otherwise, it will end up on the boot classpath and other modules will not be able +// to provide their own copy. filegroup { name: "net-utils-framework-common-srcs", @@ -26,7 +31,7 @@ filegroup { java_library { name: "net-utils-framework-common", - srcs: [":net-utils-framework-common-srcs" ], + srcs: [":net-utils-framework-common-srcs"], jarjar_rules: "jarjar-rules-shared.txt", visibility: [ "//frameworks/base/packages/Tethering", @@ -50,3 +55,16 @@ java_library { "//packages/modules/CaptivePortalLogin", ], } + +// Use a filegroup and not a library for telephony sources, as framework-annotations cannot be +// included either (some annotations would be duplicated on the bootclasspath). +filegroup { + name: "net-utils-telephony-common-srcs", + srcs: [ + // Any class here *must* have a corresponding jarjar rule in the telephony build rules. + "src_servicescommon/android/net/NetworkFactory.java", + ], + visibility: [ + "//frameworks/opt/telephony", + ], +} From cda77ca504ba2544fc4c504e29a80d1884bc49fe Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 14 Jan 2020 21:42:09 +0900 Subject: [PATCH 006/777] Build module common libs as system_current The libraries need to build as system_current since they will be used in modules that should build against that SDK. As notable changes, NetworkFactory stops using a common BASE for handler messages, as no message ID is shared with other handlers (all public messages numbers are for receiving only). It also indexes NetworkRequests by using the request itself in the request table; this is fine because .equals() / .hashCode() are implemented properly, and no request can be used that has the same ID but differences in other members. Test: built, flashed, WiFi and telephony working Test: atest FrameworksNetTests FrameworksWifiTests \ FrameworksTelephonyTests Bug: 138306002 Change-Id: I2ea2be0039b67ba34fc26e62bdb839ab7d42300c --- staticlibs/Android.bp | 14 ++++- staticlibs/jarjar-rules-shared.txt | 2 + .../android/net/util/MacAddressUtils.java | 9 ++- .../android/net/NetworkFactory.java | 58 +++++++++---------- 4 files changed, 46 insertions(+), 37 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 713a0d61d7..cf475b9236 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -31,7 +31,13 @@ filegroup { java_library { name: "net-utils-framework-common", - srcs: [":net-utils-framework-common-srcs"], + srcs: [ + ":net-utils-framework-common-srcs", + // TODO: avoid including all framework annotations as they end up in library users jars + // and need jarjaring + ":framework-annotations", + ], + sdk_version: "system_current", jarjar_rules: "jarjar-rules-shared.txt", visibility: [ "//frameworks/base/packages/Tethering", @@ -45,7 +51,11 @@ java_library { java_library { name: "net-utils-services-common", - srcs: ["src_servicescommon/**/*.java"], + srcs: [ + "src_servicescommon/**/*.java", + ":framework-annotations", + ], + sdk_version: "system_current", visibility: [ "//frameworks/base/services", "//frameworks/base/packages/Tethering", diff --git a/staticlibs/jarjar-rules-shared.txt b/staticlibs/jarjar-rules-shared.txt index 4a2b653429..b22771d17f 100644 --- a/staticlibs/jarjar-rules-shared.txt +++ b/staticlibs/jarjar-rules-shared.txt @@ -1 +1,3 @@ rule android.net.util.** com.android.net.module.util.@1 +rule android.annotation.** com.android.net.module.annotation.@1 +rule com.android.internal.annotations.** com.android.net.module.annotation.@1 \ No newline at end of file diff --git a/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java b/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java index 53457893ca..e71f8fb69a 100644 --- a/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java +++ b/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java @@ -20,11 +20,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.net.MacAddress; -import com.android.internal.util.BitUtils; -import com.android.internal.util.Preconditions; - import java.security.SecureRandom; import java.util.Arrays; +import java.util.Objects; import java.util.Random; /** @@ -98,14 +96,15 @@ public final class MacAddressUtils { * Convert a byte address to long address. */ public static long longAddrFromByteAddr(byte[] addr) { - Preconditions.checkNotNull(addr); + Objects.requireNonNull(addr); if (!isMacAddress(addr)) { throw new IllegalArgumentException( Arrays.toString(addr) + " was not a valid MAC address"); } long longAddr = 0; for (byte b : addr) { - longAddr = (longAddr << 8) + BitUtils.uint8(b); + final int uint8Byte = b & 255; + longAddr = (longAddr << 8) + uint8Byte; } return longAddr; } diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java index 479a191fc4..571f796217 100644 --- a/staticlibs/src_servicescommon/android/net/NetworkFactory.java +++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java @@ -18,21 +18,19 @@ package android.net; import android.annotation.NonNull; import android.content.Context; -import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.util.Log; -import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.IndentingPrintWriter; -import com.android.internal.util.Protocol; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; /** @@ -67,8 +65,6 @@ public class NetworkFactory extends Handler { private static final boolean DBG = true; private static final boolean VDBG = false; - - private static final int BASE = Protocol.BASE_NETWORK_FACTORY; /** * Pass a network request to the bearer. If the bearer believes it can * satisfy the request it should connect to the network and create a @@ -93,33 +89,33 @@ public class NetworkFactory extends Handler { * msg.arg2 = the ID of the NetworkProvider currently responsible for the * NetworkAgent handling this request, or NetworkProvider.ID_NONE if none. */ - public static final int CMD_REQUEST_NETWORK = BASE; + public static final int CMD_REQUEST_NETWORK = 1; /** * Cancel a network request * msg.obj = NetworkRequest */ - public static final int CMD_CANCEL_REQUEST = BASE + 1; + public static final int CMD_CANCEL_REQUEST = 2; /** * Internally used to set our best-guess score. * msg.arg1 = new score */ - private static final int CMD_SET_SCORE = BASE + 2; + private static final int CMD_SET_SCORE = 3; /** * Internally used to set our current filter for coarse bandwidth changes with * technology changes. * msg.obj = new filter */ - private static final int CMD_SET_FILTER = BASE + 3; + private static final int CMD_SET_FILTER = 4; private final Context mContext; private final ArrayList mPreConnectedQueue = new ArrayList(); private final String LOG_TAG; - private final SparseArray mNetworkRequests = - new SparseArray(); + private final Map mNetworkRequests = + new HashMap<>(); private int mScore; private NetworkCapabilities mCapabilityFilter; @@ -158,7 +154,8 @@ public class NetworkFactory extends Handler { }; mMessenger = new Messenger(this); - mProviderId = ConnectivityManager.from(mContext).registerNetworkProvider(mProvider); + mProviderId = ((ConnectivityManager) mContext.getSystemService( + Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); } public void unregister() { @@ -168,7 +165,8 @@ public class NetworkFactory extends Handler { } if (DBG) log("Unregistering NetworkFactory"); - ConnectivityManager.from(mContext).unregisterNetworkProvider(mProvider); + ((ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) + .unregisterNetworkProvider(mProvider); mProvider = null; } @@ -240,14 +238,14 @@ public class NetworkFactory extends Handler { */ @VisibleForTesting protected void handleAddRequest(NetworkRequest request, int score, int servingProviderId) { - NetworkRequestInfo n = mNetworkRequests.get(request.requestId); + NetworkRequestInfo n = mNetworkRequests.get(request); if (n == null) { if (DBG) { log("got request " + request + " with score " + score + " and providerId " + servingProviderId); } n = new NetworkRequestInfo(request, score, servingProviderId); - mNetworkRequests.put(n.request.requestId, n); + mNetworkRequests.put(n.request, n); } else { if (VDBG) { log("new score " + score + " for existing request " + request @@ -263,9 +261,9 @@ public class NetworkFactory extends Handler { @VisibleForTesting protected void handleRemoveRequest(NetworkRequest request) { - NetworkRequestInfo n = mNetworkRequests.get(request.requestId); + NetworkRequestInfo n = mNetworkRequests.get(request); if (n != null) { - mNetworkRequests.remove(request.requestId); + mNetworkRequests.remove(request); if (n.requested) releaseNetworkFor(n.request); } } @@ -334,7 +332,7 @@ public class NetworkFactory extends Handler { && (n.score < mScore || n.providerId == mProviderId) // If this factory can't satisfy the capability needs of this request, then it // should not be tracked. - && n.request.networkCapabilities.satisfiedByNetworkCapabilities(mCapabilityFilter) + && n.request.satisfiedBy(mCapabilityFilter) // Finally if the concrete implementation of the factory rejects the request, then // don't track it. && acceptRequest(n.request, n.score); @@ -350,14 +348,12 @@ public class NetworkFactory extends Handler { // - This factory can't satisfy the capability needs of the request // - The concrete implementation of the factory rejects the request && ((n.score > mScore && n.providerId != mProviderId) - || !n.request.networkCapabilities.satisfiedByNetworkCapabilities( - mCapabilityFilter) + || !n.request.satisfiedBy(mCapabilityFilter) || !acceptRequest(n.request, n.score)); } private void evalRequests() { - for (int i = 0; i < mNetworkRequests.size(); i++) { - NetworkRequestInfo n = mNetworkRequests.valueAt(i); + for (NetworkRequestInfo n : mNetworkRequests.values()) { evalRequest(n); } } @@ -384,7 +380,12 @@ public class NetworkFactory extends Handler { protected void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) { post(() -> { if (DBG) log("releaseRequestAsUnfulfillableByAnyFactory: " + r); - ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(r); + final NetworkProvider provider = mProvider; + if (provider == null) { + Log.e(LOG_TAG, "Ignoring attempt to release unregistered request as unfulfillable"); + return; + } + provider.declareNetworkRequestUnfulfillable(r); }); } @@ -428,13 +429,10 @@ public class NetworkFactory extends Handler { } public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); - pw.println(toString()); - pw.increaseIndent(); - for (int i = 0; i < mNetworkRequests.size(); i++) { - pw.println(mNetworkRequests.valueAt(i)); + writer.println(toString()); + for (NetworkRequestInfo n : mNetworkRequests.values()) { + writer.println(" " + n); } - pw.decreaseIndent(); } @Override From 6e0f4e61832fd42cde33a843f145b304ec619d83 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 15 Jan 2020 18:26:29 +0900 Subject: [PATCH 007/777] Fix visibility for services-common lib f/b/services/net should be allowed, not just f/b/services. Test: Dependent change using the build rule builds Bug: 138306002 Change-Id: Ide48e637df6e1c21cd7c0c688e3fef2ba1c97deb --- staticlibs/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index cf475b9236..2c707abc1e 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -57,7 +57,7 @@ java_library { ], sdk_version: "system_current", visibility: [ - "//frameworks/base/services", + "//frameworks/base/services/net", "//frameworks/base/packages/Tethering", "//frameworks/opt/net/wifi/service", "//frameworks/opt/net/ike", From f549e53863539a9df935decf7d1e0d304a15baf7 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 15 Jan 2020 19:22:57 +0900 Subject: [PATCH 008/777] Address MacAddressUtils / NetworkFactory comments Remove unused code, and make NetworkRequest iterating order deterministic. Test: atest FrameworksNetTests FrameworksWifiTests \ FrameworksTelephonyTests Bug: 138306002 Change-Id: I1a8f2b07dd1b3ef8286c8b578ed7ae38c87bb38c --- .../android/net/util/MacAddressUtils.java | 2 +- .../android/net/NetworkFactory.java | 19 ++----------------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java b/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java index e71f8fb69a..3ad452ba30 100644 --- a/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java +++ b/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java @@ -103,7 +103,7 @@ public final class MacAddressUtils { } long longAddr = 0; for (byte b : addr) { - final int uint8Byte = b & 255; + final int uint8Byte = b & 0xff; longAddr = (longAddr << 8) + uint8Byte; } return longAddr; diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java index 571f796217..3758bb50b5 100644 --- a/staticlibs/src_servicescommon/android/net/NetworkFactory.java +++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java @@ -29,9 +29,8 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; /** * A NetworkFactory is an entity that creates NetworkAgent objects. @@ -49,20 +48,6 @@ import java.util.concurrent.atomic.AtomicInteger; * @hide **/ public class NetworkFactory extends Handler { - /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ - public static class SerialNumber { - // Guard used by no network factory. - public static final int NONE = -1; - // A hardcoded serial number for NetworkAgents representing VPNs. These agents are - // not created by any factory, so they use this constant for clarity instead of NONE. - public static final int VPN = -2; - private static final AtomicInteger sNetworkFactorySerialNumber = new AtomicInteger(1); - /** Returns a unique serial number for a factory. */ - public static final int nextSerialNumber() { - return sNetworkFactorySerialNumber.getAndIncrement(); - } - } - private static final boolean DBG = true; private static final boolean VDBG = false; /** @@ -115,7 +100,7 @@ public class NetworkFactory extends Handler { private final String LOG_TAG; private final Map mNetworkRequests = - new HashMap<>(); + new LinkedHashMap<>(); private int mScore; private NetworkCapabilities mCapabilityFilter; From 480b00e8469871b479d981a3712458857b75484c Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Wed, 15 Jan 2020 09:09:54 -0800 Subject: [PATCH 009/777] libs(net/common): Fixes for wifi to include a) Fix the visibility for wifi service. b) Don't pre jar-jar the utils classes. This makes it hard for the service to statically link this. The jar-jar should happen in the client side (i.e wifi service will perform the necessary jar-jar). Bug: 135998869 Test: Compiles Change-Id: Ic3b92ca63593394af2003a025508fbb5e2687cfa --- staticlibs/Android.bp | 2 +- staticlibs/jarjar-rules-shared.txt | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 2c707abc1e..d3817a90dc 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -41,7 +41,7 @@ java_library { jarjar_rules: "jarjar-rules-shared.txt", visibility: [ "//frameworks/base/packages/Tethering", - "//frameworks/opt/net/wifi", + "//frameworks/opt/net/wifi/service", "//frameworks/opt/net/ike", "//frameworks/opt/telephony", "//packages/modules/NetworkStack", diff --git a/staticlibs/jarjar-rules-shared.txt b/staticlibs/jarjar-rules-shared.txt index b22771d17f..a7fda7c0ac 100644 --- a/staticlibs/jarjar-rules-shared.txt +++ b/staticlibs/jarjar-rules-shared.txt @@ -1,3 +1,2 @@ -rule android.net.util.** com.android.net.module.util.@1 rule android.annotation.** com.android.net.module.annotation.@1 -rule com.android.internal.annotations.** com.android.net.module.annotation.@1 \ No newline at end of file +rule com.android.internal.annotations.** com.android.net.module.annotation.@1 From 6beb564bbce1541c00d0dd19ee71738d1283c2bb Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Thu, 16 Jan 2020 16:36:40 +0000 Subject: [PATCH 010/777] Revert "libs(net/common): Fixes for wifi to include" Reason for revert: b/147807058 Reverted Changes: I902b7b742: telephony: jar-jar net.util classes on the usage s... I90a9c537b: wifi-service: Link net util libraries Ic3b92ca63: libs(net/common): Fixes for wifi to include. Ib2fb2bf05: wifi-service: Jar-Jar net util library. Bug: 147807058 Change-Id: I010745e2da25ac8d50922b394a5b598caddb1915 --- staticlibs/Android.bp | 2 +- staticlibs/jarjar-rules-shared.txt | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index d3817a90dc..2c707abc1e 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -41,7 +41,7 @@ java_library { jarjar_rules: "jarjar-rules-shared.txt", visibility: [ "//frameworks/base/packages/Tethering", - "//frameworks/opt/net/wifi/service", + "//frameworks/opt/net/wifi", "//frameworks/opt/net/ike", "//frameworks/opt/telephony", "//packages/modules/NetworkStack", diff --git a/staticlibs/jarjar-rules-shared.txt b/staticlibs/jarjar-rules-shared.txt index a7fda7c0ac..b22771d17f 100644 --- a/staticlibs/jarjar-rules-shared.txt +++ b/staticlibs/jarjar-rules-shared.txt @@ -1,2 +1,3 @@ +rule android.net.util.** com.android.net.module.util.@1 rule android.annotation.** com.android.net.module.annotation.@1 -rule com.android.internal.annotations.** com.android.net.module.annotation.@1 +rule com.android.internal.annotations.** com.android.net.module.annotation.@1 \ No newline at end of file From bb785fe1d835368d850f734cc53a023033c82795 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Thu, 16 Jan 2020 09:19:11 -0800 Subject: [PATCH 011/777] libs(net/common): Create filegroups for wifi sources Safer for wifi to just include the sources that it needs. Then there is no accidental risk of un-jar-jar'ed classes showing up in it's namespace. Bug: 135998869 Test: Compiles Change-Id: I2532f640fbebd4ca82be7bbb63744bcad653ac34 --- staticlibs/Android.bp | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 2c707abc1e..6827403b36 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -41,7 +41,6 @@ java_library { jarjar_rules: "jarjar-rules-shared.txt", visibility: [ "//frameworks/base/packages/Tethering", - "//frameworks/opt/net/wifi", "//frameworks/opt/net/ike", "//frameworks/opt/telephony", "//packages/modules/NetworkStack", @@ -59,7 +58,6 @@ java_library { visibility: [ "//frameworks/base/services/net", "//frameworks/base/packages/Tethering", - "//frameworks/opt/net/wifi/service", "//frameworks/opt/net/ike", "//packages/modules/NetworkStack", "//packages/modules/CaptivePortalLogin", @@ -78,3 +76,30 @@ filegroup { "//frameworks/opt/telephony", ], } + +// Use a filegroup and not a library for wifi sources, as this needs corresponding jar-jar +// rules on the wifi side. +// Any class here *must* have a corresponding jarjar rule in the wifi build rules. +filegroup { + name: "net-utils-framework-wifi-common-srcs", + srcs: [ + "src_frameworkcommon/android/net/util/MacAddressUtils.java", + ], + visibility: [ + "//frameworks/base", + ], +} + +// Use a filegroup and not a library for wifi sources, as this needs corresponding jar-jar +// rules on the wifi side. +// Any class here *must* have a corresponding jarjar rule in the wifi build rules. +filegroup { + name: "net-utils-wifi-service-common-srcs", + srcs: [ + "src_frameworkcommon/android/net/util/NetUtils.java", + "src_servicescommon/android/net/NetworkFactory.java", + ], + visibility: [ + "//frameworks/opt/net/wifi/service", + ], +} From 5f0a15860ebdaf3cce88d38c337469e280164f6b Mon Sep 17 00:00:00 2001 From: David Su Date: Thu, 16 Jan 2020 20:56:39 -0800 Subject: [PATCH 012/777] Statically link DnsSdTxtRecord into framework-wifi DnsSdTxtRecord is @hide, thus need to statically link it into framework-wifi. Bug: 135998869 Test: boots up and connects to wifi Change-Id: Ic5f7decfdbc3116a15fe8da3841cc7620105996d --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 6827403b36..c3b86682fc 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -83,6 +83,7 @@ filegroup { filegroup { name: "net-utils-framework-wifi-common-srcs", srcs: [ + "src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java", "src_frameworkcommon/android/net/util/MacAddressUtils.java", ], visibility: [ From 469b4f5cb51c1fd17a0badb5e52ca0fa13bf82e9 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 16 Jan 2020 18:58:16 +0900 Subject: [PATCH 013/777] Updates to NetworkFactory for the new NetworkAgent constructor Bug: 138306002 Bug: 139268426 Test: atest FrameworksNetTests FrameworksWifiTests FrameworksTelephonyTests Change-Id: If327cf0ffd917f9cb358f9ed3779da58fce40ef8 --- .../android/net/NetworkFactory.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java index 3758bb50b5..47054f504a 100644 --- a/staticlibs/src_servicescommon/android/net/NetworkFactory.java +++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java @@ -108,7 +108,6 @@ public class NetworkFactory extends Handler { private int mRefCount = 0; private Messenger mMessenger = null; private NetworkProvider mProvider = null; - private int mProviderId; public NetworkFactory(Looper looper, Context context, String logTag, NetworkCapabilities filter) { @@ -139,7 +138,7 @@ public class NetworkFactory extends Handler { }; mMessenger = new Messenger(this); - mProviderId = ((ConnectivityManager) mContext.getSystemService( + ((ConnectivityManager) mContext.getSystemService( Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); } @@ -292,8 +291,8 @@ public class NetworkFactory extends Handler { log(" n.requests = " + n.requested); log(" n.score = " + n.score); log(" mScore = " + mScore); - log(" n.providerId = " + n.providerId); - log(" mProviderId = " + mProviderId); + log(" request.providerId = " + n.providerId); + log(" mProvider.id = " + mProvider.getProviderId()); } if (shouldNeedNetworkFor(n)) { if (VDBG) log(" needNetworkFor"); @@ -314,7 +313,7 @@ public class NetworkFactory extends Handler { // If the score of this request is higher or equal to that of this factory and some // other factory is responsible for it, then this factory should not track the request // because it has no hope of satisfying it. - && (n.score < mScore || n.providerId == mProviderId) + && (n.score < mScore || n.providerId == mProvider.getProviderId()) // If this factory can't satisfy the capability needs of this request, then it // should not be tracked. && n.request.satisfiedBy(mCapabilityFilter) @@ -332,7 +331,7 @@ public class NetworkFactory extends Handler { // assigned to the factory // - This factory can't satisfy the capability needs of the request // - The concrete implementation of the factory rejects the request - && ((n.score > mScore && n.providerId != mProviderId) + && ((n.score > mScore && n.providerId != mProvider.getProviderId()) || !n.request.satisfiedBy(mCapabilityFilter) || !acceptRequest(n.request, n.score)); } @@ -402,11 +401,11 @@ public class NetworkFactory extends Handler { /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ public int getSerialNumber() { - return mProviderId; + return mProvider.getProviderId(); } - public int getProviderId() { - return mProviderId; + public NetworkProvider getProvider() { + return mProvider; } protected void log(String s) { @@ -422,8 +421,8 @@ public class NetworkFactory extends Handler { @Override public String toString() { - StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - mProviderId=") - .append(mProviderId).append(", ScoreFilter=") + StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - providerId=") + .append(mProvider.getProviderId()).append(", ScoreFilter=") .append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests=") .append(mNetworkRequests.size()).append(", refCount=").append(mRefCount) .append("}"); From 57a9496f198ae8d220c76bd7663e3b57ba0f7d44 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 3 Jan 2020 20:35:55 +0800 Subject: [PATCH 014/777] Add net-utils-services-common library net-utils-services-common-srcs for files in src_servicescommon and library net-utils-services-common could be used in services.jar or modules. Bug: 138306002 Bug: 139268426 Test: atest FrameworksNetTests FrameworksTelephonyTests Change-Id: I5043a34100e9ef26148e3a0c1743363d063a3604 Merged-In: I5043a34100e9ef26148e3a0c1743363d063a3604 (clean cherry-pick from internal branch) --- staticlibs/Android.bp | 21 +- .../android/net/NetworkFactory.java | 449 ++++++++++++++++++ 2 files changed, 467 insertions(+), 3 deletions(-) create mode 100644 staticlibs/src_servicescommon/android/net/NetworkFactory.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index ffc02c3cd5..5c851fd2f7 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -12,9 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -// File group "net-utils-framework-common-srcs" is also compiled into android framework. -// Add jarjar rules here so that anything outside of framework could use this library -// directly. +// 1. The "net-utils-framework-common" library is also compiled into the framework and placed on the +// boot classpath. It uses jarjar rules so that anything outside the framework can use this +// library directly. +// 2. The "net-utils-services-common" library is for use by modules and frameworks/base/services. +// It does not need to be jarjared because it is not placed on the bootclasspath. filegroup { name: "net-utils-framework-common-srcs", @@ -35,3 +37,16 @@ java_library { "//packages/modules/CaptivePortalLogin", ] } + +java_library { + name: "net-utils-services-common", + srcs: ["src_servicescommon/**/*.java"], + visibility: [ + "//frameworks/base/services", + "//frameworks/base/packages/Tethering", + "//frameworks/opt/net/wifi/service", + "//frameworks/opt/net/ike", + "//packages/modules/NetworkStack", + "//packages/modules/CaptivePortalLogin", + ], +} diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java new file mode 100644 index 0000000000..479a191fc4 --- /dev/null +++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2014 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 android.annotation.NonNull; +import android.content.Context; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.util.Log; +import android.util.SparseArray; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.Protocol; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * A NetworkFactory is an entity that creates NetworkAgent objects. + * The bearers register with ConnectivityService using {@link #register} and + * their factory will start receiving scored NetworkRequests. NetworkRequests + * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by + * overridden function. All of these can be dynamic - changing NetworkCapabilities + * or score forces re-evaluation of all current requests. + * + * If any requests pass the filter some overrideable functions will be called. + * If the bearer only cares about very simple start/stopNetwork callbacks, those + * functions can be overridden. If the bearer needs more interaction, it can + * override addNetworkRequest and removeNetworkRequest which will give it each + * request that passes their current filters. + * @hide + **/ +public class NetworkFactory extends Handler { + /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ + public static class SerialNumber { + // Guard used by no network factory. + public static final int NONE = -1; + // A hardcoded serial number for NetworkAgents representing VPNs. These agents are + // not created by any factory, so they use this constant for clarity instead of NONE. + public static final int VPN = -2; + private static final AtomicInteger sNetworkFactorySerialNumber = new AtomicInteger(1); + /** Returns a unique serial number for a factory. */ + public static final int nextSerialNumber() { + return sNetworkFactorySerialNumber.getAndIncrement(); + } + } + + private static final boolean DBG = true; + private static final boolean VDBG = false; + + private static final int BASE = Protocol.BASE_NETWORK_FACTORY; + /** + * Pass a network request to the bearer. If the bearer believes it can + * satisfy the request it should connect to the network and create a + * NetworkAgent. Once the NetworkAgent is fully functional it will + * register itself with ConnectivityService using registerNetworkAgent. + * If the bearer cannot immediately satisfy the request (no network, + * user disabled the radio, lower-scored network) it should remember + * any NetworkRequests it may be able to satisfy in the future. It may + * disregard any that it will never be able to service, for example + * those requiring a different bearer. + * msg.obj = NetworkRequest + * msg.arg1 = score - the score of the network currently satisfying this + * request. If this bearer knows in advance it cannot + * exceed this score it should not try to connect, holding the request + * for the future. + * Note that subsequent events may give a different (lower + * or higher) score for this request, transmitted to each + * NetworkFactory through additional CMD_REQUEST_NETWORK msgs + * with the same NetworkRequest but an updated score. + * Also, network conditions may change for this bearer + * allowing for a better score in the future. + * msg.arg2 = the ID of the NetworkProvider currently responsible for the + * NetworkAgent handling this request, or NetworkProvider.ID_NONE if none. + */ + public static final int CMD_REQUEST_NETWORK = BASE; + + /** + * Cancel a network request + * msg.obj = NetworkRequest + */ + public static final int CMD_CANCEL_REQUEST = BASE + 1; + + /** + * Internally used to set our best-guess score. + * msg.arg1 = new score + */ + private static final int CMD_SET_SCORE = BASE + 2; + + /** + * Internally used to set our current filter for coarse bandwidth changes with + * technology changes. + * msg.obj = new filter + */ + private static final int CMD_SET_FILTER = BASE + 3; + + private final Context mContext; + private final ArrayList mPreConnectedQueue = new ArrayList(); + private final String LOG_TAG; + + private final SparseArray mNetworkRequests = + new SparseArray(); + + private int mScore; + private NetworkCapabilities mCapabilityFilter; + + private int mRefCount = 0; + private Messenger mMessenger = null; + private NetworkProvider mProvider = null; + private int mProviderId; + + public NetworkFactory(Looper looper, Context context, String logTag, + NetworkCapabilities filter) { + super(looper); + LOG_TAG = logTag; + mContext = context; + mCapabilityFilter = filter; + } + + public void register() { + if (mProvider != null) { + Log.e(LOG_TAG, "Ignoring attempt to register already-registered NetworkFactory"); + return; + } + if (DBG) log("Registering NetworkFactory"); + + mProvider = new NetworkProvider(mContext, NetworkFactory.this.getLooper(), LOG_TAG) { + @Override + public void onNetworkRequested(@NonNull NetworkRequest request, int score, + int servingProviderId) { + handleAddRequest((NetworkRequest) request, score, servingProviderId); + } + + @Override + public void onRequestWithdrawn(@NonNull NetworkRequest request) { + handleRemoveRequest(request); + } + }; + + mMessenger = new Messenger(this); + mProviderId = ConnectivityManager.from(mContext).registerNetworkProvider(mProvider); + } + + public void unregister() { + if (mProvider == null) { + Log.e(LOG_TAG, "Ignoring attempt to unregister unregistered NetworkFactory"); + return; + } + if (DBG) log("Unregistering NetworkFactory"); + + ConnectivityManager.from(mContext).unregisterNetworkProvider(mProvider); + mProvider = null; + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case CMD_REQUEST_NETWORK: { + handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2); + break; + } + case CMD_CANCEL_REQUEST: { + handleRemoveRequest((NetworkRequest) msg.obj); + break; + } + case CMD_SET_SCORE: { + handleSetScore(msg.arg1); + break; + } + case CMD_SET_FILTER: { + handleSetFilter((NetworkCapabilities) msg.obj); + break; + } + } + } + + private class NetworkRequestInfo { + public final NetworkRequest request; + public int score; + public boolean requested; // do we have a request outstanding, limited by score + public int providerId; + + NetworkRequestInfo(NetworkRequest request, int score, int providerId) { + this.request = request; + this.score = score; + this.requested = false; + this.providerId = providerId; + } + + @Override + public String toString() { + return "{" + request + ", score=" + score + ", requested=" + requested + "}"; + } + } + + /** + * Add a NetworkRequest that the bearer may want to attempt to satisfy. + * @see #CMD_REQUEST_NETWORK + * + * @param request the request to handle. + * @param score the score of the NetworkAgent currently satisfying this request. + */ + // TODO : remove this method. It is a stopgap measure to help sheperding a number + // of dependent changes that would conflict throughout the automerger graph. Having this + // temporarily helps with the process of going through with all these dependent changes across + // the entire tree. + @VisibleForTesting + protected void handleAddRequest(NetworkRequest request, int score) { + handleAddRequest(request, score, NetworkProvider.ID_NONE); + } + + /** + * Add a NetworkRequest that the bearer may want to attempt to satisfy. + * @see #CMD_REQUEST_NETWORK + * + * @param request the request to handle. + * @param score the score of the NetworkAgent currently satisfying this request. + * @param servingProviderId the ID of the NetworkProvider that created the NetworkAgent + * currently satisfying this request. + */ + @VisibleForTesting + protected void handleAddRequest(NetworkRequest request, int score, int servingProviderId) { + NetworkRequestInfo n = mNetworkRequests.get(request.requestId); + if (n == null) { + if (DBG) { + log("got request " + request + " with score " + score + + " and providerId " + servingProviderId); + } + n = new NetworkRequestInfo(request, score, servingProviderId); + mNetworkRequests.put(n.request.requestId, n); + } else { + if (VDBG) { + log("new score " + score + " for existing request " + request + + " and providerId " + servingProviderId); + } + n.score = score; + n.providerId = servingProviderId; + } + if (VDBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); + + evalRequest(n); + } + + @VisibleForTesting + protected void handleRemoveRequest(NetworkRequest request) { + NetworkRequestInfo n = mNetworkRequests.get(request.requestId); + if (n != null) { + mNetworkRequests.remove(request.requestId); + if (n.requested) releaseNetworkFor(n.request); + } + } + + private void handleSetScore(int score) { + mScore = score; + evalRequests(); + } + + private void handleSetFilter(NetworkCapabilities netCap) { + mCapabilityFilter = netCap; + evalRequests(); + } + + /** + * Overridable function to provide complex filtering. + * Called for every request every time a new NetworkRequest is seen + * and whenever the filterScore or filterNetworkCapabilities change. + * + * acceptRequest can be overridden to provide complex filter behavior + * for the incoming requests + * + * For output, this class will call {@link #needNetworkFor} and + * {@link #releaseNetworkFor} for every request that passes the filters. + * If you don't need to see every request, you can leave the base + * implementations of those two functions and instead override + * {@link #startNetwork} and {@link #stopNetwork}. + * + * If you want to see every score fluctuation on every request, set + * your score filter to a very high number and watch {@link #needNetworkFor}. + * + * @return {@code true} to accept the request. + */ + public boolean acceptRequest(NetworkRequest request, int score) { + return true; + } + + private void evalRequest(NetworkRequestInfo n) { + if (VDBG) { + log("evalRequest"); + log(" n.requests = " + n.requested); + log(" n.score = " + n.score); + log(" mScore = " + mScore); + log(" n.providerId = " + n.providerId); + log(" mProviderId = " + mProviderId); + } + if (shouldNeedNetworkFor(n)) { + if (VDBG) log(" needNetworkFor"); + needNetworkFor(n.request, n.score); + n.requested = true; + } else if (shouldReleaseNetworkFor(n)) { + if (VDBG) log(" releaseNetworkFor"); + releaseNetworkFor(n.request); + n.requested = false; + } else { + if (VDBG) log(" done"); + } + } + + private boolean shouldNeedNetworkFor(NetworkRequestInfo n) { + // If this request is already tracked, it doesn't qualify for need + return !n.requested + // If the score of this request is higher or equal to that of this factory and some + // other factory is responsible for it, then this factory should not track the request + // because it has no hope of satisfying it. + && (n.score < mScore || n.providerId == mProviderId) + // If this factory can't satisfy the capability needs of this request, then it + // should not be tracked. + && n.request.networkCapabilities.satisfiedByNetworkCapabilities(mCapabilityFilter) + // Finally if the concrete implementation of the factory rejects the request, then + // don't track it. + && acceptRequest(n.request, n.score); + } + + private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) { + // Don't release a request that's not tracked. + return n.requested + // The request should be released if it can't be satisfied by this factory. That + // means either of the following conditions are met : + // - Its score is too high to be satisfied by this factory and it's not already + // assigned to the factory + // - This factory can't satisfy the capability needs of the request + // - The concrete implementation of the factory rejects the request + && ((n.score > mScore && n.providerId != mProviderId) + || !n.request.networkCapabilities.satisfiedByNetworkCapabilities( + mCapabilityFilter) + || !acceptRequest(n.request, n.score)); + } + + private void evalRequests() { + for (int i = 0; i < mNetworkRequests.size(); i++) { + NetworkRequestInfo n = mNetworkRequests.valueAt(i); + evalRequest(n); + } + } + + /** + * Post a command, on this NetworkFactory Handler, to re-evaluate all + * outstanding requests. Can be called from a factory implementation. + */ + protected void reevaluateAllRequests() { + post(() -> { + evalRequests(); + }); + } + + /** + * Can be called by a factory to release a request as unfulfillable: the request will be + * removed, and the caller will get a + * {@link ConnectivityManager.NetworkCallback#onUnavailable()} callback after this function + * returns. + * + * Note: this should only be called by factory which KNOWS that it is the ONLY factory which + * is able to fulfill this request! + */ + protected void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) { + post(() -> { + if (DBG) log("releaseRequestAsUnfulfillableByAnyFactory: " + r); + ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(r); + }); + } + + // override to do simple mode (request independent) + protected void startNetwork() { } + protected void stopNetwork() { } + + // override to do fancier stuff + protected void needNetworkFor(NetworkRequest networkRequest, int score) { + if (++mRefCount == 1) startNetwork(); + } + + protected void releaseNetworkFor(NetworkRequest networkRequest) { + if (--mRefCount == 0) stopNetwork(); + } + + public void setScoreFilter(int score) { + sendMessage(obtainMessage(CMD_SET_SCORE, score, 0)); + } + + public void setCapabilityFilter(NetworkCapabilities netCap) { + sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); + } + + @VisibleForTesting + protected int getRequestCount() { + return mNetworkRequests.size(); + } + + /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ + public int getSerialNumber() { + return mProviderId; + } + + public int getProviderId() { + return mProviderId; + } + + protected void log(String s) { + Log.d(LOG_TAG, s); + } + + public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); + pw.println(toString()); + pw.increaseIndent(); + for (int i = 0; i < mNetworkRequests.size(); i++) { + pw.println(mNetworkRequests.valueAt(i)); + } + pw.decreaseIndent(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - mProviderId=") + .append(mProviderId).append(", ScoreFilter=") + .append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests=") + .append(mNetworkRequests.size()).append(", refCount=").append(mRefCount) + .append("}"); + return sb.toString(); + } +} From e14bd343e09fff9faafd0346300d794d5da8810c Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 14 Jan 2020 14:47:16 +0900 Subject: [PATCH 015/777] Add a net-utils-telephony-common library for NetworkFactory. A separate target is necessary for telephony as it needs to jarjar included classes. Test: atest FrameworksNetTests FrameworksWifiTests \ FrameworksTelephonyTests Bug: 138306002 Change-Id: I4b7f79fc43fe5820c94226662bee0216b61fc599 Merged-In: I4b7f79fc43fe5820c94226662bee0216b61fc599 (clean cherry-pick from internal branch) --- staticlibs/Android.bp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 5c851fd2f7..713a0d61d7 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -17,6 +17,11 @@ // library directly. // 2. The "net-utils-services-common" library is for use by modules and frameworks/base/services. // It does not need to be jarjared because it is not placed on the bootclasspath. +// 3. The "net-utils-telephony-common-srcs" filegroup is for use specifically by telephony, which +// places many of its classes, even non-API service classes, on the boot classpath. Any file that +// is added to this filegroup *must* have a corresponding jarjar rule in the telephony jarjar +// rules file. Otherwise, it will end up on the boot classpath and other modules will not be able +// to provide their own copy. filegroup { name: "net-utils-framework-common-srcs", @@ -26,7 +31,7 @@ filegroup { java_library { name: "net-utils-framework-common", - srcs: [":net-utils-framework-common-srcs" ], + srcs: [":net-utils-framework-common-srcs"], jarjar_rules: "jarjar-rules-shared.txt", visibility: [ "//frameworks/base/packages/Tethering", @@ -50,3 +55,16 @@ java_library { "//packages/modules/CaptivePortalLogin", ], } + +// Use a filegroup and not a library for telephony sources, as framework-annotations cannot be +// included either (some annotations would be duplicated on the bootclasspath). +filegroup { + name: "net-utils-telephony-common-srcs", + srcs: [ + // Any class here *must* have a corresponding jarjar rule in the telephony build rules. + "src_servicescommon/android/net/NetworkFactory.java", + ], + visibility: [ + "//frameworks/opt/telephony", + ], +} From ce241a3b79a0390eebb43cdc927210b377cd6c14 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 14 Jan 2020 21:42:09 +0900 Subject: [PATCH 016/777] Build module common libs as system_current The libraries need to build as system_current since they will be used in modules that should build against that SDK. As notable changes, NetworkFactory stops using a common BASE for handler messages, as no message ID is shared with other handlers (all public messages numbers are for receiving only). It also indexes NetworkRequests by using the request itself in the request table; this is fine because .equals() / .hashCode() are implemented properly, and no request can be used that has the same ID but differences in other members. Test: built, flashed, WiFi and telephony working Test: atest FrameworksNetTests FrameworksWifiTests \ FrameworksTelephonyTests Bug: 138306002 Merged-In: I2ea2be0039b67ba34fc26e62bdb839ab7d42300c Change-Id: I2ea2be0039b67ba34fc26e62bdb839ab7d42300c (clean cherry-pick from internal branch) --- staticlibs/Android.bp | 14 ++++- staticlibs/jarjar-rules-shared.txt | 2 + .../android/net/util/MacAddressUtils.java | 9 ++- .../android/net/NetworkFactory.java | 58 +++++++++---------- 4 files changed, 46 insertions(+), 37 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 713a0d61d7..cf475b9236 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -31,7 +31,13 @@ filegroup { java_library { name: "net-utils-framework-common", - srcs: [":net-utils-framework-common-srcs"], + srcs: [ + ":net-utils-framework-common-srcs", + // TODO: avoid including all framework annotations as they end up in library users jars + // and need jarjaring + ":framework-annotations", + ], + sdk_version: "system_current", jarjar_rules: "jarjar-rules-shared.txt", visibility: [ "//frameworks/base/packages/Tethering", @@ -45,7 +51,11 @@ java_library { java_library { name: "net-utils-services-common", - srcs: ["src_servicescommon/**/*.java"], + srcs: [ + "src_servicescommon/**/*.java", + ":framework-annotations", + ], + sdk_version: "system_current", visibility: [ "//frameworks/base/services", "//frameworks/base/packages/Tethering", diff --git a/staticlibs/jarjar-rules-shared.txt b/staticlibs/jarjar-rules-shared.txt index 4a2b653429..b22771d17f 100644 --- a/staticlibs/jarjar-rules-shared.txt +++ b/staticlibs/jarjar-rules-shared.txt @@ -1 +1,3 @@ rule android.net.util.** com.android.net.module.util.@1 +rule android.annotation.** com.android.net.module.annotation.@1 +rule com.android.internal.annotations.** com.android.net.module.annotation.@1 \ No newline at end of file diff --git a/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java b/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java index 53457893ca..e71f8fb69a 100644 --- a/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java +++ b/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java @@ -20,11 +20,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.net.MacAddress; -import com.android.internal.util.BitUtils; -import com.android.internal.util.Preconditions; - import java.security.SecureRandom; import java.util.Arrays; +import java.util.Objects; import java.util.Random; /** @@ -98,14 +96,15 @@ public final class MacAddressUtils { * Convert a byte address to long address. */ public static long longAddrFromByteAddr(byte[] addr) { - Preconditions.checkNotNull(addr); + Objects.requireNonNull(addr); if (!isMacAddress(addr)) { throw new IllegalArgumentException( Arrays.toString(addr) + " was not a valid MAC address"); } long longAddr = 0; for (byte b : addr) { - longAddr = (longAddr << 8) + BitUtils.uint8(b); + final int uint8Byte = b & 255; + longAddr = (longAddr << 8) + uint8Byte; } return longAddr; } diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java index 479a191fc4..571f796217 100644 --- a/staticlibs/src_servicescommon/android/net/NetworkFactory.java +++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java @@ -18,21 +18,19 @@ package android.net; import android.annotation.NonNull; import android.content.Context; -import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.util.Log; -import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.IndentingPrintWriter; -import com.android.internal.util.Protocol; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; /** @@ -67,8 +65,6 @@ public class NetworkFactory extends Handler { private static final boolean DBG = true; private static final boolean VDBG = false; - - private static final int BASE = Protocol.BASE_NETWORK_FACTORY; /** * Pass a network request to the bearer. If the bearer believes it can * satisfy the request it should connect to the network and create a @@ -93,33 +89,33 @@ public class NetworkFactory extends Handler { * msg.arg2 = the ID of the NetworkProvider currently responsible for the * NetworkAgent handling this request, or NetworkProvider.ID_NONE if none. */ - public static final int CMD_REQUEST_NETWORK = BASE; + public static final int CMD_REQUEST_NETWORK = 1; /** * Cancel a network request * msg.obj = NetworkRequest */ - public static final int CMD_CANCEL_REQUEST = BASE + 1; + public static final int CMD_CANCEL_REQUEST = 2; /** * Internally used to set our best-guess score. * msg.arg1 = new score */ - private static final int CMD_SET_SCORE = BASE + 2; + private static final int CMD_SET_SCORE = 3; /** * Internally used to set our current filter for coarse bandwidth changes with * technology changes. * msg.obj = new filter */ - private static final int CMD_SET_FILTER = BASE + 3; + private static final int CMD_SET_FILTER = 4; private final Context mContext; private final ArrayList mPreConnectedQueue = new ArrayList(); private final String LOG_TAG; - private final SparseArray mNetworkRequests = - new SparseArray(); + private final Map mNetworkRequests = + new HashMap<>(); private int mScore; private NetworkCapabilities mCapabilityFilter; @@ -158,7 +154,8 @@ public class NetworkFactory extends Handler { }; mMessenger = new Messenger(this); - mProviderId = ConnectivityManager.from(mContext).registerNetworkProvider(mProvider); + mProviderId = ((ConnectivityManager) mContext.getSystemService( + Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); } public void unregister() { @@ -168,7 +165,8 @@ public class NetworkFactory extends Handler { } if (DBG) log("Unregistering NetworkFactory"); - ConnectivityManager.from(mContext).unregisterNetworkProvider(mProvider); + ((ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) + .unregisterNetworkProvider(mProvider); mProvider = null; } @@ -240,14 +238,14 @@ public class NetworkFactory extends Handler { */ @VisibleForTesting protected void handleAddRequest(NetworkRequest request, int score, int servingProviderId) { - NetworkRequestInfo n = mNetworkRequests.get(request.requestId); + NetworkRequestInfo n = mNetworkRequests.get(request); if (n == null) { if (DBG) { log("got request " + request + " with score " + score + " and providerId " + servingProviderId); } n = new NetworkRequestInfo(request, score, servingProviderId); - mNetworkRequests.put(n.request.requestId, n); + mNetworkRequests.put(n.request, n); } else { if (VDBG) { log("new score " + score + " for existing request " + request @@ -263,9 +261,9 @@ public class NetworkFactory extends Handler { @VisibleForTesting protected void handleRemoveRequest(NetworkRequest request) { - NetworkRequestInfo n = mNetworkRequests.get(request.requestId); + NetworkRequestInfo n = mNetworkRequests.get(request); if (n != null) { - mNetworkRequests.remove(request.requestId); + mNetworkRequests.remove(request); if (n.requested) releaseNetworkFor(n.request); } } @@ -334,7 +332,7 @@ public class NetworkFactory extends Handler { && (n.score < mScore || n.providerId == mProviderId) // If this factory can't satisfy the capability needs of this request, then it // should not be tracked. - && n.request.networkCapabilities.satisfiedByNetworkCapabilities(mCapabilityFilter) + && n.request.satisfiedBy(mCapabilityFilter) // Finally if the concrete implementation of the factory rejects the request, then // don't track it. && acceptRequest(n.request, n.score); @@ -350,14 +348,12 @@ public class NetworkFactory extends Handler { // - This factory can't satisfy the capability needs of the request // - The concrete implementation of the factory rejects the request && ((n.score > mScore && n.providerId != mProviderId) - || !n.request.networkCapabilities.satisfiedByNetworkCapabilities( - mCapabilityFilter) + || !n.request.satisfiedBy(mCapabilityFilter) || !acceptRequest(n.request, n.score)); } private void evalRequests() { - for (int i = 0; i < mNetworkRequests.size(); i++) { - NetworkRequestInfo n = mNetworkRequests.valueAt(i); + for (NetworkRequestInfo n : mNetworkRequests.values()) { evalRequest(n); } } @@ -384,7 +380,12 @@ public class NetworkFactory extends Handler { protected void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) { post(() -> { if (DBG) log("releaseRequestAsUnfulfillableByAnyFactory: " + r); - ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(r); + final NetworkProvider provider = mProvider; + if (provider == null) { + Log.e(LOG_TAG, "Ignoring attempt to release unregistered request as unfulfillable"); + return; + } + provider.declareNetworkRequestUnfulfillable(r); }); } @@ -428,13 +429,10 @@ public class NetworkFactory extends Handler { } public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); - pw.println(toString()); - pw.increaseIndent(); - for (int i = 0; i < mNetworkRequests.size(); i++) { - pw.println(mNetworkRequests.valueAt(i)); + writer.println(toString()); + for (NetworkRequestInfo n : mNetworkRequests.values()) { + writer.println(" " + n); } - pw.decreaseIndent(); } @Override From 376f8d49221cd8a83a671c0edfe5d90ddc73e691 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 15 Jan 2020 18:26:29 +0900 Subject: [PATCH 017/777] Fix visibility for services-common lib f/b/services/net should be allowed, not just f/b/services. Test: Dependent change using the build rule builds Bug: 138306002 Merged-In: Ide48e637df6e1c21cd7c0c688e3fef2ba1c97deb Change-Id: Ide48e637df6e1c21cd7c0c688e3fef2ba1c97deb (clean cherry-pick from internal branch) --- staticlibs/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index cf475b9236..2c707abc1e 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -57,7 +57,7 @@ java_library { ], sdk_version: "system_current", visibility: [ - "//frameworks/base/services", + "//frameworks/base/services/net", "//frameworks/base/packages/Tethering", "//frameworks/opt/net/wifi/service", "//frameworks/opt/net/ike", From 0331db1c2c3bc6cb0078fac65e64d76a5b30b74f Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 6 Jan 2020 20:01:12 +0800 Subject: [PATCH 018/777] Add DnsSdTxtRecord to common net static library Move DnsSdTxtRecord from framework to net-utils-framework-common for mainline support. Bug: 139268426 Bug: 135998869 Test: build lib pass atest FrameworksNetTests ./frameworks/opt/net/wifi/tests/wifitests/runtests.sh Merged-In: I16c37b1c0b70bd57f38bde1171bd7d84cf3fa9ce Change-Id: I16c37b1c0b70bd57f38bde1171bd7d84cf3fa9ce (clean cherry-pick from internal branch) --- .../android/net/util/nsd/DnsSdTxtRecord.java | 325 ++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 staticlibs/src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java diff --git a/staticlibs/src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java b/staticlibs/src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java new file mode 100644 index 0000000000..81768f7ed1 --- /dev/null +++ b/staticlibs/src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java @@ -0,0 +1,325 @@ +/* -*- Mode: Java; tab-width: 4 -*- + * + * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * + * 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. + + To do: + - implement remove() + - fix set() to replace existing values + */ + +package android.net.util.nsd; + +import android.os.Parcelable; +import android.os.Parcel; + +import java.util.Arrays; + +/** + * This class handles TXT record data for DNS based service discovery as specified at + * http://tools.ietf.org/html/draft-cheshire-dnsext-dns-sd-11 + * + * DNS-SD specifies that a TXT record corresponding to an SRV record consist of + * a packed array of bytes, each preceded by a length byte. Each string + * is an attribute-value pair. + * + * The DnsSdTxtRecord object stores the entire TXT data as a single byte array, traversing it + * as need be to implement its various methods. + * @hide + * + */ +public class DnsSdTxtRecord implements Parcelable { + private static final byte mSeparator = '='; + + private byte[] mData; + + /** Constructs a new, empty TXT record. */ + public DnsSdTxtRecord() { + mData = new byte[0]; + } + + /** Constructs a new TXT record from a byte array in the standard format. */ + public DnsSdTxtRecord(byte[] data) { + mData = (byte[]) data.clone(); + } + + /** Copy constructor */ + public DnsSdTxtRecord(DnsSdTxtRecord src) { + if (src != null && src.mData != null) { + mData = (byte[]) src.mData.clone(); + } + } + + /** + * Set a key/value pair. Setting an existing key will replace its value. + * @param key Must be ascii with no '=' + * @param value matching value to key + */ + public void set(String key, String value) { + byte[] keyBytes; + byte[] valBytes; + int valLen; + + if (value != null) { + valBytes = value.getBytes(); + valLen = valBytes.length; + } else { + valBytes = null; + valLen = 0; + } + + try { + keyBytes = key.getBytes("US-ASCII"); + } + catch (java.io.UnsupportedEncodingException e) { + throw new IllegalArgumentException("key should be US-ASCII"); + } + + for (int i = 0; i < keyBytes.length; i++) { + if (keyBytes[i] == '=') { + throw new IllegalArgumentException("= is not a valid character in key"); + } + } + + if (keyBytes.length + valLen >= 255) { + throw new IllegalArgumentException("Key and Value length cannot exceed 255 bytes"); + } + + int currentLoc = remove(key); + if (currentLoc == -1) + currentLoc = keyCount(); + + insert(keyBytes, valBytes, currentLoc); + } + + /** + * Get a value for a key + * + * @param key + * @return The value associated with the key + */ + public String get(String key) { + byte[] val = this.getValue(key); + return val != null ? new String(val) : null; + } + + /** Remove a key/value pair. If found, returns the index or -1 if not found */ + public int remove(String key) { + int avStart = 0; + + for (int i=0; avStart < mData.length; i++) { + int avLen = mData[avStart]; + if (key.length() <= avLen && + (key.length() == avLen || mData[avStart + key.length() + 1] == mSeparator)) { + String s = new String(mData, avStart + 1, key.length()); + if (0 == key.compareToIgnoreCase(s)) { + byte[] oldBytes = mData; + mData = new byte[oldBytes.length - avLen - 1]; + System.arraycopy(oldBytes, 0, mData, 0, avStart); + System.arraycopy(oldBytes, avStart + avLen + 1, mData, avStart, + oldBytes.length - avStart - avLen - 1); + return i; + } + } + avStart += (0xFF & (avLen + 1)); + } + return -1; + } + + /** Return the count of keys */ + public int keyCount() { + int count = 0, nextKey; + for (nextKey = 0; nextKey < mData.length; count++) { + nextKey += (0xFF & (mData[nextKey] + 1)); + } + return count; + } + + /** Return true if key is present, false if not. */ + public boolean contains(String key) { + String s = null; + for (int i = 0; null != (s = this.getKey(i)); i++) { + if (0 == key.compareToIgnoreCase(s)) return true; + } + return false; + } + + /* Gets the size in bytes */ + public int size() { + return mData.length; + } + + /* Gets the raw data in bytes */ + public byte[] getRawData() { + return (byte[]) mData.clone(); + } + + private void insert(byte[] keyBytes, byte[] value, int index) { + byte[] oldBytes = mData; + int valLen = (value != null) ? value.length : 0; + int insertion = 0; + int newLen, avLen; + + for (int i = 0; i < index && insertion < mData.length; i++) { + insertion += (0xFF & (mData[insertion] + 1)); + } + + avLen = keyBytes.length + valLen + (value != null ? 1 : 0); + newLen = avLen + oldBytes.length + 1; + + mData = new byte[newLen]; + System.arraycopy(oldBytes, 0, mData, 0, insertion); + int secondHalfLen = oldBytes.length - insertion; + System.arraycopy(oldBytes, insertion, mData, newLen - secondHalfLen, secondHalfLen); + mData[insertion] = (byte) avLen; + System.arraycopy(keyBytes, 0, mData, insertion + 1, keyBytes.length); + if (value != null) { + mData[insertion + 1 + keyBytes.length] = mSeparator; + System.arraycopy(value, 0, mData, insertion + keyBytes.length + 2, valLen); + } + } + + /** Return a key in the TXT record by zero-based index. Returns null if index exceeds the total number of keys. */ + private String getKey(int index) { + int avStart = 0; + + for (int i=0; i < index && avStart < mData.length; i++) { + avStart += mData[avStart] + 1; + } + + if (avStart < mData.length) { + int avLen = mData[avStart]; + int aLen = 0; + + for (aLen=0; aLen < avLen; aLen++) { + if (mData[avStart + aLen + 1] == mSeparator) break; + } + return new String(mData, avStart + 1, aLen); + } + return null; + } + + /** + * Look up a key in the TXT record by zero-based index and return its value. + * Returns null if index exceeds the total number of keys. + * Returns null if the key is present with no value. + */ + private byte[] getValue(int index) { + int avStart = 0; + byte[] value = null; + + for (int i=0; i < index && avStart < mData.length; i++) { + avStart += mData[avStart] + 1; + } + + if (avStart < mData.length) { + int avLen = mData[avStart]; + int aLen = 0; + + for (aLen=0; aLen < avLen; aLen++) { + if (mData[avStart + aLen + 1] == mSeparator) { + value = new byte[avLen - aLen - 1]; + System.arraycopy(mData, avStart + aLen + 2, value, 0, avLen - aLen - 1); + break; + } + } + } + return value; + } + + private String getValueAsString(int index) { + byte[] value = this.getValue(index); + return value != null ? new String(value) : null; + } + + private byte[] getValue(String forKey) { + String s = null; + int i; + + for (i = 0; null != (s = this.getKey(i)); i++) { + if (0 == forKey.compareToIgnoreCase(s)) { + return this.getValue(i); + } + } + + return null; + } + + /** + * Return a string representation. + * Example : {key1=value1},{key2=value2}.. + * + * For a key say like "key3" with null value + * {key1=value1},{key2=value2}{key3} + */ + public String toString() { + String a, result = null; + + for (int i = 0; null != (a = this.getKey(i)); i++) { + String av = "{" + a; + String val = this.getValueAsString(i); + if (val != null) + av += "=" + val + "}"; + else + av += "}"; + if (result == null) + result = av; + else + result = result + ", " + av; + } + return result != null ? result : ""; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof DnsSdTxtRecord)) { + return false; + } + + DnsSdTxtRecord record = (DnsSdTxtRecord)o; + return Arrays.equals(record.mData, mData); + } + + @Override + public int hashCode() { + return Arrays.hashCode(mData); + } + + /** Implement the Parcelable interface */ + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeByteArray(mData); + } + + /** Implement the Parcelable interface */ + public static final @android.annotation.NonNull Creator CREATOR = + new Creator() { + public DnsSdTxtRecord createFromParcel(Parcel in) { + DnsSdTxtRecord info = new DnsSdTxtRecord(); + in.readByteArray(info.mData); + return info; + } + + public DnsSdTxtRecord[] newArray(int size) { + return new DnsSdTxtRecord[size]; + } + }; +} From fc8056d7bd6110545691247165183b4c9326813d Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 15 Jan 2020 19:22:57 +0900 Subject: [PATCH 019/777] Address MacAddressUtils / NetworkFactory comments Remove unused code, and make NetworkRequest iterating order deterministic. Test: atest FrameworksNetTests FrameworksWifiTests \ FrameworksTelephonyTests Bug: 138306002 Merged-In: I1a8f2b07dd1b3ef8286c8b578ed7ae38c87bb38c Change-Id: I1a8f2b07dd1b3ef8286c8b578ed7ae38c87bb38c (clean cherry-pick from internal branch) --- .../android/net/util/MacAddressUtils.java | 2 +- .../android/net/NetworkFactory.java | 19 ++----------------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java b/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java index e71f8fb69a..3ad452ba30 100644 --- a/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java +++ b/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java @@ -103,7 +103,7 @@ public final class MacAddressUtils { } long longAddr = 0; for (byte b : addr) { - final int uint8Byte = b & 255; + final int uint8Byte = b & 0xff; longAddr = (longAddr << 8) + uint8Byte; } return longAddr; diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java index 571f796217..3758bb50b5 100644 --- a/staticlibs/src_servicescommon/android/net/NetworkFactory.java +++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java @@ -29,9 +29,8 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; /** * A NetworkFactory is an entity that creates NetworkAgent objects. @@ -49,20 +48,6 @@ import java.util.concurrent.atomic.AtomicInteger; * @hide **/ public class NetworkFactory extends Handler { - /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ - public static class SerialNumber { - // Guard used by no network factory. - public static final int NONE = -1; - // A hardcoded serial number for NetworkAgents representing VPNs. These agents are - // not created by any factory, so they use this constant for clarity instead of NONE. - public static final int VPN = -2; - private static final AtomicInteger sNetworkFactorySerialNumber = new AtomicInteger(1); - /** Returns a unique serial number for a factory. */ - public static final int nextSerialNumber() { - return sNetworkFactorySerialNumber.getAndIncrement(); - } - } - private static final boolean DBG = true; private static final boolean VDBG = false; /** @@ -115,7 +100,7 @@ public class NetworkFactory extends Handler { private final String LOG_TAG; private final Map mNetworkRequests = - new HashMap<>(); + new LinkedHashMap<>(); private int mScore; private NetworkCapabilities mCapabilityFilter; From 864bdec16e94560650123c04bb481b9203509d66 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Thu, 16 Jan 2020 09:19:11 -0800 Subject: [PATCH 020/777] libs(net/common): Create filegroups for wifi sources Safer for wifi to just include the sources that it needs. Then there is no accidental risk of un-jar-jar'ed classes showing up in it's namespace. Bug: 135998869 Test: Compiles Merged-In: I2532f640fbebd4ca82be7bbb63744bcad653ac34 Change-Id: I2532f640fbebd4ca82be7bbb63744bcad653ac34 (clean cherry-pick from internal branch) --- staticlibs/Android.bp | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 2c707abc1e..6827403b36 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -41,7 +41,6 @@ java_library { jarjar_rules: "jarjar-rules-shared.txt", visibility: [ "//frameworks/base/packages/Tethering", - "//frameworks/opt/net/wifi", "//frameworks/opt/net/ike", "//frameworks/opt/telephony", "//packages/modules/NetworkStack", @@ -59,7 +58,6 @@ java_library { visibility: [ "//frameworks/base/services/net", "//frameworks/base/packages/Tethering", - "//frameworks/opt/net/wifi/service", "//frameworks/opt/net/ike", "//packages/modules/NetworkStack", "//packages/modules/CaptivePortalLogin", @@ -78,3 +76,30 @@ filegroup { "//frameworks/opt/telephony", ], } + +// Use a filegroup and not a library for wifi sources, as this needs corresponding jar-jar +// rules on the wifi side. +// Any class here *must* have a corresponding jarjar rule in the wifi build rules. +filegroup { + name: "net-utils-framework-wifi-common-srcs", + srcs: [ + "src_frameworkcommon/android/net/util/MacAddressUtils.java", + ], + visibility: [ + "//frameworks/base", + ], +} + +// Use a filegroup and not a library for wifi sources, as this needs corresponding jar-jar +// rules on the wifi side. +// Any class here *must* have a corresponding jarjar rule in the wifi build rules. +filegroup { + name: "net-utils-wifi-service-common-srcs", + srcs: [ + "src_frameworkcommon/android/net/util/NetUtils.java", + "src_servicescommon/android/net/NetworkFactory.java", + ], + visibility: [ + "//frameworks/opt/net/wifi/service", + ], +} From 37535278c4f70f3e8ed5688376db935151b424cb Mon Sep 17 00:00:00 2001 From: David Su Date: Thu, 16 Jan 2020 20:56:39 -0800 Subject: [PATCH 021/777] Statically link DnsSdTxtRecord into framework-wifi DnsSdTxtRecord is @hide, thus need to statically link it into framework-wifi. Bug: 135998869 Test: boots up and connects to wifi Merged-In: Ic5f7decfdbc3116a15fe8da3841cc7620105996d Change-Id: Ic5f7decfdbc3116a15fe8da3841cc7620105996d (clean cherry-pick from internal branch) --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 6827403b36..c3b86682fc 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -83,6 +83,7 @@ filegroup { filegroup { name: "net-utils-framework-wifi-common-srcs", srcs: [ + "src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java", "src_frameworkcommon/android/net/util/MacAddressUtils.java", ], visibility: [ From c9366dec3be71bf2d54a45387f95dff35d7a8c09 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 16 Jan 2020 18:58:16 +0900 Subject: [PATCH 022/777] Updates to NetworkFactory for the new NetworkAgent constructor Bug: 138306002 Bug: 139268426 Test: atest FrameworksNetTests FrameworksWifiTests FrameworksTelephonyTests Merged-In: If327cf0ffd917f9cb358f9ed3779da58fce40ef8 Change-Id: If327cf0ffd917f9cb358f9ed3779da58fce40ef8 (clean cherry-pick from internal branch) --- .../android/net/NetworkFactory.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java index 3758bb50b5..47054f504a 100644 --- a/staticlibs/src_servicescommon/android/net/NetworkFactory.java +++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java @@ -108,7 +108,6 @@ public class NetworkFactory extends Handler { private int mRefCount = 0; private Messenger mMessenger = null; private NetworkProvider mProvider = null; - private int mProviderId; public NetworkFactory(Looper looper, Context context, String logTag, NetworkCapabilities filter) { @@ -139,7 +138,7 @@ public class NetworkFactory extends Handler { }; mMessenger = new Messenger(this); - mProviderId = ((ConnectivityManager) mContext.getSystemService( + ((ConnectivityManager) mContext.getSystemService( Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); } @@ -292,8 +291,8 @@ public class NetworkFactory extends Handler { log(" n.requests = " + n.requested); log(" n.score = " + n.score); log(" mScore = " + mScore); - log(" n.providerId = " + n.providerId); - log(" mProviderId = " + mProviderId); + log(" request.providerId = " + n.providerId); + log(" mProvider.id = " + mProvider.getProviderId()); } if (shouldNeedNetworkFor(n)) { if (VDBG) log(" needNetworkFor"); @@ -314,7 +313,7 @@ public class NetworkFactory extends Handler { // If the score of this request is higher or equal to that of this factory and some // other factory is responsible for it, then this factory should not track the request // because it has no hope of satisfying it. - && (n.score < mScore || n.providerId == mProviderId) + && (n.score < mScore || n.providerId == mProvider.getProviderId()) // If this factory can't satisfy the capability needs of this request, then it // should not be tracked. && n.request.satisfiedBy(mCapabilityFilter) @@ -332,7 +331,7 @@ public class NetworkFactory extends Handler { // assigned to the factory // - This factory can't satisfy the capability needs of the request // - The concrete implementation of the factory rejects the request - && ((n.score > mScore && n.providerId != mProviderId) + && ((n.score > mScore && n.providerId != mProvider.getProviderId()) || !n.request.satisfiedBy(mCapabilityFilter) || !acceptRequest(n.request, n.score)); } @@ -402,11 +401,11 @@ public class NetworkFactory extends Handler { /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ public int getSerialNumber() { - return mProviderId; + return mProvider.getProviderId(); } - public int getProviderId() { - return mProviderId; + public NetworkProvider getProvider() { + return mProvider; } protected void log(String s) { @@ -422,8 +421,8 @@ public class NetworkFactory extends Handler { @Override public String toString() { - StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - mProviderId=") - .append(mProviderId).append(", ScoreFilter=") + StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - providerId=") + .append(mProvider.getProviderId()).append(", ScoreFilter=") .append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests=") .append(mNetworkRequests.size()).append(", refCount=").append(mRefCount) .append("}"); From 5d9f8ed872e0ccccfe39b5a3b41b277ca66c1b63 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 21 Jan 2020 15:31:06 +0900 Subject: [PATCH 023/777] Run NetworkStaticLibTests on the actual source files. Currently, NetworkStaticLibTests tests the class files that are on the bootclasspath of the device. This makes running these tests slow and/or confusing, because the framework must be rebuilt and the device flashed before running the tests, and if this is not done, the old code will be tested instead. Instead, jarjar the tests so the test can be run without updating the device. Bug: 142892223 Test: atest NetworkStaticLibTests passes on device that does not have the library Change-Id: I6a0dbebddbd0b64e2722078345ffe6b0c0a1801e --- staticlibs/Android.bp | 2 ++ staticlibs/tests/unit/Android.bp | 3 +++ staticlibs/tests/unit/jarjar-rules.txt | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 staticlibs/tests/unit/jarjar-rules.txt diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 713a0d61d7..3f867fcd7c 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -40,6 +40,7 @@ java_library { "//frameworks/opt/telephony", "//packages/modules/NetworkStack", "//packages/modules/CaptivePortalLogin", + "//frameworks/libs/net/common/tests:__subpackages__", ] } @@ -53,6 +54,7 @@ java_library { "//frameworks/opt/net/ike", "//packages/modules/NetworkStack", "//packages/modules/CaptivePortalLogin", + "//frameworks/libs/net/common/tests:__subpackages__", ], } diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index 4a51a8c2d3..fe363f5a28 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -6,9 +6,12 @@ android_test { name: "NetworkStaticLibTests", certificate: "platform", srcs: ["src/**/*.java","src/**/*.kt"], + jarjar_rules: "jarjar-rules.txt", test_suites: ["device-tests"], static_libs: [ "androidx.test.rules", + "net-utils-framework-common", + "net-utils-services-common", ], libs: [ "android.test.runner", diff --git a/staticlibs/tests/unit/jarjar-rules.txt b/staticlibs/tests/unit/jarjar-rules.txt new file mode 100644 index 0000000000..dbb3974f7a --- /dev/null +++ b/staticlibs/tests/unit/jarjar-rules.txt @@ -0,0 +1,4 @@ +# Ensure that the tests can directly use the version of classes from the library. Otherwise, they +# will use whatever version is currently in the bootclasspath on the device running the test. +# These rules must match the jarjar rules used to build the library. +rule android.net.util.** com.android.net.module.util.@1 From 9c0c6a5c0505bd8cc9de4d0a06f03a0964bdd94e Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 21 Jan 2020 15:35:11 +0900 Subject: [PATCH 024/777] Add a CompareOrUpdateResult class. This is like CompareResult, but also has the concept of an item being "updated" (i.e., the same, but with different properties, in the old and the new list of items). This is needed to support updating routes. Bug: 142892223 Test: new unit test Change-Id: Ide5e31acb9baa6a5d3f50e9965d4019eb7c82cd4 --- .../android/net/util/LinkPropertiesUtils.java | 56 +++++++++++++++++ .../net/util/LinkPropertiesUtilsTest.java | 62 ++++++++++++++++++- 2 files changed, 117 insertions(+), 1 deletion(-) diff --git a/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java b/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java index 59d88accc8..c50ca0b650 100644 --- a/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java +++ b/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java @@ -26,8 +26,10 @@ import android.text.TextUtils; import java.net.InetAddress; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Objects; +import java.util.function.Function; /** * Collection of link properties utilities. @@ -64,6 +66,60 @@ public final class LinkPropertiesUtils { } } + /** + * Generic class to compare two lists of items of type {@code T} whose properties can change. + * The items to be compared must provide a way to calculate a corresponding key of type + * {@code K} such that if (and only if) an old and a new item have the same key, then the new + * item is an update of the old item. Both the old list and the new list may not contain more + * than one item with the same key, and may not contain any null items. + * + * @param A class that represents the key of the items to be compared. + * @param The class that represents the object to be compared. + */ + public static class CompareOrUpdateResult { + public final List added = new ArrayList<>(); + public final List removed = new ArrayList<>(); + public final List updated = new ArrayList<>(); + + /** + * Compares two lists of items. + * @param oldItems the old list of items. + * @param newItems the new list of items. + * @param keyCalculator a {@link Function} that calculates an item's key. + */ + public CompareOrUpdateResult(Collection oldItems, Collection newItems, + Function keyCalculator) { + HashMap updateTracker = new HashMap<>(); + + for (T oldItem : oldItems) { + updateTracker.put(keyCalculator.apply(oldItem), oldItem); + } + + for (T newItem : newItems) { + T oldItem = updateTracker.remove(keyCalculator.apply(newItem)); + if (oldItem != null) { + if (!oldItem.equals(newItem)) { + // Update of existing item. + updated.add(newItem); + } + } else { + // New item. + added.add(newItem); + } + } + + removed.addAll(updateTracker.values()); + } + + @Override + public String toString() { + return "removed=[" + TextUtils.join(",", removed) + + "] added=[" + TextUtils.join(",", added) + + "] updated=[" + TextUtils.join(",", updated) + + "]"; + } + } + /** * Compares the addresses in {@code left} LinkProperties with {@code right} * LinkProperties, examining only addresses on the base link. diff --git a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java index 6e06ee877b..e2cde34a98 100644 --- a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java @@ -26,6 +26,7 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.ProxyInfo; import android.net.RouteInfo; +import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult; import android.net.util.LinkPropertiesUtils.CompareResult; import androidx.test.runner.AndroidJUnit4; @@ -34,6 +35,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.function.Function; @RunWith(AndroidJUnit4.class) public final class LinkPropertiesUtilsTest { @@ -185,4 +191,58 @@ public final class LinkPropertiesUtilsTest { assertEquals(linkAddr1, results.removed.get(0)); assertEquals(linkAddr2, results.added.get(0)); } -} + + private void assertSameElements(List expected, List actual) { + HashSet expectedSet = new HashSet(expected); + assertEquals("expected list contains duplicates", expectedSet.size(), expected.size()); + HashSet actualSet = new HashSet(actual); + assertEquals("actual list contains duplicates", actualSet.size(), actual.size()); + assertEquals(expectedSet, actualSet); + } + + private void assertCompareOrUpdateResult(CompareOrUpdateResult result, + List expectedAdded, List expectedRemoved, + List expectedUpdated) { + assertSameElements(expectedAdded, result.added); + assertSameElements(expectedRemoved, result.removed); + assertSameElements(expectedUpdated, result.updated); + } + + private List strArray(String... strs) { + return Arrays.asList(strs); + } + + @Test + public void testCompareOrUpdateResult() { + // As the item type, use a simple string. An item is defined to be an update of another item + // if the string starts with the same alphabetical characters. + // Extracting the key from the object is just a regexp. + Function extractPrefix = (s) -> s.replaceFirst("^([a-z]+).*", "$1"); + assertEquals("goodbye", extractPrefix.apply("goodbye1234")); + + List oldItems = strArray("hello123", "goodbye5678", "howareyou669"); + List newItems = strArray("hello123", "goodbye000", "verywell"); + + final List emptyList = new ArrayList<>(); + + // Items -> empty: everything removed. + CompareOrUpdateResult result = + new CompareOrUpdateResult(oldItems, emptyList, extractPrefix); + assertCompareOrUpdateResult(result, + emptyList, strArray("hello123", "howareyou669", "goodbye5678"), emptyList); + + // Empty -> items: everything added. + result = new CompareOrUpdateResult(emptyList, newItems, extractPrefix); + assertCompareOrUpdateResult(result, + strArray("hello123", "goodbye000", "verywell"), emptyList, emptyList); + + // Empty -> empty: no change. + result = new CompareOrUpdateResult(newItems, newItems, extractPrefix); + assertCompareOrUpdateResult(result, emptyList, emptyList, emptyList); + + // Added, removed, updated at the same time. + result = new CompareOrUpdateResult<>(oldItems, newItems, extractPrefix); + assertCompareOrUpdateResult(result, + strArray("verywell"), strArray("howareyou669"), strArray("goodbye000")); + } +} \ No newline at end of file From 65e8b66875f858e80e955b1aa2567e5fcfcf0aa4 Mon Sep 17 00:00:00 2001 From: Tyler Wear Date: Mon, 27 Jan 2020 10:55:38 -0800 Subject: [PATCH 025/777] Update CompareOrUpdateResult with NULL Check Like CompareResult, add in null check for input objects. Test: updated unit test Change-Id: Iea63752ff23a5bfb1cc5cb716ec579bec6c403bf --- .../android/net/util/LinkPropertiesUtils.java | 31 ++++++++++--------- .../net/util/LinkPropertiesUtilsTest.java | 12 ++++++- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java b/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java index c50ca0b650..bd96edbf72 100644 --- a/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java +++ b/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java @@ -91,23 +91,26 @@ public final class LinkPropertiesUtils { Function keyCalculator) { HashMap updateTracker = new HashMap<>(); - for (T oldItem : oldItems) { - updateTracker.put(keyCalculator.apply(oldItem), oldItem); - } - - for (T newItem : newItems) { - T oldItem = updateTracker.remove(keyCalculator.apply(newItem)); - if (oldItem != null) { - if (!oldItem.equals(newItem)) { - // Update of existing item. - updated.add(newItem); - } - } else { - // New item. - added.add(newItem); + if (oldItems != null) { + for (T oldItem : oldItems) { + updateTracker.put(keyCalculator.apply(oldItem), oldItem); } } + if (newItems != null) { + for (T newItem : newItems) { + T oldItem = updateTracker.remove(keyCalculator.apply(newItem)); + if (oldItem != null) { + if (!oldItem.equals(newItem)) { + // Update of existing item. + updated.add(newItem); + } + } else { + // New item. + added.add(newItem); + } + } + } removed.addAll(updateTracker.values()); } diff --git a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java index e2cde34a98..0fa1c52e1a 100644 --- a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java @@ -229,7 +229,7 @@ public final class LinkPropertiesUtilsTest { CompareOrUpdateResult result = new CompareOrUpdateResult(oldItems, emptyList, extractPrefix); assertCompareOrUpdateResult(result, - emptyList, strArray("hello123", "howareyou669", "goodbye5678"), emptyList); + emptyList, strArray("hello123", "howareyou669", "goodbye5678"), emptyList); // Empty -> items: everything added. result = new CompareOrUpdateResult(emptyList, newItems, extractPrefix); @@ -244,5 +244,15 @@ public final class LinkPropertiesUtilsTest { result = new CompareOrUpdateResult<>(oldItems, newItems, extractPrefix); assertCompareOrUpdateResult(result, strArray("verywell"), strArray("howareyou669"), strArray("goodbye000")); + + // Null -> items: everything added. + result = new CompareOrUpdateResult(null, newItems, extractPrefix); + assertCompareOrUpdateResult(result, + strArray("hello123", "goodbye000", "verywell"), emptyList, emptyList); + + // Items -> null: everything removed. + result = new CompareOrUpdateResult(oldItems, null, extractPrefix); + assertCompareOrUpdateResult(result, + emptyList, strArray("hello123", "howareyou669", "goodbye5678"), emptyList); } } \ No newline at end of file From 3767434b21800c467c8e2c5a80bfdcb3203199a4 Mon Sep 17 00:00:00 2001 From: Tyler Wear Date: Tue, 28 Jan 2020 16:38:01 -0800 Subject: [PATCH 026/777] Update CompareOrUpdateResult with NULL NULL Check Add a test to CompareOrUpdateResult where the new and old item list are both NULL. Test: Updated unit test Change-Id: I6821028409d29ab864af52685629630cbf16db3b --- .../android/net/util/LinkPropertiesUtils.java | 1 + .../unit/src/android/net/util/LinkPropertiesUtilsTest.java | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java b/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java index bd96edbf72..812382694a 100644 --- a/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java +++ b/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java @@ -111,6 +111,7 @@ public final class LinkPropertiesUtils { } } } + removed.addAll(updateTracker.values()); } diff --git a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java index 0fa1c52e1a..6ffcc1d0a9 100644 --- a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java @@ -254,5 +254,9 @@ public final class LinkPropertiesUtilsTest { result = new CompareOrUpdateResult(oldItems, null, extractPrefix); assertCompareOrUpdateResult(result, emptyList, strArray("hello123", "howareyou669", "goodbye5678"), emptyList); + + // Null -> null: all lists empty. + result = new CompareOrUpdateResult(null, null, extractPrefix); + assertCompareOrUpdateResult(result, emptyList, emptyList, emptyList); } -} \ No newline at end of file +} From db0915c14cb24e8a36c2feb2b8a9bfd008e2d504 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 20 Jan 2020 17:03:21 -0800 Subject: [PATCH 027/777] Add IpRange utility to convert IP ranges to IpPrefix IKE Traffic Selectors are defined to be an IP range, with a start and an end IP address. However, the Android system works in IP Prefixes. This commit adds a utility to convert between the two. Bug: 144246767 Test: New tests added, passing Change-Id: I428fee682dea21346f92c5c628642dee3c785ba9 --- .../android/net/util/IpRange.java | 221 ++++++++++++++ .../src/android/net/util/IpRangeTest.java | 270 ++++++++++++++++++ 2 files changed, 491 insertions(+) create mode 100644 staticlibs/src_frameworkcommon/android/net/util/IpRange.java create mode 100644 staticlibs/tests/unit/src/android/net/util/IpRangeTest.java diff --git a/staticlibs/src_frameworkcommon/android/net/util/IpRange.java b/staticlibs/src_frameworkcommon/android/net/util/IpRange.java new file mode 100644 index 0000000000..04e92773bb --- /dev/null +++ b/staticlibs/src_frameworkcommon/android/net/util/IpRange.java @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2020 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.util; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.NonNull; +import android.net.IpPrefix; + +import com.android.internal.annotations.VisibleForTesting; + +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.Queue; + +/** + * This class represents an IP range, i.e., a contiguous block of IP addresses defined by a starting + * and ending IP address. These addresses may not be power-of-two aligned. + * + *

Conversion to prefixes are deterministic, and will always return the same set of {@link + * IpPrefix}(es). Ordering of IpPrefix instances is not guaranteed. + */ +public final class IpRange { + private static final int SIGNUM_POSITIVE = 1; + + private final byte[] mStartAddr; + private final byte[] mEndAddr; + + public IpRange(@NonNull InetAddress startAddr, @NonNull InetAddress endAddr) { + Objects.requireNonNull(startAddr, "startAddr must not be null"); + Objects.requireNonNull(endAddr, "endAddr must not be null"); + + if (!startAddr.getClass().equals(endAddr.getClass())) { + throw new IllegalArgumentException("Invalid range: Address family mismatch"); + } + if (addrToBigInteger(startAddr.getAddress()).compareTo( + addrToBigInteger(endAddr.getAddress())) >= 0) { + throw new IllegalArgumentException( + "Invalid range; start address must be before end address"); + } + + mStartAddr = startAddr.getAddress(); + mEndAddr = endAddr.getAddress(); + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public IpRange(@NonNull IpPrefix prefix) { + Objects.requireNonNull(prefix, "prefix must not be null"); + + // Use masked address from IpPrefix to zero out lower order bits. + mStartAddr = prefix.getRawAddress(); + + // Set all non-prefix bits to max. + mEndAddr = prefix.getRawAddress(); + for (int bitIndex = prefix.getPrefixLength(); bitIndex < 8 * mEndAddr.length; ++bitIndex) { + mEndAddr[bitIndex / 8] |= (byte) (0x80 >> (bitIndex % 8)); + } + } + + private static InetAddress getAsInetAddress(byte[] address) { + try { + return InetAddress.getByAddress(address); + } catch (UnknownHostException e) { + // Cannot happen. InetAddress.getByAddress can only throw an exception if the byte + // array is the wrong length, but are always generated from InetAddress(es). + throw new IllegalArgumentException("Address is invalid"); + } + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public InetAddress getStartAddr() { + return getAsInetAddress(mStartAddr); + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public InetAddress getEndAddr() { + return getAsInetAddress(mEndAddr); + } + + /** + * Converts this IP range to a list of IpPrefix instances. + * + *

This method outputs the IpPrefix instances for use in the routing architecture. + * + *

For example, the range 192.0.2.4 - 192.0.3.1 converts to the following prefixes: + * + *

    + *
  • 192.0.2.128/25 + *
  • 192.0.2.64/26 + *
  • 192.0.2.32/27 + *
  • 192.0.2.16/28 + *
  • 192.0.2.8/29 + *
  • 192.0.2.4/30 + *
  • 192.0.3.0/31 + *
+ */ + public List asIpPrefixes() { + final boolean isIpv6 = (mStartAddr.length == 16); + final List result = new ArrayList<>(); + final Queue workingSet = new LinkedList<>(); + + // Start with the any-address. Inet4/6Address.ANY requires compiling against + // core-platform-api. + workingSet.add(new IpPrefix(isIpv6 ? getAsInetAddress(new byte[16]) /* IPv6_ANY */ + : getAsInetAddress(new byte[4]) /* IPv4_ANY */, 0)); + + // While items are still in the queue, test and narrow to subsets. + while (!workingSet.isEmpty()) { + final IpPrefix workingPrefix = workingSet.poll(); + final IpRange workingRange = new IpRange(workingPrefix); + + // If the other range is contained within, it's part of the output. Do not test subsets, + // or we will end up with duplicates. + if (containsRange(workingRange)) { + result.add(workingPrefix); + continue; + } + + // If there is any overlap, split the working range into it's two subsets, and + // reevaluate those. + if (overlapsRange(workingRange)) { + workingSet.addAll(getSubsetPrefixes(workingPrefix)); + } + } + + return result; + } + + /** + * Returns the two prefixes that comprise the given prefix. + * + *

For example, for the prefix 192.0.2.0/24, this will return the two prefixes that combined + * make up the current prefix: + * + *

    + *
  • 192.0.2.0/25 + *
  • 192.0.2.128/25 + *
+ */ + private static List getSubsetPrefixes(IpPrefix prefix) { + final List result = new ArrayList<>(); + + final int currentPrefixLen = prefix.getPrefixLength(); + result.add(new IpPrefix(prefix.getAddress(), currentPrefixLen + 1)); + + final byte[] other = prefix.getRawAddress(); + other[currentPrefixLen / 8] = + (byte) (other[currentPrefixLen / 8] ^ (0x80 >> (currentPrefixLen % 8))); + result.add(new IpPrefix(getAsInetAddress(other), currentPrefixLen + 1)); + + return result; + } + + /** + * Checks if the other IP range is contained within this one + * + *

Checks based on byte values. For other to be contained within this IP range, other's + * starting address must be greater or equal to the current IpRange's starting address, and the + * other's ending address must be less than or equal to the current IP range's ending address. + */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public boolean containsRange(IpRange other) { + return addrToBigInteger(mStartAddr).compareTo(addrToBigInteger(other.mStartAddr)) <= 0 + && addrToBigInteger(mEndAddr).compareTo(addrToBigInteger(other.mEndAddr)) >= 0; + } + + /** + * Checks if the other IP range overlaps with this one + * + *

Checks based on byte values. For there to be overlap, this IpRange's starting address must + * be less than the other's ending address, and vice versa. + */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public boolean overlapsRange(IpRange other) { + return addrToBigInteger(mStartAddr).compareTo(addrToBigInteger(other.mEndAddr)) <= 0 + && addrToBigInteger(other.mStartAddr).compareTo(addrToBigInteger(mEndAddr)) <= 0; + } + + @Override + public int hashCode() { + return Objects.hash(mStartAddr, mEndAddr); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof IpRange)) { + return false; + } + + final IpRange other = (IpRange) obj; + return Arrays.equals(mStartAddr, other.mStartAddr) + && Arrays.equals(mEndAddr, other.mEndAddr); + } + + /** Gets the InetAddress in BigInteger form */ + private static BigInteger addrToBigInteger(byte[] addr) { + // Since addr.getAddress() returns network byte order (big-endian), it is compatible with + // the BigInteger constructor (which assumes big-endian). + return new BigInteger(SIGNUM_POSITIVE, addr); + } +} diff --git a/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java b/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java new file mode 100644 index 0000000000..f4d07e9b3e --- /dev/null +++ b/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2020 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.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.net.InetAddresses; +import android.net.IpPrefix; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class IpRangeTest { + + private static InetAddress address(String addr) { + return InetAddresses.parseNumericAddress(addr); + } + + private static final Inet4Address IPV4_ADDR = (Inet4Address) address("192.0.2.4"); + private static final Inet4Address IPV4_RANGE_END = (Inet4Address) address("192.0.3.1"); + private static final Inet6Address IPV6_ADDR = (Inet6Address) address("2001:db8::"); + private static final Inet6Address IPV6_RANGE_END = (Inet6Address) address("2001:db9:010f::"); + + private static final byte[] IPV4_BYTES = IPV4_ADDR.getAddress(); + private static final byte[] IPV6_BYTES = IPV6_ADDR.getAddress(); + + @Test + public void testConstructorBadArguments() { + try { + new IpRange(null, IPV6_ADDR); + fail("Expected NullPointerException: null start address"); + } catch (NullPointerException expected) { + } + + try { + new IpRange(IPV6_ADDR, null); + fail("Expected NullPointerException: null end address"); + } catch (NullPointerException expected) { + } + + try { + new IpRange(null, null); + fail("Expected NullPointerException: null addresses"); + } catch (NullPointerException expected) { + } + + try { + new IpRange(null); + fail("Expected NullPointerException: null start address"); + } catch (NullPointerException expected) { + } + + try { + new IpRange(address("10.10.10.10"), address("1.2.3.4")); + fail("Expected IllegalArgumentException: start address after end address"); + } catch (IllegalArgumentException expected) { + } + + try { + new IpRange(address("ffff::"), address("abcd::")); + fail("Expected IllegalArgumentException: start address after end address"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testConstructor() { + IpRange r = new IpRange(new IpPrefix(IPV4_ADDR, 32)); + assertEquals(IPV4_ADDR, r.getStartAddr()); + assertEquals(IPV4_ADDR, r.getEndAddr()); + + r = new IpRange(new IpPrefix(IPV4_ADDR, 16)); + assertEquals(address("192.0.0.0"), r.getStartAddr()); + assertEquals(address("192.0.255.255"), r.getEndAddr()); + + r = new IpRange(IPV4_ADDR, IPV4_RANGE_END); + assertEquals(IPV4_ADDR, r.getStartAddr()); + assertEquals(IPV4_RANGE_END, r.getEndAddr()); + + r = new IpRange(new IpPrefix(IPV6_ADDR, 128)); + assertEquals(IPV6_ADDR, r.getStartAddr()); + assertEquals(IPV6_ADDR, r.getEndAddr()); + + r = new IpRange(new IpPrefix(IPV6_ADDR, 16)); + assertEquals(address("2001::"), r.getStartAddr()); + assertEquals(address("2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff"), r.getEndAddr()); + + r = new IpRange(IPV6_ADDR, IPV6_RANGE_END); + assertEquals(IPV6_ADDR, r.getStartAddr()); + assertEquals(IPV6_RANGE_END, r.getEndAddr()); + } + + @Test + public void testContainsRangeEqualRanges() { + final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); + final IpRange r2 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); + + assertTrue(r1.containsRange(r2)); + assertTrue(r2.containsRange(r1)); + assertEquals(r1, r2); + } + + @Test + public void testContainsRangeSubset() { + final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 64)); + final IpRange r2 = new IpRange(new IpPrefix(address("2001:db8::0101"), 128)); + + assertTrue(r1.containsRange(r2)); + assertFalse(r2.containsRange(r1)); + assertNotEquals(r1, r2); + } + + @Test + public void testContainsRangeTruncatesLowerOrderBits() { + final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 100)); + final IpRange r2 = new IpRange(new IpPrefix(address("2001:db8::0101"), 100)); + + assertTrue(r1.containsRange(r2)); + assertTrue(r2.containsRange(r1)); + assertEquals(r1, r2); + } + + @Test + public void testContainsRangeSubsetSameStartAddr() { + final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); + final IpRange r2 = new IpRange(new IpPrefix(IPV6_ADDR, 39)); + + assertTrue(r1.containsRange(r2)); + assertFalse(r2.containsRange(r1)); + assertNotEquals(r1, r2); + } + + @Test + public void testContainsRangeOverlapping() { + final IpRange r1 = new IpRange(new IpPrefix(address("2001:db9::"), 32)); + final IpRange r2 = new IpRange(address("2001:db8::"), address("2001:db9::1")); + + assertFalse(r1.containsRange(r2)); + assertFalse(r2.containsRange(r1)); + assertNotEquals(r1, r2); + } + + @Test + public void testOverlapsRangeEqualRanges() { + final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); + final IpRange r2 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); + + assertTrue(r1.overlapsRange(r2)); + assertTrue(r2.overlapsRange(r1)); + assertEquals(r1, r2); + } + + @Test + public void testOverlapsRangeSubset() { + final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); + final IpRange r2 = new IpRange(new IpPrefix(IPV6_ADDR, 39)); + + assertTrue(r1.overlapsRange(r2)); + assertTrue(r2.overlapsRange(r1)); + assertNotEquals(r1, r2); + } + + @Test + public void testOverlapsRangeDisjoint() { + final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 32)); + final IpRange r2 = new IpRange(new IpPrefix(address("2001:db9::"), 32)); + + assertFalse(r1.overlapsRange(r2)); + assertFalse(r2.overlapsRange(r1)); + assertNotEquals(r1, r2); + } + + @Test + public void testOverlapsRangePartialOverlapLow() { + final IpRange r1 = new IpRange(new IpPrefix(address("2001:db9::"), 32)); + final IpRange r2 = new IpRange(address("2001:db8::"), address("2001:db9::1")); + + assertTrue(r1.overlapsRange(r2)); + assertTrue(r2.overlapsRange(r1)); + assertNotEquals(r1, r2); + } + + @Test + public void testOverlapsRangePartialOverlapHigh() { + final IpRange r1 = new IpRange(new IpPrefix(address("2001:db7::"), 32)); + final IpRange r2 = new IpRange(address("2001:db7::ffff"), address("2001:db8::")); + + assertTrue(r1.overlapsRange(r2)); + assertTrue(r2.overlapsRange(r1)); + assertNotEquals(r1, r2); + } + + @Test + public void testIpRangeToPrefixesIpv4FullRange() throws Exception { + final IpRange range = new IpRange(address("0.0.0.0"), address("255.255.255.255")); + final List prefixes = new ArrayList<>(); + prefixes.add(new IpPrefix("0.0.0.0/0")); + + assertEquals(prefixes, range.asIpPrefixes()); + } + + @Test + public void testIpRangeToPrefixesIpv4() throws Exception { + final IpRange range = new IpRange(IPV4_ADDR, IPV4_RANGE_END); + final List prefixes = new ArrayList<>(); + prefixes.add(new IpPrefix("192.0.2.128/25")); + prefixes.add(new IpPrefix("192.0.2.64/26")); + prefixes.add(new IpPrefix("192.0.2.32/27")); + prefixes.add(new IpPrefix("192.0.2.16/28")); + prefixes.add(new IpPrefix("192.0.2.8/29")); + prefixes.add(new IpPrefix("192.0.2.4/30")); + prefixes.add(new IpPrefix("192.0.3.0/31")); + + assertEquals(prefixes, range.asIpPrefixes()); + } + + @Test + public void testIpRangeToPrefixesIpv6FullRange() throws Exception { + final IpRange range = + new IpRange(address("::"), address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); + final List prefixes = new ArrayList<>(); + prefixes.add(new IpPrefix("::/0")); + + assertEquals(prefixes, range.asIpPrefixes()); + } + + @Test + public void testIpRangeToPrefixesIpv6() throws Exception { + final IpRange range = new IpRange(IPV6_ADDR, IPV6_RANGE_END); + final List prefixes = new ArrayList<>(); + prefixes.add(new IpPrefix("2001:db8::/32")); + prefixes.add(new IpPrefix("2001:db9::/40")); + prefixes.add(new IpPrefix("2001:db9:100::/45")); + prefixes.add(new IpPrefix("2001:db9:108::/46")); + prefixes.add(new IpPrefix("2001:db9:10c::/47")); + prefixes.add(new IpPrefix("2001:db9:10e::/48")); + prefixes.add(new IpPrefix("2001:db9:10f::/128")); + + assertEquals(prefixes, range.asIpPrefixes()); + } +} From 14a2bbf857fcadc9c809914a6e0d018bd6a231b0 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 2 Mar 2020 19:24:15 +0900 Subject: [PATCH 028/777] Make NetworkFactory a single-use object. Currently, when bluetooth tethering is disabled, the bluetooth process crashes because unregister() calls setScoreFilter() and immediately nulls out mProvider. This crashes as soon as the message posted by setScoreFilter() dereferences mProvider from the handler thread. This sort of teardown problem is very difficult to fix given NetworkFactory's threading model where some code runs on the handler thread and some code runs on whatever thread calls it. Instead of complicating the code to do this, simply make it impossible to call register() after having called unregister(). The only factory that does so today is bluetooth tethering, and that can be trivially modified to create and register a new factory instead. This CL renames the unregister() method to terminate() in order to make it clear that the object cannot be reused, and also to ensure that no other code in the tree is unexpectedly calling unregister(). Bug: 148635501 Test: atest FrameworksNetTests Change-Id: Icf4c7a957e46e4ba017c0a5984e5c42a75b36ecd --- .../android/net/NetworkFactory.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java index 47054f504a..9bcc86378a 100644 --- a/staticlibs/src_servicescommon/android/net/NetworkFactory.java +++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java @@ -117,10 +117,10 @@ public class NetworkFactory extends Handler { mCapabilityFilter = filter; } + /* Registers this NetworkFactory with the system. May only be called once per factory. */ public void register() { if (mProvider != null) { - Log.e(LOG_TAG, "Ignoring attempt to register already-registered NetworkFactory"); - return; + throw new IllegalStateException("A NetworkFactory must only be registered once"); } if (DBG) log("Registering NetworkFactory"); @@ -142,16 +142,19 @@ public class NetworkFactory extends Handler { Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); } - public void unregister() { + /** Unregisters this NetworkFactory. After this call, the object can no longer be used. */ + public void terminate() { if (mProvider == null) { - Log.e(LOG_TAG, "Ignoring attempt to unregister unregistered NetworkFactory"); - return; + throw new IllegalStateException("This NetworkFactory was never registered"); } if (DBG) log("Unregistering NetworkFactory"); ((ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) .unregisterNetworkProvider(mProvider); - mProvider = null; + + // Remove all pending messages, since this object cannot be reused. Any message currently + // being processed will continue to run. + removeCallbacksAndMessages(null); } @Override From 0e9e646d5b2c5988bef24a7d05e1fb6b435c3000 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 2 Mar 2020 19:24:15 +0900 Subject: [PATCH 029/777] Make NetworkFactory a single-use object. Currently, when bluetooth tethering is disabled, the bluetooth process crashes because unregister() calls setScoreFilter() and immediately nulls out mProvider. This crashes as soon as the message posted by setScoreFilter() dereferences mProvider from the handler thread. This sort of teardown problem is very difficult to fix given NetworkFactory's threading model where some code runs on the handler thread and some code runs on whatever thread calls it. Instead of complicating the code to do this, simply make it impossible to call register() after having called unregister(). The only factory that does so today is bluetooth tethering, and that can be trivially modified to create and register a new factory instead. This CL renames the unregister() method to terminate() in order to make it clear that the object cannot be reused, and also to ensure that no other code in the tree is unexpectedly calling unregister(). Bug: 148635501 Test: atest FrameworksNetTests Change-Id: Icf4c7a957e46e4ba017c0a5984e5c42a75b36ecd Merged-In: Icf4c7a957e46e4ba017c0a5984e5c42a75b36ecd --- .../android/net/NetworkFactory.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java index 47054f504a..9bcc86378a 100644 --- a/staticlibs/src_servicescommon/android/net/NetworkFactory.java +++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java @@ -117,10 +117,10 @@ public class NetworkFactory extends Handler { mCapabilityFilter = filter; } + /* Registers this NetworkFactory with the system. May only be called once per factory. */ public void register() { if (mProvider != null) { - Log.e(LOG_TAG, "Ignoring attempt to register already-registered NetworkFactory"); - return; + throw new IllegalStateException("A NetworkFactory must only be registered once"); } if (DBG) log("Registering NetworkFactory"); @@ -142,16 +142,19 @@ public class NetworkFactory extends Handler { Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); } - public void unregister() { + /** Unregisters this NetworkFactory. After this call, the object can no longer be used. */ + public void terminate() { if (mProvider == null) { - Log.e(LOG_TAG, "Ignoring attempt to unregister unregistered NetworkFactory"); - return; + throw new IllegalStateException("This NetworkFactory was never registered"); } if (DBG) log("Unregistering NetworkFactory"); ((ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) .unregisterNetworkProvider(mProvider); - mProvider = null; + + // Remove all pending messages, since this object cannot be reused. Any message currently + // being processed will continue to run. + removeCallbacksAndMessages(null); } @Override From d65368d53deb1f23416882538ad10f5a3822f1d6 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 25 Mar 2020 02:08:38 +0900 Subject: [PATCH 030/777] Update NetworkProvider calls for API council request Bug: 152238712 Test: FrameworksNetTests Change-Id: Iec50554a9548a5cbdcf556a1a0536d9a94559793 --- staticlibs/src_servicescommon/android/net/NetworkFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java index 9bcc86378a..252c2ea775 100644 --- a/staticlibs/src_servicescommon/android/net/NetworkFactory.java +++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java @@ -132,7 +132,7 @@ public class NetworkFactory extends Handler { } @Override - public void onRequestWithdrawn(@NonNull NetworkRequest request) { + public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { handleRemoveRequest(request); } }; From b3da68581ea34e7db2553e30e8241334dd4b6dff Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 27 Mar 2020 15:02:54 +0900 Subject: [PATCH 031/777] Address further API council comments. Test: FrameworksNetTests NetworkStackTests Bug: 152238712 Change-Id: I0b2526b58f0437f499ca1bbbc55fbf875003e4df --- staticlibs/src_servicescommon/android/net/NetworkFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java index 252c2ea775..06399f8525 100644 --- a/staticlibs/src_servicescommon/android/net/NetworkFactory.java +++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java @@ -319,7 +319,7 @@ public class NetworkFactory extends Handler { && (n.score < mScore || n.providerId == mProvider.getProviderId()) // If this factory can't satisfy the capability needs of this request, then it // should not be tracked. - && n.request.satisfiedBy(mCapabilityFilter) + && n.request.canBeSatisfiedBy(mCapabilityFilter) // Finally if the concrete implementation of the factory rejects the request, then // don't track it. && acceptRequest(n.request, n.score); @@ -335,7 +335,7 @@ public class NetworkFactory extends Handler { // - This factory can't satisfy the capability needs of the request // - The concrete implementation of the factory rejects the request && ((n.score > mScore && n.providerId != mProvider.getProviderId()) - || !n.request.satisfiedBy(mCapabilityFilter) + || !n.request.canBeSatisfiedBy(mCapabilityFilter) || !acceptRequest(n.request, n.score)); } From 6edf7b01e5aa7e7a4f62b1178dcf0dc89855e059 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 25 Mar 2020 02:08:38 +0900 Subject: [PATCH 032/777] Update NetworkProvider calls for API council request Bug: 152238712 Test: FrameworksNetTests Copy from ag/10825365 Change-Id: Iec50554a9548a5cbdcf556a1a0536d9a94559793 Merged-In: Iec50554a9548a5cbdcf556a1a0536d9a94559793 --- staticlibs/src_servicescommon/android/net/NetworkFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java index 9bcc86378a..252c2ea775 100644 --- a/staticlibs/src_servicescommon/android/net/NetworkFactory.java +++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java @@ -132,7 +132,7 @@ public class NetworkFactory extends Handler { } @Override - public void onRequestWithdrawn(@NonNull NetworkRequest request) { + public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { handleRemoveRequest(request); } }; From be19bb240a904e4815afe478198b0e0e88944e11 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 27 Mar 2020 15:02:54 +0900 Subject: [PATCH 033/777] Address further API council comments. Test: FrameworksNetTests NetworkStackTests Bug: 152238712 Copy from ag/10856890 Change-Id: I0b2526b58f0437f499ca1bbbc55fbf875003e4df Merged-In: I0b2526b58f0437f499ca1bbbc55fbf875003e4df --- staticlibs/src_servicescommon/android/net/NetworkFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java index 252c2ea775..06399f8525 100644 --- a/staticlibs/src_servicescommon/android/net/NetworkFactory.java +++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java @@ -319,7 +319,7 @@ public class NetworkFactory extends Handler { && (n.score < mScore || n.providerId == mProvider.getProviderId()) // If this factory can't satisfy the capability needs of this request, then it // should not be tracked. - && n.request.satisfiedBy(mCapabilityFilter) + && n.request.canBeSatisfiedBy(mCapabilityFilter) // Finally if the concrete implementation of the factory rejects the request, then // don't track it. && acceptRequest(n.request, n.score); @@ -335,7 +335,7 @@ public class NetworkFactory extends Handler { // - This factory can't satisfy the capability needs of the request // - The concrete implementation of the factory rejects the request && ((n.score > mScore && n.providerId != mProvider.getProviderId()) - || !n.request.satisfiedBy(mCapabilityFilter) + || !n.request.canBeSatisfiedBy(mCapabilityFilter) || !acceptRequest(n.request, n.score)); } From 0607dd9a16aebc9f268cdf8a0f9f5b63ed1b684f Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Fri, 27 Mar 2020 00:30:41 +0100 Subject: [PATCH 034/777] src_frameworkcommon: Fix filegroup base path The filegroups here were set up without an explicit path. As a result, the files within were incorrectly considered part of the "src_frameworkcommon.android.net.utils" package by droidstubs' filter_packages filter (and thus not fed into droidstubs). This CL fixes the filegroups by adding an explicit path to where the package tree starts for each of them, such that the path-based package filter in droidstubs can work correctly. Also @hide the classes which otherwise would now be considered exposed API by droidstubs. Bug: 151160048 Test: make checkapi Change-Id: I969fc9846294a42554233cffda725797ee0185f4 --- staticlibs/Android.bp | 7 +++++++ .../src_frameworkcommon/android/net/util/IpRange.java | 2 ++ .../android/net/util/LinkPropertiesUtils.java | 1 + .../android/net/util/MacAddressUtils.java | 1 + .../src_frameworkcommon/android/net/util/NetUtils.java | 1 + 5 files changed, 12 insertions(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 8f845bc2e8..d29ba3657f 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -23,9 +23,14 @@ // rules file. Otherwise, it will end up on the boot classpath and other modules will not be able // to provide their own copy. +// Note: all filegroups here must have the right path attribute because otherwise, if they are +// included in the bootclasspath, they could incorrectly be included in the SDK documentation even +// though they are not in the current.txt files. + filegroup { name: "net-utils-framework-common-srcs", srcs: ["src_frameworkcommon/**/*.java"], + path: "src_frameworkcommon", visibility: ["//frameworks/base"], } @@ -74,6 +79,7 @@ filegroup { // Any class here *must* have a corresponding jarjar rule in the telephony build rules. "src_servicescommon/android/net/NetworkFactory.java", ], + path: "src_servicescommon", visibility: [ "//frameworks/opt/telephony", ], @@ -88,6 +94,7 @@ filegroup { "src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java", "src_frameworkcommon/android/net/util/MacAddressUtils.java", ], + path: "src_frameworkcommon", visibility: [ "//frameworks/base", ], diff --git a/staticlibs/src_frameworkcommon/android/net/util/IpRange.java b/staticlibs/src_frameworkcommon/android/net/util/IpRange.java index 04e92773bb..099770bca4 100644 --- a/staticlibs/src_frameworkcommon/android/net/util/IpRange.java +++ b/staticlibs/src_frameworkcommon/android/net/util/IpRange.java @@ -39,6 +39,8 @@ import java.util.Queue; * *

Conversion to prefixes are deterministic, and will always return the same set of {@link * IpPrefix}(es). Ordering of IpPrefix instances is not guaranteed. + * + * @hide */ public final class IpRange { private static final int SIGNUM_POSITIVE = 1; diff --git a/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java b/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java index 812382694a..282fa10d2b 100644 --- a/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java +++ b/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java @@ -33,6 +33,7 @@ import java.util.function.Function; /** * Collection of link properties utilities. + * @hide */ public final class LinkPropertiesUtils { diff --git a/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java b/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java index 3ad452ba30..969d1270be 100644 --- a/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java +++ b/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java @@ -27,6 +27,7 @@ import java.util.Random; /** * Collection of MAC address utilities. + * @hide */ public final class MacAddressUtils { diff --git a/staticlibs/src_frameworkcommon/android/net/util/NetUtils.java b/staticlibs/src_frameworkcommon/android/net/util/NetUtils.java index e0065904fb..302119ea11 100644 --- a/staticlibs/src_frameworkcommon/android/net/util/NetUtils.java +++ b/staticlibs/src_frameworkcommon/android/net/util/NetUtils.java @@ -27,6 +27,7 @@ import java.util.Collection; /** * Collection of network common utilities. + * @hide */ public final class NetUtils { From e8a0575ad79f1a44c7dbc78adc77172f64e293b6 Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Fri, 27 Mar 2020 00:30:41 +0100 Subject: [PATCH 035/777] src_frameworkcommon: Fix filegroup base path The filegroups here were set up without an explicit path. As a result, the files within were incorrectly considered part of the "src_frameworkcommon.android.net.utils" package by droidstubs' filter_packages filter (and thus not fed into droidstubs). This CL fixes the filegroups by adding an explicit path to where the package tree starts for each of them, such that the path-based package filter in droidstubs can work correctly. Also @hide the classes which otherwise would now be considered exposed API by droidstubs. Bug: 151160048 Test: make checkapi Change-Id: I969fc9846294a42554233cffda725797ee0185f4 --- staticlibs/Android.bp | 7 +++++++ .../src_frameworkcommon/android/net/util/IpRange.java | 2 ++ .../android/net/util/LinkPropertiesUtils.java | 1 + .../android/net/util/MacAddressUtils.java | 1 + .../src_frameworkcommon/android/net/util/NetUtils.java | 1 + 5 files changed, 12 insertions(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 8f845bc2e8..d29ba3657f 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -23,9 +23,14 @@ // rules file. Otherwise, it will end up on the boot classpath and other modules will not be able // to provide their own copy. +// Note: all filegroups here must have the right path attribute because otherwise, if they are +// included in the bootclasspath, they could incorrectly be included in the SDK documentation even +// though they are not in the current.txt files. + filegroup { name: "net-utils-framework-common-srcs", srcs: ["src_frameworkcommon/**/*.java"], + path: "src_frameworkcommon", visibility: ["//frameworks/base"], } @@ -74,6 +79,7 @@ filegroup { // Any class here *must* have a corresponding jarjar rule in the telephony build rules. "src_servicescommon/android/net/NetworkFactory.java", ], + path: "src_servicescommon", visibility: [ "//frameworks/opt/telephony", ], @@ -88,6 +94,7 @@ filegroup { "src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java", "src_frameworkcommon/android/net/util/MacAddressUtils.java", ], + path: "src_frameworkcommon", visibility: [ "//frameworks/base", ], diff --git a/staticlibs/src_frameworkcommon/android/net/util/IpRange.java b/staticlibs/src_frameworkcommon/android/net/util/IpRange.java index 04e92773bb..099770bca4 100644 --- a/staticlibs/src_frameworkcommon/android/net/util/IpRange.java +++ b/staticlibs/src_frameworkcommon/android/net/util/IpRange.java @@ -39,6 +39,8 @@ import java.util.Queue; * *

Conversion to prefixes are deterministic, and will always return the same set of {@link * IpPrefix}(es). Ordering of IpPrefix instances is not guaranteed. + * + * @hide */ public final class IpRange { private static final int SIGNUM_POSITIVE = 1; diff --git a/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java b/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java index 812382694a..282fa10d2b 100644 --- a/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java +++ b/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java @@ -33,6 +33,7 @@ import java.util.function.Function; /** * Collection of link properties utilities. + * @hide */ public final class LinkPropertiesUtils { diff --git a/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java b/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java index 3ad452ba30..969d1270be 100644 --- a/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java +++ b/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java @@ -27,6 +27,7 @@ import java.util.Random; /** * Collection of MAC address utilities. + * @hide */ public final class MacAddressUtils { diff --git a/staticlibs/src_frameworkcommon/android/net/util/NetUtils.java b/staticlibs/src_frameworkcommon/android/net/util/NetUtils.java index e0065904fb..302119ea11 100644 --- a/staticlibs/src_frameworkcommon/android/net/util/NetUtils.java +++ b/staticlibs/src_frameworkcommon/android/net/util/NetUtils.java @@ -27,6 +27,7 @@ import java.util.Collection; /** * Collection of network common utilities. + * @hide */ public final class NetUtils { From ba972ca71f751ef061493183988dca98e7185dab Mon Sep 17 00:00:00 2001 From: markchien Date: Tue, 21 Apr 2020 15:23:06 +0800 Subject: [PATCH 036/777] Make NetworkStaticLibTests as test lib Share the tests with TetheringCoverageTests because tethering module use net-utils-framework-common. Remove unused static library. Currently we do not implement any unit test for net-utils-services-common. "net-utils-services-common" can be back when we add new test for it. Bug: 148636687 Test: atest NetworkStaticLibTests atest TetheringCoverageTests Change-Id: I2f3a94b2ba50cd4d73303961bf1661a3091ab033 --- staticlibs/tests/unit/Android.bp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index fe363f5a28..52c5f82f61 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -2,20 +2,29 @@ // Build NetworkStaticLibTests package //######################################################################## -android_test { - name: "NetworkStaticLibTests", - certificate: "platform", +android_library { + name: "NetworkStaticLibTestsLib", srcs: ["src/**/*.java","src/**/*.kt"], jarjar_rules: "jarjar-rules.txt", - test_suites: ["device-tests"], static_libs: [ - "androidx.test.rules", "net-utils-framework-common", - "net-utils-services-common", + "androidx.test.rules", ], libs: [ "android.test.runner", "android.test.base", ], + visibility: [ + "//frameworks/base/packages/Tethering/tests/integration", + ] +} + +android_test { + name: "NetworkStaticLibTests", + certificate: "platform", + static_libs: [ + "NetworkStaticLibTestsLib", + ], + test_suites: ["device-tests"], } From 5837655b2e59021f10e034ca9a21f5f85279f94d Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 22 Apr 2020 03:46:18 +0000 Subject: [PATCH 037/777] Make NetworkStaticLibTests as test lib Share the tests with TetheringCoverageTests because tethering module use net-utils-framework-common. Remove unused static library. Currently we do not implement any unit test for net-utils-services-common. "net-utils-services-common" can be back when we add new test for it. Bug: 148636687 Test: atest NetworkStaticLibTests atest TetheringCoverageTests Merged-In: I2f3a94b2ba50cd4d73303961bf1661a3091ab033 Change-Id: I2f3a94b2ba50cd4d73303961bf1661a3091ab033 --- staticlibs/tests/unit/Android.bp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index fe363f5a28..52c5f82f61 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -2,20 +2,29 @@ // Build NetworkStaticLibTests package //######################################################################## -android_test { - name: "NetworkStaticLibTests", - certificate: "platform", +android_library { + name: "NetworkStaticLibTestsLib", srcs: ["src/**/*.java","src/**/*.kt"], jarjar_rules: "jarjar-rules.txt", - test_suites: ["device-tests"], static_libs: [ - "androidx.test.rules", "net-utils-framework-common", - "net-utils-services-common", + "androidx.test.rules", ], libs: [ "android.test.runner", "android.test.base", ], + visibility: [ + "//frameworks/base/packages/Tethering/tests/integration", + ] +} + +android_test { + name: "NetworkStaticLibTests", + certificate: "platform", + static_libs: [ + "NetworkStaticLibTestsLib", + ], + test_suites: ["device-tests"], } From 40ba249403b2489ffbbacd98267ff2d410f387da Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 15 May 2020 15:44:41 +0900 Subject: [PATCH 038/777] Opportunistic cleanup of NetworkFactory. This addresses warnings from IntelliJ and removes a method that was marked for removal. Test: FrameworksWifiTests FrameworksNetTests FrameworksTelephonyTests Bug: none Change-Id: Ic3c84cc1e12e06a8f007464fdd3ec11b989bd3aa --- .../android/net/NetworkFactory.java | 40 ++++--------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java index 06399f8525..55edd293de 100644 --- a/staticlibs/src_servicescommon/android/net/NetworkFactory.java +++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java @@ -21,14 +21,12 @@ import android.content.Context; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.os.Messenger; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.Map; @@ -96,7 +94,6 @@ public class NetworkFactory extends Handler { private static final int CMD_SET_FILTER = 4; private final Context mContext; - private final ArrayList mPreConnectedQueue = new ArrayList(); private final String LOG_TAG; private final Map mNetworkRequests = @@ -106,7 +103,6 @@ public class NetworkFactory extends Handler { private NetworkCapabilities mCapabilityFilter; private int mRefCount = 0; - private Messenger mMessenger = null; private NetworkProvider mProvider = null; public NetworkFactory(Looper looper, Context context, String logTag, @@ -128,7 +124,7 @@ public class NetworkFactory extends Handler { @Override public void onNetworkRequested(@NonNull NetworkRequest request, int score, int servingProviderId) { - handleAddRequest((NetworkRequest) request, score, servingProviderId); + handleAddRequest(request, score, servingProviderId); } @Override @@ -137,7 +133,6 @@ public class NetworkFactory extends Handler { } }; - mMessenger = new Messenger(this); ((ConnectivityManager) mContext.getSystemService( Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); } @@ -179,7 +174,7 @@ public class NetworkFactory extends Handler { } } - private class NetworkRequestInfo { + private static class NetworkRequestInfo { public final NetworkRequest request; public int score; public boolean requested; // do we have a request outstanding, limited by score @@ -198,22 +193,6 @@ public class NetworkFactory extends Handler { } } - /** - * Add a NetworkRequest that the bearer may want to attempt to satisfy. - * @see #CMD_REQUEST_NETWORK - * - * @param request the request to handle. - * @param score the score of the NetworkAgent currently satisfying this request. - */ - // TODO : remove this method. It is a stopgap measure to help sheperding a number - // of dependent changes that would conflict throughout the automerger graph. Having this - // temporarily helps with the process of going through with all these dependent changes across - // the entire tree. - @VisibleForTesting - protected void handleAddRequest(NetworkRequest request, int score) { - handleAddRequest(request, score, NetworkProvider.ID_NONE); - } - /** * Add a NetworkRequest that the bearer may want to attempt to satisfy. * @see #CMD_REQUEST_NETWORK @@ -350,9 +329,7 @@ public class NetworkFactory extends Handler { * outstanding requests. Can be called from a factory implementation. */ protected void reevaluateAllRequests() { - post(() -> { - evalRequests(); - }); + post(this::evalRequests); } /** @@ -424,11 +401,10 @@ public class NetworkFactory extends Handler { @Override public String toString() { - StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - providerId=") - .append(mProvider.getProviderId()).append(", ScoreFilter=") - .append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests=") - .append(mNetworkRequests.size()).append(", refCount=").append(mRefCount) - .append("}"); - return sb.toString(); + return "{" + LOG_TAG + " - providerId=" + + mProvider.getProviderId() + ", ScoreFilter=" + + mScore + ", Filter=" + mCapabilityFilter + ", requests=" + + mNetworkRequests.size() + ", refCount=" + mRefCount + + "}"; } } From 420e81760af93de7de0f3f7615fd896692895ee7 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 15 May 2020 09:01:24 +0000 Subject: [PATCH 039/777] Opportunistic cleanup of NetworkFactory. This addresses warnings from IntelliJ and removes a method that was marked for removal. Test: FrameworksWifiTests FrameworksNetTests FrameworksTelephonyTests Bug: 150570873 Original-Change: https://android-review.googlesource.com/1312594 Merged-In: Ic3c84cc1e12e06a8f007464fdd3ec11b989bd3aa Change-Id: Ic3c84cc1e12e06a8f007464fdd3ec11b989bd3aa --- .../android/net/NetworkFactory.java | 40 ++++--------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java index 06399f8525..55edd293de 100644 --- a/staticlibs/src_servicescommon/android/net/NetworkFactory.java +++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java @@ -21,14 +21,12 @@ import android.content.Context; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.os.Messenger; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.Map; @@ -96,7 +94,6 @@ public class NetworkFactory extends Handler { private static final int CMD_SET_FILTER = 4; private final Context mContext; - private final ArrayList mPreConnectedQueue = new ArrayList(); private final String LOG_TAG; private final Map mNetworkRequests = @@ -106,7 +103,6 @@ public class NetworkFactory extends Handler { private NetworkCapabilities mCapabilityFilter; private int mRefCount = 0; - private Messenger mMessenger = null; private NetworkProvider mProvider = null; public NetworkFactory(Looper looper, Context context, String logTag, @@ -128,7 +124,7 @@ public class NetworkFactory extends Handler { @Override public void onNetworkRequested(@NonNull NetworkRequest request, int score, int servingProviderId) { - handleAddRequest((NetworkRequest) request, score, servingProviderId); + handleAddRequest(request, score, servingProviderId); } @Override @@ -137,7 +133,6 @@ public class NetworkFactory extends Handler { } }; - mMessenger = new Messenger(this); ((ConnectivityManager) mContext.getSystemService( Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); } @@ -179,7 +174,7 @@ public class NetworkFactory extends Handler { } } - private class NetworkRequestInfo { + private static class NetworkRequestInfo { public final NetworkRequest request; public int score; public boolean requested; // do we have a request outstanding, limited by score @@ -198,22 +193,6 @@ public class NetworkFactory extends Handler { } } - /** - * Add a NetworkRequest that the bearer may want to attempt to satisfy. - * @see #CMD_REQUEST_NETWORK - * - * @param request the request to handle. - * @param score the score of the NetworkAgent currently satisfying this request. - */ - // TODO : remove this method. It is a stopgap measure to help sheperding a number - // of dependent changes that would conflict throughout the automerger graph. Having this - // temporarily helps with the process of going through with all these dependent changes across - // the entire tree. - @VisibleForTesting - protected void handleAddRequest(NetworkRequest request, int score) { - handleAddRequest(request, score, NetworkProvider.ID_NONE); - } - /** * Add a NetworkRequest that the bearer may want to attempt to satisfy. * @see #CMD_REQUEST_NETWORK @@ -350,9 +329,7 @@ public class NetworkFactory extends Handler { * outstanding requests. Can be called from a factory implementation. */ protected void reevaluateAllRequests() { - post(() -> { - evalRequests(); - }); + post(this::evalRequests); } /** @@ -424,11 +401,10 @@ public class NetworkFactory extends Handler { @Override public String toString() { - StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - providerId=") - .append(mProvider.getProviderId()).append(", ScoreFilter=") - .append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests=") - .append(mNetworkRequests.size()).append(", refCount=").append(mRefCount) - .append("}"); - return sb.toString(); + return "{" + LOG_TAG + " - providerId=" + + mProvider.getProviderId() + ", ScoreFilter=" + + mScore + ", Filter=" + mCapabilityFilter + ", requests=" + + mNetworkRequests.size() + ", refCount=" + mRefCount + + "}"; } } From 9e77f761fd00a5b69c5024133d7b9bf877fd63b2 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 8 Jun 2020 15:55:25 +0900 Subject: [PATCH 040/777] Move Inet[4]AddressUtils to libs/net The classes should not be picked up from frameworks/base, as they are part of several mainline modules. Bug: 151052811 Test: m; manual: flashed, wifi and telephony working Test: atest NetworkStackCoverageTests Change-Id: I2b3dcf2e238be047147232769602df56894dc6b1 --- staticlibs/Android.bp | 1 + .../net/module/util/Inet4AddressUtils.java | 166 ++++++++++++++ .../net/module/util/InetAddressUtils.java | 58 +++++ staticlibs/tests/unit/Android.bp | 2 + .../module/util/Inet4AddressUtilsTest.java | 210 ++++++++++++++++++ 5 files changed, 437 insertions(+) create mode 100644 staticlibs/src_frameworkcommon/com/android/net/module/util/Inet4AddressUtils.java create mode 100644 staticlibs/src_frameworkcommon/com/android/net/module/util/InetAddressUtils.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/Inet4AddressUtilsTest.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index d29ba3657f..d93579b15d 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -93,6 +93,7 @@ filegroup { srcs: [ "src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java", "src_frameworkcommon/android/net/util/MacAddressUtils.java", + "src_frameworkcommon/com/android/net/module/util/**/*.java", ], path: "src_frameworkcommon", visibility: [ diff --git a/staticlibs/src_frameworkcommon/com/android/net/module/util/Inet4AddressUtils.java b/staticlibs/src_frameworkcommon/com/android/net/module/util/Inet4AddressUtils.java new file mode 100644 index 0000000000..a1d34a0f3f --- /dev/null +++ b/staticlibs/src_frameworkcommon/com/android/net/module/util/Inet4AddressUtils.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * Collection of utilities to work with IPv4 addresses. + * @hide + */ +public class Inet4AddressUtils { + + /** + * Convert a IPv4 address from an integer to an InetAddress (0x04030201 -> 1.2.3.4) + * + *

This method uses the higher-order int bytes as the lower-order IPv4 address bytes, + * which is an unusual convention. Consider {@link #intToInet4AddressHTH(int)} instead. + * @param hostAddress an int coding for an IPv4 address, where higher-order int byte is + * lower-order IPv4 address byte + */ + public static Inet4Address intToInet4AddressHTL(int hostAddress) { + return intToInet4AddressHTH(Integer.reverseBytes(hostAddress)); + } + + /** + * Convert a IPv4 address from an integer to an InetAddress (0x01020304 -> 1.2.3.4) + * @param hostAddress an int coding for an IPv4 address + */ + public static Inet4Address intToInet4AddressHTH(int hostAddress) { + byte[] addressBytes = { (byte) (0xff & (hostAddress >> 24)), + (byte) (0xff & (hostAddress >> 16)), + (byte) (0xff & (hostAddress >> 8)), + (byte) (0xff & hostAddress) }; + + try { + return (Inet4Address) InetAddress.getByAddress(addressBytes); + } catch (UnknownHostException e) { + throw new AssertionError(); + } + } + + /** + * Convert an IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x01020304) + * + *

This conversion can help order IP addresses: considering the ordering + * 192.0.2.1 < 192.0.2.2 < ..., resulting ints will follow that ordering if read as unsigned + * integers with {@link Integer#toUnsignedLong}. + * @param inetAddr is an InetAddress corresponding to the IPv4 address + * @return the IP address as integer + */ + public static int inet4AddressToIntHTH(Inet4Address inetAddr) + throws IllegalArgumentException { + byte [] addr = inetAddr.getAddress(); + return ((addr[0] & 0xff) << 24) | ((addr[1] & 0xff) << 16) + | ((addr[2] & 0xff) << 8) | (addr[3] & 0xff); + } + + /** + * Convert a IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x04030201) + * + *

This method stores the higher-order IPv4 address bytes in the lower-order int bytes, + * which is an unusual convention. Consider {@link #inet4AddressToIntHTH(Inet4Address)} instead. + * @param inetAddr is an InetAddress corresponding to the IPv4 address + * @return the IP address as integer + */ + public static int inet4AddressToIntHTL(Inet4Address inetAddr) { + return Integer.reverseBytes(inet4AddressToIntHTH(inetAddr)); + } + + /** + * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0xffff8000) + * @return the IPv4 netmask as an integer + */ + public static int prefixLengthToV4NetmaskIntHTH(int prefixLength) + throws IllegalArgumentException { + if (prefixLength < 0 || prefixLength > 32) { + throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)"); + } + // (int)a << b is equivalent to a << (b & 0x1f): can't shift by 32 (-1 << 32 == -1) + return prefixLength == 0 ? 0 : 0xffffffff << (32 - prefixLength); + } + + /** + * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0x0080ffff). + * + *

This method stores the higher-order IPv4 address bytes in the lower-order int bytes, + * which is an unusual convention. Consider {@link #prefixLengthToV4NetmaskIntHTH(int)} instead. + * @return the IPv4 netmask as an integer + */ + public static int prefixLengthToV4NetmaskIntHTL(int prefixLength) + throws IllegalArgumentException { + return Integer.reverseBytes(prefixLengthToV4NetmaskIntHTH(prefixLength)); + } + + /** + * Convert an IPv4 netmask to a prefix length, checking that the netmask is contiguous. + * @param netmask as a {@code Inet4Address}. + * @return the network prefix length + * @throws IllegalArgumentException the specified netmask was not contiguous. + * @hide + */ + public static int netmaskToPrefixLength(Inet4Address netmask) { + // inetAddressToInt returns an int in *network* byte order. + int i = inet4AddressToIntHTH(netmask); + int prefixLength = Integer.bitCount(i); + int trailingZeros = Integer.numberOfTrailingZeros(i); + if (trailingZeros != 32 - prefixLength) { + throw new IllegalArgumentException("Non-contiguous netmask: " + Integer.toHexString(i)); + } + return prefixLength; + } + + /** + * Returns the implicit netmask of an IPv4 address, as was the custom before 1993. + */ + public static int getImplicitNetmask(Inet4Address address) { + int firstByte = address.getAddress()[0] & 0xff; // Convert to an unsigned value. + if (firstByte < 128) { + return 8; + } else if (firstByte < 192) { + return 16; + } else if (firstByte < 224) { + return 24; + } else { + return 32; // Will likely not end well for other reasons. + } + } + + /** + * Get the broadcast address for a given prefix. + * + *

For example 192.168.0.1/24 -> 192.168.0.255 + */ + public static Inet4Address getBroadcastAddress(Inet4Address addr, int prefixLength) + throws IllegalArgumentException { + final int intBroadcastAddr = inet4AddressToIntHTH(addr) + | ~prefixLengthToV4NetmaskIntHTH(prefixLength); + return intToInet4AddressHTH(intBroadcastAddr); + } + + /** + * Get a prefix mask as Inet4Address for a given prefix length. + * + *

For example 20 -> 255.255.240.0 + */ + public static Inet4Address getPrefixMaskAsInet4Address(int prefixLength) + throws IllegalArgumentException { + return intToInet4AddressHTH(prefixLengthToV4NetmaskIntHTH(prefixLength)); + } +} diff --git a/staticlibs/src_frameworkcommon/com/android/net/module/util/InetAddressUtils.java b/staticlibs/src_frameworkcommon/com/android/net/module/util/InetAddressUtils.java new file mode 100644 index 0000000000..6300328e8d --- /dev/null +++ b/staticlibs/src_frameworkcommon/com/android/net/module/util/InetAddressUtils.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import android.os.Parcel; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * Collection of utilities to interact with {@link InetAddress} + * @hide + */ +public class InetAddressUtils { + + /** + * Writes an InetAddress to a parcel. The address may be null. This is likely faster than + * calling writeSerializable. + * @hide + */ + public static void parcelInetAddress(Parcel parcel, InetAddress address, int flags) { + byte[] addressArray = (address != null) ? address.getAddress() : null; + parcel.writeByteArray(addressArray); + } + + /** + * Reads an InetAddress from a parcel. Returns null if the address that was written was null + * or if the data is invalid. + * @hide + */ + public static InetAddress unparcelInetAddress(Parcel in) { + byte[] addressArray = in.createByteArray(); + if (addressArray == null) { + return null; + } + try { + return InetAddress.getByAddress(addressArray); + } catch (UnknownHostException e) { + return null; + } + } + + private InetAddressUtils() {} +} diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index 52c5f82f61..cb15277324 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -5,6 +5,7 @@ android_library { name: "NetworkStaticLibTestsLib", srcs: ["src/**/*.java","src/**/*.kt"], + min_sdk_version: "29", jarjar_rules: "jarjar-rules.txt", static_libs: [ "net-utils-framework-common", @@ -16,6 +17,7 @@ android_library { ], visibility: [ "//frameworks/base/packages/Tethering/tests/integration", + "//packages/modules/NetworkStack/tests/integration", ] } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/Inet4AddressUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/Inet4AddressUtilsTest.java new file mode 100644 index 0000000000..5d5ed911f2 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/Inet4AddressUtilsTest.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import static com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress; +import static com.android.net.module.util.Inet4AddressUtils.getImplicitNetmask; +import static com.android.net.module.util.Inet4AddressUtils.getPrefixMaskAsInet4Address; +import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH; +import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTL; +import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; +import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTL; +import static com.android.net.module.util.Inet4AddressUtils.netmaskToPrefixLength; +import static com.android.net.module.util.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH; +import static com.android.net.module.util.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL; + +import static junit.framework.Assert.assertEquals; + +import static org.junit.Assert.fail; + +import android.net.InetAddresses; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class Inet4AddressUtilsTest { + + @Test + public void testInet4AddressToIntHTL() { + assertEquals(0, inet4AddressToIntHTL(ipv4Address("0.0.0.0"))); + assertEquals(0x000080ff, inet4AddressToIntHTL(ipv4Address("255.128.0.0"))); + assertEquals(0x0080ff0a, inet4AddressToIntHTL(ipv4Address("10.255.128.0"))); + assertEquals(0x00feff0a, inet4AddressToIntHTL(ipv4Address("10.255.254.0"))); + assertEquals(0xfeffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.254"))); + assertEquals(0xffffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.255"))); + } + + @Test + public void testIntToInet4AddressHTL() { + assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTL(0)); + assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTL(0x000080ff)); + assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTL(0x0080ff0a)); + assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTL(0x00feff0a)); + assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTL(0xfeffa8c0)); + assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTL(0xffffa8c0)); + } + + @Test + public void testInet4AddressToIntHTH() { + assertEquals(0, inet4AddressToIntHTH(ipv4Address("0.0.0.0"))); + assertEquals(0xff800000, inet4AddressToIntHTH(ipv4Address("255.128.0.0"))); + assertEquals(0x0aff8000, inet4AddressToIntHTH(ipv4Address("10.255.128.0"))); + assertEquals(0x0afffe00, inet4AddressToIntHTH(ipv4Address("10.255.254.0"))); + assertEquals(0xc0a8fffe, inet4AddressToIntHTH(ipv4Address("192.168.255.254"))); + assertEquals(0xc0a8ffff, inet4AddressToIntHTH(ipv4Address("192.168.255.255"))); + } + + @Test + public void testIntToInet4AddressHTH() { + assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTH(0)); + assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTH(0xff800000)); + assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTH(0x0aff8000)); + assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTH(0x0afffe00)); + assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTH(0xc0a8fffe)); + assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTH(0xc0a8ffff)); + } + + + @Test + public void testPrefixLengthToV4NetmaskIntHTL() { + assertEquals(0, prefixLengthToV4NetmaskIntHTL(0)); + assertEquals(0x000080ff /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTL(9)); + assertEquals(0x0080ffff /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTL(17)); + assertEquals(0x00feffff /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTL(23)); + assertEquals(0xfeffffff /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTL(31)); + assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTL(32)); + } + + @Test + public void testPrefixLengthToV4NetmaskIntHTH() { + assertEquals(0, prefixLengthToV4NetmaskIntHTH(0)); + assertEquals(0xff800000 /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTH(9)); + assertEquals(0xffff8000 /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTH(17)); + assertEquals(0xfffffe00 /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTH(23)); + assertEquals(0xfffffffe /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTH(31)); + assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTH(32)); + } + + @Test(expected = IllegalArgumentException.class) + public void testPrefixLengthToV4NetmaskIntHTH_NegativeLength() { + prefixLengthToV4NetmaskIntHTH(-1); + } + + @Test(expected = IllegalArgumentException.class) + public void testPrefixLengthToV4NetmaskIntHTH_LengthTooLarge() { + prefixLengthToV4NetmaskIntHTH(33); + } + + private void checkAddressMasking(String expectedAddr, String addr, int prefixLength) { + final int prefix = prefixLengthToV4NetmaskIntHTH(prefixLength); + final int addrInt = inet4AddressToIntHTH(ipv4Address(addr)); + assertEquals(ipv4Address(expectedAddr), intToInet4AddressHTH(prefix & addrInt)); + } + + @Test + public void testPrefixLengthToV4NetmaskIntHTH_MaskAddr() { + checkAddressMasking("192.168.0.0", "192.168.128.1", 16); + checkAddressMasking("255.240.0.0", "255.255.255.255", 12); + checkAddressMasking("255.255.255.255", "255.255.255.255", 32); + checkAddressMasking("0.0.0.0", "255.255.255.255", 0); + } + + @Test + public void testGetImplicitNetmask() { + assertEquals(8, getImplicitNetmask(ipv4Address("4.2.2.2"))); + assertEquals(8, getImplicitNetmask(ipv4Address("10.5.6.7"))); + assertEquals(16, getImplicitNetmask(ipv4Address("173.194.72.105"))); + assertEquals(16, getImplicitNetmask(ipv4Address("172.23.68.145"))); + assertEquals(24, getImplicitNetmask(ipv4Address("192.0.2.1"))); + assertEquals(24, getImplicitNetmask(ipv4Address("192.168.5.1"))); + assertEquals(32, getImplicitNetmask(ipv4Address("224.0.0.1"))); + assertEquals(32, getImplicitNetmask(ipv4Address("255.6.7.8"))); + } + + private void assertInvalidNetworkMask(Inet4Address addr) { + try { + netmaskToPrefixLength(addr); + fail("Invalid netmask " + addr.getHostAddress() + " did not cause exception"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testNetmaskToPrefixLength() { + assertEquals(0, netmaskToPrefixLength(ipv4Address("0.0.0.0"))); + assertEquals(9, netmaskToPrefixLength(ipv4Address("255.128.0.0"))); + assertEquals(17, netmaskToPrefixLength(ipv4Address("255.255.128.0"))); + assertEquals(23, netmaskToPrefixLength(ipv4Address("255.255.254.0"))); + assertEquals(31, netmaskToPrefixLength(ipv4Address("255.255.255.254"))); + assertEquals(32, netmaskToPrefixLength(ipv4Address("255.255.255.255"))); + + assertInvalidNetworkMask(ipv4Address("0.0.0.1")); + assertInvalidNetworkMask(ipv4Address("255.255.255.253")); + assertInvalidNetworkMask(ipv4Address("255.255.0.255")); + } + + @Test + public void testGetPrefixMaskAsAddress() { + assertEquals("255.255.240.0", getPrefixMaskAsInet4Address(20).getHostAddress()); + assertEquals("255.0.0.0", getPrefixMaskAsInet4Address(8).getHostAddress()); + assertEquals("0.0.0.0", getPrefixMaskAsInet4Address(0).getHostAddress()); + assertEquals("255.255.255.255", getPrefixMaskAsInet4Address(32).getHostAddress()); + } + + @Test + public void testGetBroadcastAddress() { + assertEquals("192.168.15.255", + getBroadcastAddress(ipv4Address("192.168.0.123"), 20).getHostAddress()); + assertEquals("192.255.255.255", + getBroadcastAddress(ipv4Address("192.168.0.123"), 8).getHostAddress()); + assertEquals("192.168.0.123", + getBroadcastAddress(ipv4Address("192.168.0.123"), 32).getHostAddress()); + assertEquals("255.255.255.255", + getBroadcastAddress(ipv4Address("192.168.0.123"), 0).getHostAddress()); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetBroadcastAddress_PrefixTooLarge() { + getBroadcastAddress(ipv4Address("192.168.0.123"), 33); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetBroadcastAddress_NegativePrefix() { + getBroadcastAddress(ipv4Address("192.168.0.123"), -1); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetPrefixMaskAsAddress_PrefixTooLarge() { + getPrefixMaskAsInet4Address(33); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetPrefixMaskAsAddress_NegativePrefix() { + getPrefixMaskAsInet4Address(-1); + } + + private Inet4Address ipv4Address(String addr) { + return (Inet4Address) InetAddresses.parseNumericAddress(addr); + } +} From a9a6defaf4a92c51c5feb98ba9b8b87e46768a0f Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Mon, 15 Jun 2020 16:50:00 +0800 Subject: [PATCH 041/777] Move DnsPacket to libs/net This class might be used by some mainline modules. Cut the dependency between it and framework base classes. Bug: 151052811 Test: atest DnsPacketTest Test: atest DnsResolverTest Change-Id: Id12aaedb6dd75144ca9b58b94bfcd845a1f16360 --- .../android/net/module/util/DnsPacket.java | 252 ++++++++++++++++++ .../android/module/util/DnsPacketTest.java | 159 +++++++++++ 2 files changed, 411 insertions(+) create mode 100644 staticlibs/src_frameworkcommon/com/android/net/module/util/DnsPacket.java create mode 100644 staticlibs/tests/unit/src/com/android/module/util/DnsPacketTest.java diff --git a/staticlibs/src_frameworkcommon/com/android/net/module/util/DnsPacket.java b/staticlibs/src_frameworkcommon/com/android/net/module/util/DnsPacket.java new file mode 100644 index 0000000000..ac337e0104 --- /dev/null +++ b/staticlibs/src_frameworkcommon/com/android/net/module/util/DnsPacket.java @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.text.TextUtils; + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.text.DecimalFormat; +import java.text.FieldPosition; +import java.util.ArrayList; +import java.util.List; + +/** + * Defines basic data for DNS protocol based on RFC 1035. + * Subclasses create the specific format used in DNS packet. + * + * @hide + */ +public abstract class DnsPacket { + /** + * Thrown when parsing packet failed. + */ + public static class ParseException extends RuntimeException { + public String reason; + public ParseException(@NonNull String reason) { + super(reason); + this.reason = reason; + } + + public ParseException(@NonNull String reason, @NonNull Throwable cause) { + super(reason, cause); + this.reason = reason; + } + } + + /** + * DNS header for DNS protocol based on RFC 1035. + */ + public class DnsHeader { + private static final String TAG = "DnsHeader"; + public final int id; + public final int flags; + public final int rcode; + private final int[] mRecordCount; + + /** + * Create a new DnsHeader from a positioned ByteBuffer. + * + * The ByteBuffer must be in network byte order (which is the default). + * Reads the passed ByteBuffer from its current position and decodes a DNS header. + * When this constructor returns, the reading position of the ByteBuffer has been + * advanced to the end of the DNS header record. + * This is meant to chain with other methods reading a DNS response in sequence. + */ + DnsHeader(@NonNull ByteBuffer buf) throws BufferUnderflowException { + id = Short.toUnsignedInt(buf.getShort()); + flags = Short.toUnsignedInt(buf.getShort()); + rcode = flags & 0xF; + mRecordCount = new int[NUM_SECTIONS]; + for (int i = 0; i < NUM_SECTIONS; ++i) { + mRecordCount[i] = Short.toUnsignedInt(buf.getShort()); + } + } + + /** + * Get record count by type. + */ + public int getRecordCount(int type) { + return mRecordCount[type]; + } + } + + /** + * Superclass for DNS questions and DNS resource records. + * + * DNS questions (No TTL/RDATA) + * DNS resource records (With TTL/RDATA) + */ + public class DnsRecord { + private static final int MAXNAMESIZE = 255; + private static final int MAXLABELSIZE = 63; + private static final int MAXLABELCOUNT = 128; + private static final int NAME_NORMAL = 0; + private static final int NAME_COMPRESSION = 0xC0; + private final DecimalFormat mByteFormat = new DecimalFormat(); + private final FieldPosition mPos = new FieldPosition(0); + + private static final String TAG = "DnsRecord"; + + public final String dName; + public final int nsType; + public final int nsClass; + public final long ttl; + private final byte[] mRdata; + + /** + * Create a new DnsRecord from a positioned ByteBuffer. + * + * Reads the passed ByteBuffer from its current position and decodes a DNS record. + * When this constructor returns, the reading position of the ByteBuffer has been + * advanced to the end of the DNS header record. + * This is meant to chain with other methods reading a DNS response in sequence. + * + * @param ByteBuffer input of record, must be in network byte order + * (which is the default). + */ + DnsRecord(int recordType, @NonNull ByteBuffer buf) + throws BufferUnderflowException, ParseException { + dName = parseName(buf, 0 /* Parse depth */); + if (dName.length() > MAXNAMESIZE) { + throw new ParseException( + "Parse name fail, name size is too long: " + dName.length()); + } + nsType = Short.toUnsignedInt(buf.getShort()); + nsClass = Short.toUnsignedInt(buf.getShort()); + + if (recordType != QDSECTION) { + ttl = Integer.toUnsignedLong(buf.getInt()); + final int length = Short.toUnsignedInt(buf.getShort()); + mRdata = new byte[length]; + buf.get(mRdata); + } else { + ttl = 0; + mRdata = null; + } + } + + /** + * Get a copy of rdata. + */ + @Nullable + public byte[] getRR() { + return (mRdata == null) ? null : mRdata.clone(); + } + + /** + * Convert label from {@code byte[]} to {@code String} + * + * Follows the same conversion rules of the native code (ns_name.c in libc) + */ + private String labelToString(@NonNull byte[] label) { + final StringBuffer sb = new StringBuffer(); + for (int i = 0; i < label.length; ++i) { + int b = Byte.toUnsignedInt(label[i]); + // Control characters and non-ASCII characters. + if (b <= 0x20 || b >= 0x7f) { + // Append the byte as an escaped decimal number, e.g., "\19" for 0x13. + sb.append('\\'); + mByteFormat.format(b, sb, mPos); + } else if (b == '"' || b == '.' || b == ';' || b == '\\' + || b == '(' || b == ')' || b == '@' || b == '$') { + // Append the byte as an escaped character, e.g., "\:" for 0x3a. + sb.append('\\'); + sb.append((char) b); + } else { + // Append the byte as a character, e.g., "a" for 0x61. + sb.append((char) b); + } + } + return sb.toString(); + } + + private String parseName(@NonNull ByteBuffer buf, int depth) throws + BufferUnderflowException, ParseException { + if (depth > MAXLABELCOUNT) { + throw new ParseException("Failed to parse name, too many labels"); + } + final int len = Byte.toUnsignedInt(buf.get()); + final int mask = len & NAME_COMPRESSION; + if (0 == len) { + return ""; + } else if (mask != NAME_NORMAL && mask != NAME_COMPRESSION) { + throw new ParseException("Parse name fail, bad label type"); + } else if (mask == NAME_COMPRESSION) { + // Name compression based on RFC 1035 - 4.1.4 Message compression + final int offset = ((len & ~NAME_COMPRESSION) << 8) + Byte.toUnsignedInt(buf.get()); + final int oldPos = buf.position(); + if (offset >= oldPos - 2) { + throw new ParseException("Parse compression name fail, invalid compression"); + } + buf.position(offset); + final String pointed = parseName(buf, depth + 1); + buf.position(oldPos); + return pointed; + } else { + final byte[] label = new byte[len]; + buf.get(label); + final String head = labelToString(label); + if (head.length() > MAXLABELSIZE) { + throw new ParseException("Parse name fail, invalid label length"); + } + final String tail = parseName(buf, depth + 1); + return TextUtils.isEmpty(tail) ? head : head + "." + tail; + } + } + } + + public static final int QDSECTION = 0; + public static final int ANSECTION = 1; + public static final int NSSECTION = 2; + public static final int ARSECTION = 3; + private static final int NUM_SECTIONS = ARSECTION + 1; + + private static final String TAG = DnsPacket.class.getSimpleName(); + + protected final DnsHeader mHeader; + protected final List[] mRecords; + + protected DnsPacket(@NonNull byte[] data) throws ParseException { + if (null == data) throw new ParseException("Parse header failed, null input data"); + final ByteBuffer buffer; + try { + buffer = ByteBuffer.wrap(data); + mHeader = new DnsHeader(buffer); + } catch (BufferUnderflowException e) { + throw new ParseException("Parse Header fail, bad input data", e); + } + + mRecords = new ArrayList[NUM_SECTIONS]; + + for (int i = 0; i < NUM_SECTIONS; ++i) { + final int count = mHeader.getRecordCount(i); + if (count > 0) { + mRecords[i] = new ArrayList(count); + } + for (int j = 0; j < count; ++j) { + try { + mRecords[i].add(new DnsRecord(i, buffer)); + } catch (BufferUnderflowException e) { + throw new ParseException("Parse record fail", e); + } + } + } + } +} diff --git a/staticlibs/tests/unit/src/com/android/module/util/DnsPacketTest.java b/staticlibs/tests/unit/src/com/android/module/util/DnsPacketTest.java new file mode 100644 index 0000000000..1bbba08804 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/module/util/DnsPacketTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class DnsPacketTest { + private void assertHeaderParses(DnsPacket.DnsHeader header, int id, int flag, + int qCount, int aCount, int nsCount, int arCount) { + assertEquals(header.id, id); + assertEquals(header.flags, flag); + assertEquals(header.getRecordCount(DnsPacket.QDSECTION), qCount); + assertEquals(header.getRecordCount(DnsPacket.ANSECTION), aCount); + assertEquals(header.getRecordCount(DnsPacket.NSSECTION), nsCount); + assertEquals(header.getRecordCount(DnsPacket.ARSECTION), arCount); + } + + private void assertRecordParses(DnsPacket.DnsRecord record, String dname, + int dtype, int dclass, int ttl, byte[] rr) { + assertEquals(record.dName, dname); + assertEquals(record.nsType, dtype); + assertEquals(record.nsClass, dclass); + assertEquals(record.ttl, ttl); + assertTrue(Arrays.equals(record.getRR(), rr)); + } + + class TestDnsPacket extends DnsPacket { + TestDnsPacket(byte[] data) throws DnsPacket.ParseException { + super(data); + } + + public DnsHeader getHeader() { + return mHeader; + } + public List getRecordList(int secType) { + return mRecords[secType]; + } + } + + @Test + public void testNullDisallowed() { + try { + new TestDnsPacket(null); + fail("Exception not thrown for null byte array"); + } catch (DnsPacket.ParseException e) { + } + } + + @Test + public void testV4Answer() throws Exception { + final byte[] v4blob = new byte[] { + /* Header */ + 0x55, 0x66, /* Transaction ID */ + (byte) 0x81, (byte) 0x80, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x01, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + /* Answers */ + (byte) 0xc0, 0x0c, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + 0x00, 0x00, 0x01, 0x2b, /* TTL */ + 0x00, 0x04, /* Data length */ + (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 /* Address */ + }; + TestDnsPacket packet = new TestDnsPacket(v4blob); + + // Header part + assertHeaderParses(packet.getHeader(), 0x5566, 0x8180, 1, 1, 0, 0); + + // Record part + List qdRecordList = + packet.getRecordList(DnsPacket.QDSECTION); + assertEquals(qdRecordList.size(), 1); + assertRecordParses(qdRecordList.get(0), "www.google.com", 1, 1, 0, null); + + List anRecordList = + packet.getRecordList(DnsPacket.ANSECTION); + assertEquals(anRecordList.size(), 1); + assertRecordParses(anRecordList.get(0), "www.google.com", 1, 1, 0x12b, + new byte[]{ (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 }); + } + + @Test + public void testV6Answer() throws Exception { + final byte[] v6blob = new byte[] { + /* Header */ + 0x77, 0x22, /* Transaction ID */ + (byte) 0x81, (byte) 0x80, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x01, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x1c, /* Type */ + 0x00, 0x01, /* Class */ + /* Answers */ + (byte) 0xc0, 0x0c, /* Name */ + 0x00, 0x1c, /* Type */ + 0x00, 0x01, /* Class */ + 0x00, 0x00, 0x00, 0x37, /* TTL */ + 0x00, 0x10, /* Data length */ + 0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 /* Address */ + }; + TestDnsPacket packet = new TestDnsPacket(v6blob); + + // Header part + assertHeaderParses(packet.getHeader(), 0x7722, 0x8180, 1, 1, 0, 0); + + // Record part + List qdRecordList = + packet.getRecordList(DnsPacket.QDSECTION); + assertEquals(qdRecordList.size(), 1); + assertRecordParses(qdRecordList.get(0), "www.google.com", 28, 1, 0, null); + + List anRecordList = + packet.getRecordList(DnsPacket.ANSECTION); + assertEquals(anRecordList.size(), 1); + assertRecordParses(anRecordList.get(0), "www.google.com", 28, 1, 0x37, + new byte[]{ 0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 }); + } +} From 162f4de45ff31e016d41381ba92990a6624e853a Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Sat, 20 Jun 2020 11:38:17 +0800 Subject: [PATCH 042/777] Add the visibility of net-utils-framework-common for cts-net DnsResolverTest required DnsPacket to parse DNS answer, and the DnsPacket class is provided by system previously. However, DnsPacket was moved to here with changed package, which has no backward-compatibility and might cause NoClassDefFoundError. To solve this problem, build the DnsResolverTest with DnsPacket directly. Test: build Test: atest DnsResolverTest Bug: 150952393 Change-Id: I463fd58173cee55a210fa6c6b8c9b0d5a74b7906 --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index d93579b15d..0f8dda0869 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -45,6 +45,7 @@ java_library { sdk_version: "system_current", jarjar_rules: "jarjar-rules-shared.txt", visibility: [ + "//cts/tests/tests/net", "//frameworks/base/packages/Tethering", "//frameworks/opt/net/ike", "//frameworks/opt/telephony", From 85c290e33ea8556f9ca51847498eb87d8fb41634 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Mon, 15 Jun 2020 16:50:00 +0800 Subject: [PATCH 043/777] Move DnsPacket to libs/net This class might be used by some mainline modules. Cut the dependency between it and framework base classes. Bug: 151052811 Test: atest DnsPacketTest Test: atest DnsResolverTest (clean cherry-pick from internal branch) Merged-In: Id12aaedb6dd75144ca9b58b94bfcd845a1f16360 Change-Id: Id12aaedb6dd75144ca9b58b94bfcd845a1f16360 --- .../android/net/module/util/DnsPacket.java | 252 ++++++++++++++++++ .../android/module/util/DnsPacketTest.java | 159 +++++++++++ 2 files changed, 411 insertions(+) create mode 100644 staticlibs/src_frameworkcommon/com/android/net/module/util/DnsPacket.java create mode 100644 staticlibs/tests/unit/src/com/android/module/util/DnsPacketTest.java diff --git a/staticlibs/src_frameworkcommon/com/android/net/module/util/DnsPacket.java b/staticlibs/src_frameworkcommon/com/android/net/module/util/DnsPacket.java new file mode 100644 index 0000000000..ac337e0104 --- /dev/null +++ b/staticlibs/src_frameworkcommon/com/android/net/module/util/DnsPacket.java @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.text.TextUtils; + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.text.DecimalFormat; +import java.text.FieldPosition; +import java.util.ArrayList; +import java.util.List; + +/** + * Defines basic data for DNS protocol based on RFC 1035. + * Subclasses create the specific format used in DNS packet. + * + * @hide + */ +public abstract class DnsPacket { + /** + * Thrown when parsing packet failed. + */ + public static class ParseException extends RuntimeException { + public String reason; + public ParseException(@NonNull String reason) { + super(reason); + this.reason = reason; + } + + public ParseException(@NonNull String reason, @NonNull Throwable cause) { + super(reason, cause); + this.reason = reason; + } + } + + /** + * DNS header for DNS protocol based on RFC 1035. + */ + public class DnsHeader { + private static final String TAG = "DnsHeader"; + public final int id; + public final int flags; + public final int rcode; + private final int[] mRecordCount; + + /** + * Create a new DnsHeader from a positioned ByteBuffer. + * + * The ByteBuffer must be in network byte order (which is the default). + * Reads the passed ByteBuffer from its current position and decodes a DNS header. + * When this constructor returns, the reading position of the ByteBuffer has been + * advanced to the end of the DNS header record. + * This is meant to chain with other methods reading a DNS response in sequence. + */ + DnsHeader(@NonNull ByteBuffer buf) throws BufferUnderflowException { + id = Short.toUnsignedInt(buf.getShort()); + flags = Short.toUnsignedInt(buf.getShort()); + rcode = flags & 0xF; + mRecordCount = new int[NUM_SECTIONS]; + for (int i = 0; i < NUM_SECTIONS; ++i) { + mRecordCount[i] = Short.toUnsignedInt(buf.getShort()); + } + } + + /** + * Get record count by type. + */ + public int getRecordCount(int type) { + return mRecordCount[type]; + } + } + + /** + * Superclass for DNS questions and DNS resource records. + * + * DNS questions (No TTL/RDATA) + * DNS resource records (With TTL/RDATA) + */ + public class DnsRecord { + private static final int MAXNAMESIZE = 255; + private static final int MAXLABELSIZE = 63; + private static final int MAXLABELCOUNT = 128; + private static final int NAME_NORMAL = 0; + private static final int NAME_COMPRESSION = 0xC0; + private final DecimalFormat mByteFormat = new DecimalFormat(); + private final FieldPosition mPos = new FieldPosition(0); + + private static final String TAG = "DnsRecord"; + + public final String dName; + public final int nsType; + public final int nsClass; + public final long ttl; + private final byte[] mRdata; + + /** + * Create a new DnsRecord from a positioned ByteBuffer. + * + * Reads the passed ByteBuffer from its current position and decodes a DNS record. + * When this constructor returns, the reading position of the ByteBuffer has been + * advanced to the end of the DNS header record. + * This is meant to chain with other methods reading a DNS response in sequence. + * + * @param ByteBuffer input of record, must be in network byte order + * (which is the default). + */ + DnsRecord(int recordType, @NonNull ByteBuffer buf) + throws BufferUnderflowException, ParseException { + dName = parseName(buf, 0 /* Parse depth */); + if (dName.length() > MAXNAMESIZE) { + throw new ParseException( + "Parse name fail, name size is too long: " + dName.length()); + } + nsType = Short.toUnsignedInt(buf.getShort()); + nsClass = Short.toUnsignedInt(buf.getShort()); + + if (recordType != QDSECTION) { + ttl = Integer.toUnsignedLong(buf.getInt()); + final int length = Short.toUnsignedInt(buf.getShort()); + mRdata = new byte[length]; + buf.get(mRdata); + } else { + ttl = 0; + mRdata = null; + } + } + + /** + * Get a copy of rdata. + */ + @Nullable + public byte[] getRR() { + return (mRdata == null) ? null : mRdata.clone(); + } + + /** + * Convert label from {@code byte[]} to {@code String} + * + * Follows the same conversion rules of the native code (ns_name.c in libc) + */ + private String labelToString(@NonNull byte[] label) { + final StringBuffer sb = new StringBuffer(); + for (int i = 0; i < label.length; ++i) { + int b = Byte.toUnsignedInt(label[i]); + // Control characters and non-ASCII characters. + if (b <= 0x20 || b >= 0x7f) { + // Append the byte as an escaped decimal number, e.g., "\19" for 0x13. + sb.append('\\'); + mByteFormat.format(b, sb, mPos); + } else if (b == '"' || b == '.' || b == ';' || b == '\\' + || b == '(' || b == ')' || b == '@' || b == '$') { + // Append the byte as an escaped character, e.g., "\:" for 0x3a. + sb.append('\\'); + sb.append((char) b); + } else { + // Append the byte as a character, e.g., "a" for 0x61. + sb.append((char) b); + } + } + return sb.toString(); + } + + private String parseName(@NonNull ByteBuffer buf, int depth) throws + BufferUnderflowException, ParseException { + if (depth > MAXLABELCOUNT) { + throw new ParseException("Failed to parse name, too many labels"); + } + final int len = Byte.toUnsignedInt(buf.get()); + final int mask = len & NAME_COMPRESSION; + if (0 == len) { + return ""; + } else if (mask != NAME_NORMAL && mask != NAME_COMPRESSION) { + throw new ParseException("Parse name fail, bad label type"); + } else if (mask == NAME_COMPRESSION) { + // Name compression based on RFC 1035 - 4.1.4 Message compression + final int offset = ((len & ~NAME_COMPRESSION) << 8) + Byte.toUnsignedInt(buf.get()); + final int oldPos = buf.position(); + if (offset >= oldPos - 2) { + throw new ParseException("Parse compression name fail, invalid compression"); + } + buf.position(offset); + final String pointed = parseName(buf, depth + 1); + buf.position(oldPos); + return pointed; + } else { + final byte[] label = new byte[len]; + buf.get(label); + final String head = labelToString(label); + if (head.length() > MAXLABELSIZE) { + throw new ParseException("Parse name fail, invalid label length"); + } + final String tail = parseName(buf, depth + 1); + return TextUtils.isEmpty(tail) ? head : head + "." + tail; + } + } + } + + public static final int QDSECTION = 0; + public static final int ANSECTION = 1; + public static final int NSSECTION = 2; + public static final int ARSECTION = 3; + private static final int NUM_SECTIONS = ARSECTION + 1; + + private static final String TAG = DnsPacket.class.getSimpleName(); + + protected final DnsHeader mHeader; + protected final List[] mRecords; + + protected DnsPacket(@NonNull byte[] data) throws ParseException { + if (null == data) throw new ParseException("Parse header failed, null input data"); + final ByteBuffer buffer; + try { + buffer = ByteBuffer.wrap(data); + mHeader = new DnsHeader(buffer); + } catch (BufferUnderflowException e) { + throw new ParseException("Parse Header fail, bad input data", e); + } + + mRecords = new ArrayList[NUM_SECTIONS]; + + for (int i = 0; i < NUM_SECTIONS; ++i) { + final int count = mHeader.getRecordCount(i); + if (count > 0) { + mRecords[i] = new ArrayList(count); + } + for (int j = 0; j < count; ++j) { + try { + mRecords[i].add(new DnsRecord(i, buffer)); + } catch (BufferUnderflowException e) { + throw new ParseException("Parse record fail", e); + } + } + } + } +} diff --git a/staticlibs/tests/unit/src/com/android/module/util/DnsPacketTest.java b/staticlibs/tests/unit/src/com/android/module/util/DnsPacketTest.java new file mode 100644 index 0000000000..1bbba08804 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/module/util/DnsPacketTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class DnsPacketTest { + private void assertHeaderParses(DnsPacket.DnsHeader header, int id, int flag, + int qCount, int aCount, int nsCount, int arCount) { + assertEquals(header.id, id); + assertEquals(header.flags, flag); + assertEquals(header.getRecordCount(DnsPacket.QDSECTION), qCount); + assertEquals(header.getRecordCount(DnsPacket.ANSECTION), aCount); + assertEquals(header.getRecordCount(DnsPacket.NSSECTION), nsCount); + assertEquals(header.getRecordCount(DnsPacket.ARSECTION), arCount); + } + + private void assertRecordParses(DnsPacket.DnsRecord record, String dname, + int dtype, int dclass, int ttl, byte[] rr) { + assertEquals(record.dName, dname); + assertEquals(record.nsType, dtype); + assertEquals(record.nsClass, dclass); + assertEquals(record.ttl, ttl); + assertTrue(Arrays.equals(record.getRR(), rr)); + } + + class TestDnsPacket extends DnsPacket { + TestDnsPacket(byte[] data) throws DnsPacket.ParseException { + super(data); + } + + public DnsHeader getHeader() { + return mHeader; + } + public List getRecordList(int secType) { + return mRecords[secType]; + } + } + + @Test + public void testNullDisallowed() { + try { + new TestDnsPacket(null); + fail("Exception not thrown for null byte array"); + } catch (DnsPacket.ParseException e) { + } + } + + @Test + public void testV4Answer() throws Exception { + final byte[] v4blob = new byte[] { + /* Header */ + 0x55, 0x66, /* Transaction ID */ + (byte) 0x81, (byte) 0x80, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x01, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + /* Answers */ + (byte) 0xc0, 0x0c, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + 0x00, 0x00, 0x01, 0x2b, /* TTL */ + 0x00, 0x04, /* Data length */ + (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 /* Address */ + }; + TestDnsPacket packet = new TestDnsPacket(v4blob); + + // Header part + assertHeaderParses(packet.getHeader(), 0x5566, 0x8180, 1, 1, 0, 0); + + // Record part + List qdRecordList = + packet.getRecordList(DnsPacket.QDSECTION); + assertEquals(qdRecordList.size(), 1); + assertRecordParses(qdRecordList.get(0), "www.google.com", 1, 1, 0, null); + + List anRecordList = + packet.getRecordList(DnsPacket.ANSECTION); + assertEquals(anRecordList.size(), 1); + assertRecordParses(anRecordList.get(0), "www.google.com", 1, 1, 0x12b, + new byte[]{ (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 }); + } + + @Test + public void testV6Answer() throws Exception { + final byte[] v6blob = new byte[] { + /* Header */ + 0x77, 0x22, /* Transaction ID */ + (byte) 0x81, (byte) 0x80, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x01, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x1c, /* Type */ + 0x00, 0x01, /* Class */ + /* Answers */ + (byte) 0xc0, 0x0c, /* Name */ + 0x00, 0x1c, /* Type */ + 0x00, 0x01, /* Class */ + 0x00, 0x00, 0x00, 0x37, /* TTL */ + 0x00, 0x10, /* Data length */ + 0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 /* Address */ + }; + TestDnsPacket packet = new TestDnsPacket(v6blob); + + // Header part + assertHeaderParses(packet.getHeader(), 0x7722, 0x8180, 1, 1, 0, 0); + + // Record part + List qdRecordList = + packet.getRecordList(DnsPacket.QDSECTION); + assertEquals(qdRecordList.size(), 1); + assertRecordParses(qdRecordList.get(0), "www.google.com", 28, 1, 0, null); + + List anRecordList = + packet.getRecordList(DnsPacket.ANSECTION); + assertEquals(anRecordList.size(), 1); + assertRecordParses(anRecordList.get(0), "www.google.com", 28, 1, 0x37, + new byte[]{ 0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 }); + } +} From fd5479e5d486c553e8f446315c7e5de8627bb725 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Sat, 20 Jun 2020 11:38:17 +0800 Subject: [PATCH 044/777] Add the visibility of net-utils-framework-common for cts-net DnsResolverTest required DnsPacket to parse DNS answer, and the DnsPacket class is provided by system previously. However, DnsPacket was moved to here with changed package, which has no backward-compatibility and might cause NoClassDefFoundError. To solve this problem, build the DnsResolverTest with DnsPacket directly. Test: build Test: atest DnsResolverTest Bug: 150952393 (clean cherry-pick from internal branch) Merged-In: I463fd58173cee55a210fa6c6b8c9b0d5a74b7906 Change-Id: I463fd58173cee55a210fa6c6b8c9b0d5a74b7906 --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index d29ba3657f..ef6d62d23e 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -45,6 +45,7 @@ java_library { sdk_version: "system_current", jarjar_rules: "jarjar-rules-shared.txt", visibility: [ + "//cts/tests/tests/net", "//frameworks/base/packages/Tethering", "//frameworks/opt/net/ike", "//frameworks/opt/telephony", From f109837101010c5189cc51604f643e853f3de308 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 8 Jun 2020 15:55:25 +0900 Subject: [PATCH 045/777] Move Inet[4]AddressUtils to libs/net The classes should not be picked up from frameworks/base, as they are part of several mainline modules. Bug: 151052811 Test: m; manual: flashed, wifi and telephony working Test: atest NetworkStackCoverageTests (clean cherry-pick from internal branch) Merged-In: I2b3dcf2e238be047147232769602df56894dc6b1 Change-Id: I2b3dcf2e238be047147232769602df56894dc6b1 --- staticlibs/Android.bp | 1 + .../net/module/util/Inet4AddressUtils.java | 166 ++++++++++++++ .../net/module/util/InetAddressUtils.java | 58 +++++ staticlibs/tests/unit/Android.bp | 2 + .../module/util/Inet4AddressUtilsTest.java | 210 ++++++++++++++++++ 5 files changed, 437 insertions(+) create mode 100644 staticlibs/src_frameworkcommon/com/android/net/module/util/Inet4AddressUtils.java create mode 100644 staticlibs/src_frameworkcommon/com/android/net/module/util/InetAddressUtils.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/Inet4AddressUtilsTest.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index ef6d62d23e..0f8dda0869 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -94,6 +94,7 @@ filegroup { srcs: [ "src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java", "src_frameworkcommon/android/net/util/MacAddressUtils.java", + "src_frameworkcommon/com/android/net/module/util/**/*.java", ], path: "src_frameworkcommon", visibility: [ diff --git a/staticlibs/src_frameworkcommon/com/android/net/module/util/Inet4AddressUtils.java b/staticlibs/src_frameworkcommon/com/android/net/module/util/Inet4AddressUtils.java new file mode 100644 index 0000000000..a1d34a0f3f --- /dev/null +++ b/staticlibs/src_frameworkcommon/com/android/net/module/util/Inet4AddressUtils.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * Collection of utilities to work with IPv4 addresses. + * @hide + */ +public class Inet4AddressUtils { + + /** + * Convert a IPv4 address from an integer to an InetAddress (0x04030201 -> 1.2.3.4) + * + *

This method uses the higher-order int bytes as the lower-order IPv4 address bytes, + * which is an unusual convention. Consider {@link #intToInet4AddressHTH(int)} instead. + * @param hostAddress an int coding for an IPv4 address, where higher-order int byte is + * lower-order IPv4 address byte + */ + public static Inet4Address intToInet4AddressHTL(int hostAddress) { + return intToInet4AddressHTH(Integer.reverseBytes(hostAddress)); + } + + /** + * Convert a IPv4 address from an integer to an InetAddress (0x01020304 -> 1.2.3.4) + * @param hostAddress an int coding for an IPv4 address + */ + public static Inet4Address intToInet4AddressHTH(int hostAddress) { + byte[] addressBytes = { (byte) (0xff & (hostAddress >> 24)), + (byte) (0xff & (hostAddress >> 16)), + (byte) (0xff & (hostAddress >> 8)), + (byte) (0xff & hostAddress) }; + + try { + return (Inet4Address) InetAddress.getByAddress(addressBytes); + } catch (UnknownHostException e) { + throw new AssertionError(); + } + } + + /** + * Convert an IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x01020304) + * + *

This conversion can help order IP addresses: considering the ordering + * 192.0.2.1 < 192.0.2.2 < ..., resulting ints will follow that ordering if read as unsigned + * integers with {@link Integer#toUnsignedLong}. + * @param inetAddr is an InetAddress corresponding to the IPv4 address + * @return the IP address as integer + */ + public static int inet4AddressToIntHTH(Inet4Address inetAddr) + throws IllegalArgumentException { + byte [] addr = inetAddr.getAddress(); + return ((addr[0] & 0xff) << 24) | ((addr[1] & 0xff) << 16) + | ((addr[2] & 0xff) << 8) | (addr[3] & 0xff); + } + + /** + * Convert a IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x04030201) + * + *

This method stores the higher-order IPv4 address bytes in the lower-order int bytes, + * which is an unusual convention. Consider {@link #inet4AddressToIntHTH(Inet4Address)} instead. + * @param inetAddr is an InetAddress corresponding to the IPv4 address + * @return the IP address as integer + */ + public static int inet4AddressToIntHTL(Inet4Address inetAddr) { + return Integer.reverseBytes(inet4AddressToIntHTH(inetAddr)); + } + + /** + * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0xffff8000) + * @return the IPv4 netmask as an integer + */ + public static int prefixLengthToV4NetmaskIntHTH(int prefixLength) + throws IllegalArgumentException { + if (prefixLength < 0 || prefixLength > 32) { + throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)"); + } + // (int)a << b is equivalent to a << (b & 0x1f): can't shift by 32 (-1 << 32 == -1) + return prefixLength == 0 ? 0 : 0xffffffff << (32 - prefixLength); + } + + /** + * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0x0080ffff). + * + *

This method stores the higher-order IPv4 address bytes in the lower-order int bytes, + * which is an unusual convention. Consider {@link #prefixLengthToV4NetmaskIntHTH(int)} instead. + * @return the IPv4 netmask as an integer + */ + public static int prefixLengthToV4NetmaskIntHTL(int prefixLength) + throws IllegalArgumentException { + return Integer.reverseBytes(prefixLengthToV4NetmaskIntHTH(prefixLength)); + } + + /** + * Convert an IPv4 netmask to a prefix length, checking that the netmask is contiguous. + * @param netmask as a {@code Inet4Address}. + * @return the network prefix length + * @throws IllegalArgumentException the specified netmask was not contiguous. + * @hide + */ + public static int netmaskToPrefixLength(Inet4Address netmask) { + // inetAddressToInt returns an int in *network* byte order. + int i = inet4AddressToIntHTH(netmask); + int prefixLength = Integer.bitCount(i); + int trailingZeros = Integer.numberOfTrailingZeros(i); + if (trailingZeros != 32 - prefixLength) { + throw new IllegalArgumentException("Non-contiguous netmask: " + Integer.toHexString(i)); + } + return prefixLength; + } + + /** + * Returns the implicit netmask of an IPv4 address, as was the custom before 1993. + */ + public static int getImplicitNetmask(Inet4Address address) { + int firstByte = address.getAddress()[0] & 0xff; // Convert to an unsigned value. + if (firstByte < 128) { + return 8; + } else if (firstByte < 192) { + return 16; + } else if (firstByte < 224) { + return 24; + } else { + return 32; // Will likely not end well for other reasons. + } + } + + /** + * Get the broadcast address for a given prefix. + * + *

For example 192.168.0.1/24 -> 192.168.0.255 + */ + public static Inet4Address getBroadcastAddress(Inet4Address addr, int prefixLength) + throws IllegalArgumentException { + final int intBroadcastAddr = inet4AddressToIntHTH(addr) + | ~prefixLengthToV4NetmaskIntHTH(prefixLength); + return intToInet4AddressHTH(intBroadcastAddr); + } + + /** + * Get a prefix mask as Inet4Address for a given prefix length. + * + *

For example 20 -> 255.255.240.0 + */ + public static Inet4Address getPrefixMaskAsInet4Address(int prefixLength) + throws IllegalArgumentException { + return intToInet4AddressHTH(prefixLengthToV4NetmaskIntHTH(prefixLength)); + } +} diff --git a/staticlibs/src_frameworkcommon/com/android/net/module/util/InetAddressUtils.java b/staticlibs/src_frameworkcommon/com/android/net/module/util/InetAddressUtils.java new file mode 100644 index 0000000000..6300328e8d --- /dev/null +++ b/staticlibs/src_frameworkcommon/com/android/net/module/util/InetAddressUtils.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import android.os.Parcel; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * Collection of utilities to interact with {@link InetAddress} + * @hide + */ +public class InetAddressUtils { + + /** + * Writes an InetAddress to a parcel. The address may be null. This is likely faster than + * calling writeSerializable. + * @hide + */ + public static void parcelInetAddress(Parcel parcel, InetAddress address, int flags) { + byte[] addressArray = (address != null) ? address.getAddress() : null; + parcel.writeByteArray(addressArray); + } + + /** + * Reads an InetAddress from a parcel. Returns null if the address that was written was null + * or if the data is invalid. + * @hide + */ + public static InetAddress unparcelInetAddress(Parcel in) { + byte[] addressArray = in.createByteArray(); + if (addressArray == null) { + return null; + } + try { + return InetAddress.getByAddress(addressArray); + } catch (UnknownHostException e) { + return null; + } + } + + private InetAddressUtils() {} +} diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index 52c5f82f61..cb15277324 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -5,6 +5,7 @@ android_library { name: "NetworkStaticLibTestsLib", srcs: ["src/**/*.java","src/**/*.kt"], + min_sdk_version: "29", jarjar_rules: "jarjar-rules.txt", static_libs: [ "net-utils-framework-common", @@ -16,6 +17,7 @@ android_library { ], visibility: [ "//frameworks/base/packages/Tethering/tests/integration", + "//packages/modules/NetworkStack/tests/integration", ] } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/Inet4AddressUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/Inet4AddressUtilsTest.java new file mode 100644 index 0000000000..5d5ed911f2 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/Inet4AddressUtilsTest.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import static com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress; +import static com.android.net.module.util.Inet4AddressUtils.getImplicitNetmask; +import static com.android.net.module.util.Inet4AddressUtils.getPrefixMaskAsInet4Address; +import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH; +import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTL; +import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; +import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTL; +import static com.android.net.module.util.Inet4AddressUtils.netmaskToPrefixLength; +import static com.android.net.module.util.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH; +import static com.android.net.module.util.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL; + +import static junit.framework.Assert.assertEquals; + +import static org.junit.Assert.fail; + +import android.net.InetAddresses; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class Inet4AddressUtilsTest { + + @Test + public void testInet4AddressToIntHTL() { + assertEquals(0, inet4AddressToIntHTL(ipv4Address("0.0.0.0"))); + assertEquals(0x000080ff, inet4AddressToIntHTL(ipv4Address("255.128.0.0"))); + assertEquals(0x0080ff0a, inet4AddressToIntHTL(ipv4Address("10.255.128.0"))); + assertEquals(0x00feff0a, inet4AddressToIntHTL(ipv4Address("10.255.254.0"))); + assertEquals(0xfeffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.254"))); + assertEquals(0xffffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.255"))); + } + + @Test + public void testIntToInet4AddressHTL() { + assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTL(0)); + assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTL(0x000080ff)); + assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTL(0x0080ff0a)); + assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTL(0x00feff0a)); + assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTL(0xfeffa8c0)); + assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTL(0xffffa8c0)); + } + + @Test + public void testInet4AddressToIntHTH() { + assertEquals(0, inet4AddressToIntHTH(ipv4Address("0.0.0.0"))); + assertEquals(0xff800000, inet4AddressToIntHTH(ipv4Address("255.128.0.0"))); + assertEquals(0x0aff8000, inet4AddressToIntHTH(ipv4Address("10.255.128.0"))); + assertEquals(0x0afffe00, inet4AddressToIntHTH(ipv4Address("10.255.254.0"))); + assertEquals(0xc0a8fffe, inet4AddressToIntHTH(ipv4Address("192.168.255.254"))); + assertEquals(0xc0a8ffff, inet4AddressToIntHTH(ipv4Address("192.168.255.255"))); + } + + @Test + public void testIntToInet4AddressHTH() { + assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTH(0)); + assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTH(0xff800000)); + assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTH(0x0aff8000)); + assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTH(0x0afffe00)); + assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTH(0xc0a8fffe)); + assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTH(0xc0a8ffff)); + } + + + @Test + public void testPrefixLengthToV4NetmaskIntHTL() { + assertEquals(0, prefixLengthToV4NetmaskIntHTL(0)); + assertEquals(0x000080ff /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTL(9)); + assertEquals(0x0080ffff /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTL(17)); + assertEquals(0x00feffff /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTL(23)); + assertEquals(0xfeffffff /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTL(31)); + assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTL(32)); + } + + @Test + public void testPrefixLengthToV4NetmaskIntHTH() { + assertEquals(0, prefixLengthToV4NetmaskIntHTH(0)); + assertEquals(0xff800000 /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTH(9)); + assertEquals(0xffff8000 /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTH(17)); + assertEquals(0xfffffe00 /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTH(23)); + assertEquals(0xfffffffe /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTH(31)); + assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTH(32)); + } + + @Test(expected = IllegalArgumentException.class) + public void testPrefixLengthToV4NetmaskIntHTH_NegativeLength() { + prefixLengthToV4NetmaskIntHTH(-1); + } + + @Test(expected = IllegalArgumentException.class) + public void testPrefixLengthToV4NetmaskIntHTH_LengthTooLarge() { + prefixLengthToV4NetmaskIntHTH(33); + } + + private void checkAddressMasking(String expectedAddr, String addr, int prefixLength) { + final int prefix = prefixLengthToV4NetmaskIntHTH(prefixLength); + final int addrInt = inet4AddressToIntHTH(ipv4Address(addr)); + assertEquals(ipv4Address(expectedAddr), intToInet4AddressHTH(prefix & addrInt)); + } + + @Test + public void testPrefixLengthToV4NetmaskIntHTH_MaskAddr() { + checkAddressMasking("192.168.0.0", "192.168.128.1", 16); + checkAddressMasking("255.240.0.0", "255.255.255.255", 12); + checkAddressMasking("255.255.255.255", "255.255.255.255", 32); + checkAddressMasking("0.0.0.0", "255.255.255.255", 0); + } + + @Test + public void testGetImplicitNetmask() { + assertEquals(8, getImplicitNetmask(ipv4Address("4.2.2.2"))); + assertEquals(8, getImplicitNetmask(ipv4Address("10.5.6.7"))); + assertEquals(16, getImplicitNetmask(ipv4Address("173.194.72.105"))); + assertEquals(16, getImplicitNetmask(ipv4Address("172.23.68.145"))); + assertEquals(24, getImplicitNetmask(ipv4Address("192.0.2.1"))); + assertEquals(24, getImplicitNetmask(ipv4Address("192.168.5.1"))); + assertEquals(32, getImplicitNetmask(ipv4Address("224.0.0.1"))); + assertEquals(32, getImplicitNetmask(ipv4Address("255.6.7.8"))); + } + + private void assertInvalidNetworkMask(Inet4Address addr) { + try { + netmaskToPrefixLength(addr); + fail("Invalid netmask " + addr.getHostAddress() + " did not cause exception"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testNetmaskToPrefixLength() { + assertEquals(0, netmaskToPrefixLength(ipv4Address("0.0.0.0"))); + assertEquals(9, netmaskToPrefixLength(ipv4Address("255.128.0.0"))); + assertEquals(17, netmaskToPrefixLength(ipv4Address("255.255.128.0"))); + assertEquals(23, netmaskToPrefixLength(ipv4Address("255.255.254.0"))); + assertEquals(31, netmaskToPrefixLength(ipv4Address("255.255.255.254"))); + assertEquals(32, netmaskToPrefixLength(ipv4Address("255.255.255.255"))); + + assertInvalidNetworkMask(ipv4Address("0.0.0.1")); + assertInvalidNetworkMask(ipv4Address("255.255.255.253")); + assertInvalidNetworkMask(ipv4Address("255.255.0.255")); + } + + @Test + public void testGetPrefixMaskAsAddress() { + assertEquals("255.255.240.0", getPrefixMaskAsInet4Address(20).getHostAddress()); + assertEquals("255.0.0.0", getPrefixMaskAsInet4Address(8).getHostAddress()); + assertEquals("0.0.0.0", getPrefixMaskAsInet4Address(0).getHostAddress()); + assertEquals("255.255.255.255", getPrefixMaskAsInet4Address(32).getHostAddress()); + } + + @Test + public void testGetBroadcastAddress() { + assertEquals("192.168.15.255", + getBroadcastAddress(ipv4Address("192.168.0.123"), 20).getHostAddress()); + assertEquals("192.255.255.255", + getBroadcastAddress(ipv4Address("192.168.0.123"), 8).getHostAddress()); + assertEquals("192.168.0.123", + getBroadcastAddress(ipv4Address("192.168.0.123"), 32).getHostAddress()); + assertEquals("255.255.255.255", + getBroadcastAddress(ipv4Address("192.168.0.123"), 0).getHostAddress()); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetBroadcastAddress_PrefixTooLarge() { + getBroadcastAddress(ipv4Address("192.168.0.123"), 33); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetBroadcastAddress_NegativePrefix() { + getBroadcastAddress(ipv4Address("192.168.0.123"), -1); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetPrefixMaskAsAddress_PrefixTooLarge() { + getPrefixMaskAsInet4Address(33); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetPrefixMaskAsAddress_NegativePrefix() { + getPrefixMaskAsInet4Address(-1); + } + + private Inet4Address ipv4Address(String addr) { + return (Inet4Address) InetAddresses.parseNumericAddress(addr); + } +} From 9fff546da71b6c95389da0838a6925a00e677817 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 29 Jul 2020 12:20:49 +0900 Subject: [PATCH 046/777] Set the NAME_* constants public The constants are useful to examine or build DNS packets. Test: m Bug: 160617623 Bug: 160656765 Change-Id: I0fbe59e4bfb2ffc8ceb83ff5f81ceeab0f83228b --- .../com/android/net/module/util/DnsPacket.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/src_frameworkcommon/com/android/net/module/util/DnsPacket.java b/staticlibs/src_frameworkcommon/com/android/net/module/util/DnsPacket.java index ac337e0104..5ac731cb0f 100644 --- a/staticlibs/src_frameworkcommon/com/android/net/module/util/DnsPacket.java +++ b/staticlibs/src_frameworkcommon/com/android/net/module/util/DnsPacket.java @@ -97,8 +97,8 @@ public abstract class DnsPacket { private static final int MAXNAMESIZE = 255; private static final int MAXLABELSIZE = 63; private static final int MAXLABELCOUNT = 128; - private static final int NAME_NORMAL = 0; - private static final int NAME_COMPRESSION = 0xC0; + public static final int NAME_NORMAL = 0; + public static final int NAME_COMPRESSION = 0xC0; private final DecimalFormat mByteFormat = new DecimalFormat(); private final FieldPosition mPos = new FieldPosition(0); From 48c6c7d838f60bf52ad3c919a243e9582cd489fe Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 25 Jun 2020 23:39:15 +0900 Subject: [PATCH 047/777] Move utilities to libs/net MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These files used to be in the network stack directory, but the libs directory is a much more suitable place for them. Also fix a typo : ConcurrentIntepreter → ConcurrentInterpreter Also move {FdEvents,Packet}Reader to internal annotations. That's what they should have been using in the first place anyway. Note that this does not fix preupload issues reported by checkstyle to make review easier. The fixes are in a followup patch to this one. Test: checkbuild Change-Id: I675077fd42cbb092c0e6bd56571f2fc022e582fd --- staticlibs/Android.bp | 105 ++++- .../android/net/NetworkFactory.java | 0 .../android/net/util/FdEventsReader.java | 269 ++++++++++++ .../device/android/net/util/PacketReader.java | 60 +++ .../testutils/ConcurrentInterpreter.kt | 188 +++++++++ .../com/android/testutils/DevSdkIgnoreRule.kt | 90 ++++ .../android/testutils/DevSdkIgnoreRunner.kt | 72 ++++ .../com/android/testutils/FakeDns.kt | 94 +++++ .../com/android/testutils/HandlerUtils.kt | 49 +++ .../android/testutils/NetworkStatsUtils.kt | 78 ++++ .../com/android/testutils/ParcelUtils.kt | 68 +++ .../android/testutils/TapPacketReader.java | 93 +++++ .../android/testutils/TestNetworkTracker.kt | 92 ++++ .../testutils/TestableNetworkCallback.kt | 393 ++++++++++++++++++ .../testutils/TestableNetworkStatsProvider.kt | 98 +++++ .../TestableNetworkStatsProviderBinder.kt | 64 +++ .../TestableNetworkStatsProviderCbBinder.kt | 84 ++++ .../android/net/util/IpRange.java | 0 .../android/net/util/LinkPropertiesUtils.java | 0 .../android/net/util/MacAddressUtils.java | 0 .../android/net/util/NetUtils.java | 0 .../android/net/util/nsd/DnsSdTxtRecord.java | 0 .../android/net/module/util/DnsPacket.java | 0 .../net/module/util/Inet4AddressUtils.java | 0 .../net/module/util/InetAddressUtils.java | 0 .../android/net/module/util/TrackRecord.kt | 247 +++++++++++ .../com/android/testutils/ConcurrentUtils.kt | 26 ++ .../com/android/testutils/ExceptionUtils.java | 67 +++ .../com/android/testutils/FileUtils.kt | 27 ++ .../com/android/testutils/MiscAsserts.kt | 103 +++++ .../com/android/testutils/PacketFilter.kt | 87 ++++ .../com/android/testutils/SkipPresubmit.kt | 24 ++ staticlibs/jarjar-rules-shared.txt | 9 +- staticlibs/tests/unit/Android.bp | 2 + staticlibs/tests/unit/jarjar-rules.txt | 10 +- .../net/module/util/PacketReaderTest.java | 248 +++++++++++ 36 files changed, 2724 insertions(+), 23 deletions(-) rename staticlibs/{src_servicescommon => device}/android/net/NetworkFactory.java (100%) create mode 100644 staticlibs/device/android/net/util/FdEventsReader.java create mode 100644 staticlibs/device/android/net/util/PacketReader.java create mode 100644 staticlibs/devicetests/com/android/testutils/ConcurrentInterpreter.kt create mode 100644 staticlibs/devicetests/com/android/testutils/DevSdkIgnoreRule.kt create mode 100644 staticlibs/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt create mode 100644 staticlibs/devicetests/com/android/testutils/FakeDns.kt create mode 100644 staticlibs/devicetests/com/android/testutils/HandlerUtils.kt create mode 100644 staticlibs/devicetests/com/android/testutils/NetworkStatsUtils.kt create mode 100644 staticlibs/devicetests/com/android/testutils/ParcelUtils.kt create mode 100644 staticlibs/devicetests/com/android/testutils/TapPacketReader.java create mode 100644 staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt create mode 100644 staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt create mode 100644 staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt create mode 100644 staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt create mode 100644 staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt rename staticlibs/{src_frameworkcommon => framework}/android/net/util/IpRange.java (100%) rename staticlibs/{src_frameworkcommon => framework}/android/net/util/LinkPropertiesUtils.java (100%) rename staticlibs/{src_frameworkcommon => framework}/android/net/util/MacAddressUtils.java (100%) rename staticlibs/{src_frameworkcommon => framework}/android/net/util/NetUtils.java (100%) rename staticlibs/{src_frameworkcommon => framework}/android/net/util/nsd/DnsSdTxtRecord.java (100%) rename staticlibs/{src_frameworkcommon => framework}/com/android/net/module/util/DnsPacket.java (100%) rename staticlibs/{src_frameworkcommon => framework}/com/android/net/module/util/Inet4AddressUtils.java (100%) rename staticlibs/{src_frameworkcommon => framework}/com/android/net/module/util/InetAddressUtils.java (100%) create mode 100644 staticlibs/hostdevice/com/android/net/module/util/TrackRecord.kt create mode 100644 staticlibs/hostdevice/com/android/testutils/ConcurrentUtils.kt create mode 100644 staticlibs/hostdevice/com/android/testutils/ExceptionUtils.java create mode 100644 staticlibs/hostdevice/com/android/testutils/FileUtils.kt create mode 100644 staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt create mode 100644 staticlibs/hostdevice/com/android/testutils/PacketFilter.kt create mode 100644 staticlibs/hostdevice/com/android/testutils/SkipPresubmit.kt create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 0f8dda0869..4b15b16980 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -27,10 +27,86 @@ // included in the bootclasspath, they could incorrectly be included in the SDK documentation even // though they are not in the current.txt files. +java_library { + name: "net-utils-device-common", + srcs: [ + "device/**/*.java", + // This library is used by system modules, for which the system health impact of Kotlin + // has not yet been evaluated. + // "src_devicecommon/**/*.kt", + ":framework-annotations", + ], + sdk_version: "system_current", + min_sdk_version: "29", + target_sdk_version: "30", + apex_available: [ + "//apex_available:anyapex", + "//apex_available:platform", + ], + visibility: [ + "//frameworks/base/packages/Tethering", + "//frameworks/opt/net/ike", + "//frameworks/opt/net/wifi/service", + "//frameworks/opt/net/telephony", + "//packages/modules/NetworkStack", + "//packages/modules/CaptivePortalLogin", + "//frameworks/libs/net/common/tests:__subpackages__", + ], + libs: [ + "androidx.annotation_annotation", + ], +} + +java_library { + // Consider using net-tests-utils instead if writing device code. + // That library has a lot more useful tools into it for users that + // work on Android and includes this lib. + name: "net-tests-utils-host-device-common", + srcs: [ + "hostdevice/**/*.java", + "hostdevice/**/*.kt", + ], + host_supported: true, + visibility: [ + "//frameworks/libs/net/common/tests:__subpackages__", + ], + static_libs: [ + "kotlin-test" + ] +} + +java_defaults { + name: "lib_mockito_extended", + static_libs: [ + "mockito-target-extended-minus-junit4" + ], + jni_libs: [ + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", + ], +} + +java_library { + name: "net-tests-utils", + srcs: [ + "devicetests/**/*.java", + "devicetests/**/*.kt", + ], + defaults: ["lib_mockito_extended"], + libs: [ + "androidx.annotation_annotation", + ], + static_libs: [ + "androidx.test.ext.junit", + "net-tests-utils-host-device-common", + "net-utils-device-common", + ], +} + filegroup { name: "net-utils-framework-common-srcs", - srcs: ["src_frameworkcommon/**/*.java"], - path: "src_frameworkcommon", + srcs: ["framework/**/*.java"], + path: "framework", visibility: ["//frameworks/base"], } @@ -49,7 +125,7 @@ java_library { "//frameworks/base/packages/Tethering", "//frameworks/opt/net/ike", "//frameworks/opt/telephony", - "//packages/modules/NetworkStack", + "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", ] @@ -58,17 +134,12 @@ java_library { java_library { name: "net-utils-services-common", srcs: [ - "src_servicescommon/**/*.java", + "device/android/net/NetworkFactory.java", ":framework-annotations", ], sdk_version: "system_current", visibility: [ "//frameworks/base/services/net", - "//frameworks/base/packages/Tethering", - "//frameworks/opt/net/ike", - "//packages/modules/NetworkStack", - "//packages/modules/CaptivePortalLogin", - "//frameworks/libs/net/common/tests:__subpackages__", ], } @@ -78,9 +149,9 @@ filegroup { name: "net-utils-telephony-common-srcs", srcs: [ // Any class here *must* have a corresponding jarjar rule in the telephony build rules. - "src_servicescommon/android/net/NetworkFactory.java", + "device/android/net/NetworkFactory.java", ], - path: "src_servicescommon", + path: "device", visibility: [ "//frameworks/opt/telephony", ], @@ -92,11 +163,11 @@ filegroup { filegroup { name: "net-utils-framework-wifi-common-srcs", srcs: [ - "src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java", - "src_frameworkcommon/android/net/util/MacAddressUtils.java", - "src_frameworkcommon/com/android/net/module/util/**/*.java", + "framework/android/net/util/nsd/DnsSdTxtRecord.java", + "framework/android/net/util/MacAddressUtils.java", + "framework/com/android/net/module/util/**/*.java", ], - path: "src_frameworkcommon", + path: "framework", visibility: [ "//frameworks/base", ], @@ -108,8 +179,8 @@ filegroup { filegroup { name: "net-utils-wifi-service-common-srcs", srcs: [ - "src_frameworkcommon/android/net/util/NetUtils.java", - "src_servicescommon/android/net/NetworkFactory.java", + "device/android/net/NetworkFactory.java", + "framework/android/net/util/NetUtils.java", ], visibility: [ "//frameworks/opt/net/wifi/service", diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/device/android/net/NetworkFactory.java similarity index 100% rename from staticlibs/src_servicescommon/android/net/NetworkFactory.java rename to staticlibs/device/android/net/NetworkFactory.java diff --git a/staticlibs/device/android/net/util/FdEventsReader.java b/staticlibs/device/android/net/util/FdEventsReader.java new file mode 100644 index 0000000000..a5714aa5db --- /dev/null +++ b/staticlibs/device/android/net/util/FdEventsReader.java @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2016 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. + */ + +// TODO : move this and PacketReader to com.android.net.module.util. +package android.net.util; + +import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; +import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; + +import android.os.Handler; +import android.os.Looper; +import android.os.MessageQueue; +import android.system.ErrnoException; +import android.system.OsConstants; +import android.util.Log; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.FileDescriptor; +import java.io.IOException; + + +/** + * This class encapsulates the mechanics of registering a file descriptor + * with a thread's Looper and handling read events (and errors). + * + * Subclasses MUST implement createFd() and SHOULD override handlePacket(). They MAY override + * onStop() and onStart(). + * + * Subclasses can expect a call life-cycle like the following: + * + * [1] when a client calls start(), createFd() is called, followed by the onStart() hook if all + * goes well. Implementations may override onStart() for additional initialization. + * + * [2] yield, waiting for read event or error notification: + * + * [a] readPacket() && handlePacket() + * + * [b] if (no error): + * goto 2 + * else: + * goto 3 + * + * [3] when a client calls stop(), the onStop() hook is called (unless already stopped or never + * started). Implementations may override onStop() for additional cleanup. + * + * The packet receive buffer is recycled on every read call, so subclasses + * should make any copies they would like inside their handlePacket() + * implementation. + * + * All public methods MUST only be called from the same thread with which + * the Handler constructor argument is associated. + * + * @param the type of the buffer used to read data. + */ +public abstract class FdEventsReader { + private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR; + private static final int UNREGISTER_THIS_FD = 0; + + @NonNull + private final Handler mHandler; + @NonNull + private final MessageQueue mQueue; + @NonNull + private final BufferType mBuffer; + @Nullable + private FileDescriptor mFd; + private long mPacketsReceived; + + protected static void closeFd(FileDescriptor fd) { + try { + SocketUtils.closeSocket(fd); + } catch (IOException ignored) { + } + } + + protected FdEventsReader(@NonNull Handler h, @NonNull BufferType buffer) { + mHandler = h; + mQueue = mHandler.getLooper().getQueue(); + mBuffer = buffer; + } + + @VisibleForTesting + @NonNull + protected MessageQueue getMessageQueue() { + return mQueue; + } + + /** Start this FdEventsReader. */ + public boolean start() { + if (!onCorrectThread()) { + throw new IllegalStateException("start() called from off-thread"); + } + + return createAndRegisterFd(); + } + + /** Stop this FdEventsReader and destroy the file descriptor. */ + public void stop() { + if (!onCorrectThread()) { + throw new IllegalStateException("stop() called from off-thread"); + } + + unregisterAndDestroyFd(); + } + + @NonNull + public Handler getHandler() { + return mHandler; + } + + protected abstract int recvBufSize(@NonNull BufferType buffer); + + /** Returns the size of the receive buffer. */ + public int recvBufSize() { + return recvBufSize(mBuffer); + } + + /** + * Get the number of successful calls to {@link #readPacket(FileDescriptor, Object)}. + * + *

A call was successful if {@link #readPacket(FileDescriptor, Object)} returned a value > 0. + */ + public final long numPacketsReceived() { + return mPacketsReceived; + } + + /** + * Subclasses MUST create the listening socket here, including setting all desired socket + * options, interface or address/port binding, etc. The socket MUST be created nonblocking. + */ + @Nullable + protected abstract FileDescriptor createFd(); + + /** + * Implementations MUST return the bytes read or throw an Exception. + * + *

The caller may throw a {@link ErrnoException} with {@link OsConstants#EAGAIN} or + * {@link OsConstants#EINTR}, in which case {@link FdEventsReader} will ignore the buffer + * contents and respectively wait for further input or retry the read immediately. For all other + * exceptions, the {@link FdEventsReader} will be stopped with no more interactions with this + * method. + */ + protected abstract int readPacket(@NonNull FileDescriptor fd, @NonNull BufferType buffer) + throws Exception; + + /** + * Called by the main loop for every packet. Any desired copies of + * |recvbuf| should be made in here, as the underlying byte array is + * reused across all reads. + */ + protected void handlePacket(@NonNull BufferType recvbuf, int length) {} + + /** + * Called by the main loop to log errors. In some cases |e| may be null. + */ + protected void logError(@NonNull String msg, @Nullable Exception e) {} + + /** + * Called by start(), if successful, just prior to returning. + */ + protected void onStart() {} + + /** + * Called by stop() just prior to returning. + */ + protected void onStop() {} + + private boolean createAndRegisterFd() { + if (mFd != null) return true; + + try { + mFd = createFd(); + } catch (Exception e) { + logError("Failed to create socket: ", e); + closeFd(mFd); + mFd = null; + } + + if (mFd == null) return false; + + getMessageQueue().addOnFileDescriptorEventListener( + mFd, + FD_EVENTS, + (fd, events) -> { + // Always call handleInput() so read/recvfrom are given + // a proper chance to encounter a meaningful errno and + // perhaps log a useful error message. + if (!isRunning() || !handleInput()) { + unregisterAndDestroyFd(); + return UNREGISTER_THIS_FD; + } + return FD_EVENTS; + }); + onStart(); + return true; + } + + private boolean isRunning() { + return (mFd != null) && mFd.valid(); + } + + // Keep trying to read until we get EAGAIN/EWOULDBLOCK or some fatal error. + private boolean handleInput() { + while (isRunning()) { + final int bytesRead; + + try { + bytesRead = readPacket(mFd, mBuffer); + if (bytesRead < 1) { + if (isRunning()) logError("Socket closed, exiting", null); + break; + } + mPacketsReceived++; + } catch (ErrnoException e) { + if (e.errno == OsConstants.EAGAIN) { + // We've read everything there is to read this time around. + return true; + } else if (e.errno == OsConstants.EINTR) { + continue; + } else { + if (isRunning()) logError("readPacket error: ", e); + break; + } + } catch (Exception e) { + if (isRunning()) logError("readPacket error: ", e); + break; + } + + try { + handlePacket(mBuffer, bytesRead); + } catch (Exception e) { + logError("handlePacket error: ", e); + Log.wtf(FdEventsReader.class.getSimpleName(), "Error handling packet", e); + } + } + + return false; + } + + private void unregisterAndDestroyFd() { + if (mFd == null) return; + + getMessageQueue().removeOnFileDescriptorEventListener(mFd); + closeFd(mFd); + mFd = null; + onStop(); + } + + private boolean onCorrectThread() { + return (mHandler.getLooper() == Looper.myLooper()); + } +} diff --git a/staticlibs/device/android/net/util/PacketReader.java b/staticlibs/device/android/net/util/PacketReader.java new file mode 100644 index 0000000000..61b3d6e294 --- /dev/null +++ b/staticlibs/device/android/net/util/PacketReader.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 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. + */ + +// TODO : move this and FdEventsReader to com.android.net.module.util. +package android.net.util; + +import static java.lang.Math.max; + +import android.os.Handler; +import android.system.Os; + +import java.io.FileDescriptor; + +/** + * Specialization of {@link FdEventsReader} that reads packets into a byte array. + * + * TODO: rename this class to something more correctly descriptive (something + * like [or less horrible than] FdReadEventsHandler?). + */ +public abstract class PacketReader extends FdEventsReader { + + public static final int DEFAULT_RECV_BUF_SIZE = 2 * 1024; + + protected PacketReader(Handler h) { + this(h, DEFAULT_RECV_BUF_SIZE); + } + + protected PacketReader(Handler h, int recvBufSize) { + super(h, new byte[max(recvBufSize, DEFAULT_RECV_BUF_SIZE)]); + } + + @Override + protected final int recvBufSize(byte[] buffer) { + return buffer.length; + } + + /** + * Subclasses MAY override this to change the default read() implementation + * in favour of, say, recvfrom(). + * + * Implementations MUST return the bytes read or throw an Exception. + */ + @Override + protected int readPacket(FileDescriptor fd, byte[] packetBuffer) throws Exception { + return Os.read(fd, packetBuffer, 0, packetBuffer.length); + } +} diff --git a/staticlibs/devicetests/com/android/testutils/ConcurrentInterpreter.kt b/staticlibs/devicetests/com/android/testutils/ConcurrentInterpreter.kt new file mode 100644 index 0000000000..98464eb002 --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/ConcurrentInterpreter.kt @@ -0,0 +1,188 @@ +package com.android.testutils + +import android.os.SystemClock +import java.util.concurrent.CyclicBarrier +import kotlin.system.measureTimeMillis +import kotlin.test.assertEquals +import kotlin.test.assertFails +import kotlin.test.assertNull +import kotlin.test.assertTrue + +// The table contains pairs associating a regexp with the code to run. The statement is matched +// against each matcher in sequence and when a match is found the associated code is run, passing +// it the TrackRecord under test and the result of the regexp match. +typealias InterpretMatcher = Pair, T, MatchResult) -> Any?> + +// The default unit of time for interpreted tests +val INTERPRET_TIME_UNIT = 40L // ms + +/** + * A small interpreter for testing parallel code. The interpreter will read a list of lines + * consisting of "|"-separated statements. Each column runs in a different concurrent thread + * and all threads wait for each other in between lines. Each statement is split on ";" then + * matched with regular expressions in the instructionTable constant, which contains the + * code associated with each statement. The interpreter supports an object being passed to + * the interpretTestSpec() method to be passed in each lambda (think about the object under + * test), and an optional transform function to be executed on the object at the start of + * every thread. + * + * The time unit is defined in milliseconds by the interpretTimeUnit member, which has a default + * value but can be passed to the constructor. Whitespace is ignored. + * + * The interpretation table has to be passed as an argument. It's a table associating a regexp + * with the code that should execute, as a function taking three arguments : the interpreter, + * the regexp match, and the object. See the individual tests for the DSL of that test. + * Implementors for new interpreting languages are encouraged to look at the defaultInterpretTable + * constant below for an example of how to write an interpreting table. + * Some expressions already exist by default and can be used by all interpreters. They include : + * sleep(x) : sleeps for x time units and returns Unit ; sleep alone means sleep(1) + * EXPR = VALUE : asserts that EXPR equals VALUE. EXPR is interpreted. VALUE can either be the + * string "null" or an int. Returns Unit. + * EXPR time x..y : measures the time taken by EXPR and asserts it took at least x and at most + * y time units. + * EXPR // any text : comments are ignored. + */ +open class ConcurrentInterpreter( + localInterpretTable: List>, + val interpretTimeUnit: Long = INTERPRET_TIME_UNIT +) { + private val interpretTable: List> = + localInterpretTable + getDefaultInstructions() + + // Split the line into multiple statements separated by ";" and execute them. Return whatever + // the last statement returned. + fun interpretMultiple(instr: String, r: T): Any? { + return instr.split(";").map { interpret(it.trim(), r) }.last() + } + + // Match the statement to a regex and interpret it. + fun interpret(instr: String, r: T): Any? { + val (matcher, code) = + interpretTable.find { instr matches it.first } ?: throw SyntaxException(instr) + val match = matcher.matchEntire(instr) ?: throw SyntaxException(instr) + return code(this, r, match) + } + + // Spins as many threads as needed by the test spec and interpret each program concurrently, + // having all threads waiting on a CyclicBarrier after each line. + // |lineShift| says how many lines after the call the spec starts. This is used for error + // reporting. Unfortunately AFAICT there is no way to get the line of an argument rather + // than the line at which the expression starts. + fun interpretTestSpec( + spec: String, + initial: T, + lineShift: Int = 0, + threadTransform: (T) -> T = { it } + ) { + // For nice stack traces + val callSite = getCallingMethod() + val lines = spec.trim().trim('\n').split("\n").map { it.split("|") } + // |threads| contains arrays of strings that make up the statements of a thread : in other + // words, it's an array that contains a list of statements for each column in the spec. + val threadCount = lines[0].size + assertTrue(lines.all { it.size == threadCount }) + val threadInstructions = (0 until threadCount).map { i -> lines.map { it[i].trim() } } + val barrier = CyclicBarrier(threadCount) + var crash: InterpretException? = null + threadInstructions.mapIndexed { threadIndex, instructions -> + Thread { + val threadLocal = threadTransform(initial) + barrier.await() + var lineNum = 0 + instructions.forEach { + if (null != crash) return@Thread + lineNum += 1 + try { + interpretMultiple(it, threadLocal) + } catch (e: Throwable) { + // If fail() or some exception was called, the thread will come here ; if + // the exception isn't caught the process will crash, which is not nice for + // testing. Instead, catch the exception, cancel other threads, and report + // nicely. Catch throwable because fail() is AssertionError, which inherits + // from Error. + crash = InterpretException(threadIndex, it, + callSite.lineNumber + lineNum + lineShift, + callSite.className, callSite.methodName, callSite.fileName, e) + } + barrier.await() + } + }.also { it.start() } + }.forEach { it.join() } + // If the test failed, crash with line number + crash?.let { throw it } + } + + // Helper to get the stack trace for a calling method + private fun getCallingStackTrace(): Array { + try { + throw RuntimeException() + } catch (e: RuntimeException) { + return e.stackTrace + } + } + + // Find the calling method. This is the first method in the stack trace that is annotated + // with @Test. + fun getCallingMethod(): StackTraceElement { + val stackTrace = getCallingStackTrace() + return stackTrace.find { element -> + val clazz = Class.forName(element.className) + // Because the stack trace doesn't list the formal arguments, find all methods with + // this name and return this name if any of them is annotated with @Test. + clazz.declaredMethods + .filter { method -> method.name == element.methodName } + .any { method -> method.getAnnotation(org.junit.Test::class.java) != null } + } ?: stackTrace[3] + // If no method is annotated return the 4th one, because that's what it usually is : + // 0 is getCallingStackTrace, 1 is this method, 2 is ConcurrentInterpreter#interpretTestSpec + } +} + +private fun getDefaultInstructions() = listOf>( + // Interpret an empty line as doing nothing. + Regex("") to { _, _, _ -> null }, + // Ignore comments. + Regex("(.*)//.*") to { i, t, r -> i.interpret(r.strArg(1), t) }, + // Interpret "XXX time x..y" : run XXX and check it took at least x and not more than y + Regex("""(.*)\s*time\s*(\d+)\.\.(\d+)""") to { i, t, r -> + val time = measureTimeMillis { i.interpret(r.strArg(1), t) } + assertTrue(time in r.timeArg(2)..r.timeArg(3), "$time not in ${r.timeArg(2)..r.timeArg(3)}") + }, + // Interpret "XXX = YYY" : run XXX and assert its return value is equal to YYY. "null" supported + Regex("""(.*)\s*=\s*(null|\d+)""") to { i, t, r -> + i.interpret(r.strArg(1), t).also { + if ("null" == r.strArg(2)) assertNull(it) else assertEquals(r.intArg(2), it) + } + }, + // Interpret sleep. Optional argument for the count, in INTERPRET_TIME_UNIT units. + Regex("""sleep(\((\d+)\))?""") to { i, t, r -> + SystemClock.sleep(if (r.strArg(2).isEmpty()) i.interpretTimeUnit else r.timeArg(2)) + }, + Regex("""(.*)\s*fails""") to { i, t, r -> + assertFails { i.interpret(r.strArg(1), t) } + } +) + +class SyntaxException(msg: String, cause: Throwable? = null) : RuntimeException(msg, cause) +class InterpretException( + threadIndex: Int, + instr: String, + lineNum: Int, + className: String, + methodName: String, + fileName: String, + cause: Throwable +) : RuntimeException("Failure: $instr", cause) { + init { + stackTrace = arrayOf(StackTraceElement( + className, + "$methodName:thread$threadIndex", + fileName, + lineNum)) + super.getStackTrace() + } +} + +// Some small helpers to avoid to say the large ".groupValues[index].trim()" every time +fun MatchResult.strArg(index: Int) = this.groupValues[index].trim() +fun MatchResult.intArg(index: Int) = strArg(index).toInt() +fun MatchResult.timeArg(index: Int) = INTERPRET_TIME_UNIT * intArg(index) diff --git a/staticlibs/devicetests/com/android/testutils/DevSdkIgnoreRule.kt b/staticlibs/devicetests/com/android/testutils/DevSdkIgnoreRule.kt new file mode 100644 index 0000000000..4a83f6fa1a --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/DevSdkIgnoreRule.kt @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2020 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 com.android.testutils + +import android.os.Build +import org.junit.Assume.assumeTrue +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runners.model.Statement + +/** + * Returns true if the development SDK version of the device is in the provided range. + * + * If the device is not using a release SDK, the development SDK is considered to be higher than + * [Build.VERSION.SDK_INT]. + */ +fun isDevSdkInRange(minExclusive: Int?, maxInclusive: Int?): Boolean { + // In-development API n+1 will have SDK_INT == n and CODENAME != REL. + // Stable API n has SDK_INT == n and CODENAME == REL. + val release = "REL" == Build.VERSION.CODENAME + val sdkInt = Build.VERSION.SDK_INT + val devApiLevel = sdkInt + if (release) 0 else 1 + + return (minExclusive == null || devApiLevel > minExclusive) && + (maxInclusive == null || devApiLevel <= maxInclusive) +} + +/** + * A test rule to ignore tests based on the development SDK level. + * + * If the device is not using a release SDK, the development SDK is considered to be higher than + * [Build.VERSION.SDK_INT]. + * + * @param ignoreClassUpTo Skip all tests in the class if the device dev SDK is <= this value. + * @param ignoreClassAfter Skip all tests in the class if the device dev SDK is > this value. + */ +class DevSdkIgnoreRule @JvmOverloads constructor( + private val ignoreClassUpTo: Int? = null, + private val ignoreClassAfter: Int? = null +) : TestRule { + override fun apply(base: Statement, description: Description): Statement { + return IgnoreBySdkStatement(base, description) + } + + /** + * Ignore the test for any development SDK that is strictly after [value]. + * + * If the device is not using a release SDK, the development SDK is considered to be higher + * than [Build.VERSION.SDK_INT]. + */ + annotation class IgnoreAfter(val value: Int) + + /** + * Ignore the test for any development SDK that lower than or equal to [value]. + * + * If the device is not using a release SDK, the development SDK is considered to be higher + * than [Build.VERSION.SDK_INT]. + */ + annotation class IgnoreUpTo(val value: Int) + + private inner class IgnoreBySdkStatement( + private val base: Statement, + private val description: Description + ) : Statement() { + override fun evaluate() { + val ignoreAfter = description.getAnnotation(IgnoreAfter::class.java) + val ignoreUpTo = description.getAnnotation(IgnoreUpTo::class.java) + + val message = "Skipping test for build ${Build.VERSION.CODENAME} " + + "with SDK ${Build.VERSION.SDK_INT}" + assumeTrue(message, isDevSdkInRange(ignoreClassUpTo, ignoreClassAfter)) + assumeTrue(message, isDevSdkInRange(ignoreUpTo?.value, ignoreAfter?.value)) + base.evaluate() + } + } +} \ No newline at end of file diff --git a/staticlibs/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt b/staticlibs/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt new file mode 100644 index 0000000000..73b2843f83 --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2020 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 com.android.testutils + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import org.junit.runner.Description +import org.junit.runner.Runner +import org.junit.runner.notification.RunNotifier + +/** + * A runner that can skip tests based on the development SDK as defined in [DevSdkIgnoreRule]. + * + * Generally [DevSdkIgnoreRule] should be used for that purpose (using rules is preferable over + * replacing the test runner), however JUnit runners inspect all methods in the test class before + * processing test rules. This may cause issues if the test methods are referencing classes that do + * not exist on the SDK of the device the test is run on. + * + * This runner inspects [IgnoreAfter] and [IgnoreUpTo] annotations on the test class, and will skip + * the whole class if they do not match the development SDK as defined in [DevSdkIgnoreRule]. + * Otherwise, it will delegate to [AndroidJUnit4] to run the test as usual. + * + * Example usage: + * + * @RunWith(DevSdkIgnoreRunner::class) + * @IgnoreUpTo(Build.VERSION_CODES.Q) + * class MyTestClass { ... } + */ +class DevSdkIgnoreRunner(private val klass: Class<*>) : Runner() { + private val baseRunner = klass.let { + val ignoreAfter = it.getAnnotation(IgnoreAfter::class.java) + val ignoreUpTo = it.getAnnotation(IgnoreUpTo::class.java) + + if (isDevSdkInRange(ignoreUpTo?.value, ignoreAfter?.value)) AndroidJUnit4(klass) else null + } + + override fun run(notifier: RunNotifier) { + if (baseRunner != null) { + baseRunner.run(notifier) + return + } + + // Report a single, skipped placeholder test for this class, so that the class is still + // visible as skipped in test results. + notifier.fireTestIgnored( + Description.createTestDescription(klass, "skippedClassForDevSdkMismatch")) + } + + override fun getDescription(): Description { + return baseRunner?.description ?: Description.createSuiteDescription(klass) + } + + override fun testCount(): Int { + // When ignoring the tests, a skipped placeholder test is reported, so test count is 1. + return baseRunner?.testCount() ?: 1 + } +} \ No newline at end of file diff --git a/staticlibs/devicetests/com/android/testutils/FakeDns.kt b/staticlibs/devicetests/com/android/testutils/FakeDns.kt new file mode 100644 index 0000000000..825d74878e --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/FakeDns.kt @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2019 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 com.android.testutils + +import android.net.DnsResolver +import android.net.InetAddresses +import android.os.Looper +import android.os.Handler +import com.android.internal.annotations.GuardedBy +import java.net.InetAddress +import java.util.concurrent.Executor +import org.mockito.invocation.InvocationOnMock +import org.mockito.Mockito.any +import org.mockito.Mockito.anyInt +import org.mockito.Mockito.doAnswer + +const val TYPE_UNSPECIFIED = -1 +// TODO: Integrate with NetworkMonitorTest. +class FakeDns(val mockResolver: DnsResolver) { + class DnsEntry(val hostname: String, val type: Int, val addresses: List) { + fun match(host: String, type: Int) = hostname.equals(host) && type == type + } + + @GuardedBy("answers") + val answers = ArrayList() + + fun getAnswer(hostname: String, type: Int): DnsEntry? = synchronized(answers) { + return answers.firstOrNull { it.match(hostname, type) } + } + + fun setAnswer(hostname: String, answer: Array, type: Int) = synchronized(answers) { + val ans = DnsEntry(hostname, type, generateAnswer(answer)) + // Replace or remove the existing one. + when (val index = answers.indexOfFirst { it.match(hostname, type) }) { + -1 -> answers.add(ans) + else -> answers[index] = ans + } + } + + private fun generateAnswer(answer: Array) = + answer.filterNotNull().map { InetAddresses.parseNumericAddress(it) } + + fun startMocking() { + // Mock DnsResolver.query() w/o type + doAnswer { + mockAnswer(it, 1, -1, 3, 5) + }.`when`(mockResolver).query(any() /* network */, any() /* domain */, anyInt() /* flags */, + any() /* executor */, any() /* cancellationSignal */, any() /*callback*/) + // Mock DnsResolver.query() w/ type + doAnswer { + mockAnswer(it, 1, 2, 4, 6) + }.`when`(mockResolver).query(any() /* network */, any() /* domain */, anyInt() /* nsType */, + anyInt() /* flags */, any() /* executor */, any() /* cancellationSignal */, + any() /*callback*/) + } + + private fun mockAnswer( + it: InvocationOnMock, + posHos: Int, + posType: Int, + posExecutor: Int, + posCallback: Int + ) { + val hostname = it.arguments[posHos] as String + val executor = it.arguments[posExecutor] as Executor + val callback = it.arguments[posCallback] as DnsResolver.Callback> + var type = if (posType != -1) it.arguments[posType] as Int else TYPE_UNSPECIFIED + val answer = getAnswer(hostname, type) + + if (!answer?.addresses.isNullOrEmpty()) { + Handler(Looper.getMainLooper()).post({ executor.execute({ + callback.onAnswer(answer?.addresses, 0); }) }) + } + } + + /** Clears all entries. */ + fun clearAll() = synchronized(answers) { + answers.clear() + } +} diff --git a/staticlibs/devicetests/com/android/testutils/HandlerUtils.kt b/staticlibs/devicetests/com/android/testutils/HandlerUtils.kt new file mode 100644 index 0000000000..fa36209462 --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/HandlerUtils.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019 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 com.android.testutils + +import android.os.ConditionVariable +import android.os.Handler +import android.os.HandlerThread +import java.util.concurrent.Executor +import kotlin.system.measureTimeMillis +import kotlin.test.fail + +/** + * Block until the specified Handler or HandlerThread becomes idle, or until timeoutMs has passed. + */ +fun HandlerThread.waitForIdle(timeoutMs: Int) = threadHandler.waitForIdle(timeoutMs.toLong()) +fun HandlerThread.waitForIdle(timeoutMs: Long) = threadHandler.waitForIdle(timeoutMs) +fun Handler.waitForIdle(timeoutMs: Int) = waitForIdle(timeoutMs.toLong()) +fun Handler.waitForIdle(timeoutMs: Long) { + val cv = ConditionVariable(false) + post(cv::open) + if (!cv.block(timeoutMs)) { + fail("Handler did not become idle after ${timeoutMs}ms") + } +} + +/** + * Block until the given Serial Executor becomes idle, or until timeoutMs has passed. + */ +fun waitForIdleSerialExecutor(executor: Executor, timeoutMs: Long) { + val cv = ConditionVariable() + executor.execute(cv::open) + if (!cv.block(timeoutMs)) { + fail("Executor did not become idle after ${timeoutMs}ms") + } +} diff --git a/staticlibs/devicetests/com/android/testutils/NetworkStatsUtils.kt b/staticlibs/devicetests/com/android/testutils/NetworkStatsUtils.kt new file mode 100644 index 0000000000..8324b25ee3 --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/NetworkStatsUtils.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2020 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 com.android.testutils + +import android.net.NetworkStats +import kotlin.test.assertTrue + +@JvmOverloads +fun orderInsensitiveEquals( + leftStats: NetworkStats, + rightStats: NetworkStats, + compareTime: Boolean = false +): Boolean { + if (leftStats == rightStats) return true + if (compareTime && leftStats.getElapsedRealtime() != rightStats.getElapsedRealtime()) { + return false + } + + // While operations such as add/subtract will preserve empty entries. This will make + // the result be hard to verify during test. Remove them before comparing since they + // are not really affect correctness. + // TODO (b/152827872): Remove empty entries after addition/subtraction. + val leftTrimmedEmpty = leftStats.removeEmptyEntries() + val rightTrimmedEmpty = rightStats.removeEmptyEntries() + + if (leftTrimmedEmpty.size() != rightTrimmedEmpty.size()) return false + val left = NetworkStats.Entry() + val right = NetworkStats.Entry() + // Order insensitive compare. + for (i in 0 until leftTrimmedEmpty.size()) { + leftTrimmedEmpty.getValues(i, left) + val j: Int = rightTrimmedEmpty.findIndexHinted(left.iface, left.uid, left.set, left.tag, + left.metered, left.roaming, left.defaultNetwork, i) + if (j == -1) return false + rightTrimmedEmpty.getValues(j, right) + if (left != right) return false + } + return true +} + +/** + * Assert that two {@link NetworkStats} are equals, assuming the order of the records are not + * necessarily the same. + * + * @note {@code elapsedRealtime} is not compared by default, given that in test cases that is not + * usually used. + */ +@JvmOverloads +fun assertNetworkStatsEquals( + expected: NetworkStats, + actual: NetworkStats, + compareTime: Boolean = false +) { + assertTrue(orderInsensitiveEquals(expected, actual, compareTime), + "expected: " + expected + " but was: " + actual) +} + +/** + * Assert that after being parceled then unparceled, {@link NetworkStats} is equal to the original + * object. + */ +fun assertParcelingIsLossless(stats: NetworkStats) { + assertParcelingIsLossless(stats, { a, b -> orderInsensitiveEquals(a, b) }) +} diff --git a/staticlibs/devicetests/com/android/testutils/ParcelUtils.kt b/staticlibs/devicetests/com/android/testutils/ParcelUtils.kt new file mode 100644 index 0000000000..5784f7cbcc --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/ParcelUtils.kt @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2019 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 com.android.testutils + +import android.os.Parcel +import android.os.Parcelable +import kotlin.test.assertTrue +import kotlin.test.fail + +/** + * Return a new instance of `T` after being parceled then unparceled. + */ +fun parcelingRoundTrip(source: T): T { + val creator: Parcelable.Creator + try { + creator = source.javaClass.getField("CREATOR").get(null) as Parcelable.Creator + } catch (e: IllegalAccessException) { + fail("Missing CREATOR field: " + e.message) + } catch (e: NoSuchFieldException) { + fail("Missing CREATOR field: " + e.message) + } + + var p = Parcel.obtain() + source.writeToParcel(p, /* flags */ 0) + p.setDataPosition(0) + val marshalled = p.marshall() + p = Parcel.obtain() + p.unmarshall(marshalled, 0, marshalled.size) + p.setDataPosition(0) + return creator.createFromParcel(p) +} + +/** + * Assert that after being parceled then unparceled, `source` is equal to the original + * object. If a customized equals function is provided, uses the provided one. + */ +@JvmOverloads +fun assertParcelingIsLossless( + source: T, + equals: (T, T) -> Boolean = { a, b -> a == b } +) { + val actual = parcelingRoundTrip(source) + assertTrue(equals(source, actual), "Expected $source, but was $actual") +} + +@JvmOverloads +fun assertParcelSane( + obj: T, + fieldCount: Int, + equals: (T, T) -> Boolean = { a, b -> a == b } +) { + assertFieldCountEquals(fieldCount, obj::class.java) + assertParcelingIsLossless(obj, equals) +} diff --git a/staticlibs/devicetests/com/android/testutils/TapPacketReader.java b/staticlibs/devicetests/com/android/testutils/TapPacketReader.java new file mode 100644 index 0000000000..fea1cd9a5a --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/TapPacketReader.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2020 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 com.android.testutils; + +import android.net.util.PacketReader; +import android.os.Handler; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.net.module.util.ArrayTrackRecord; + +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.function.Predicate; + +import kotlin.Lazy; +import kotlin.LazyKt; + +public class TapPacketReader extends PacketReader { + private final FileDescriptor mTapFd; + private final ArrayTrackRecord mReceivedPackets = new ArrayTrackRecord<>(); + private final Lazy.ReadHead> mReadHead = + LazyKt.lazy(mReceivedPackets::newReadHead); + + public TapPacketReader(Handler h, FileDescriptor tapFd, int maxPacketSize) { + super(h, maxPacketSize); + mTapFd = tapFd; + } + + @Override + protected FileDescriptor createFd() { + return mTapFd; + } + + @Override + protected void handlePacket(byte[] recvbuf, int length) { + final byte[] newPacket = Arrays.copyOf(recvbuf, length); + if (!mReceivedPackets.add(newPacket)) { + throw new AssertionError("More than " + Integer.MAX_VALUE + " packets outstanding!"); + } + } + + /** + * Get the next packet that was received on the interface. + */ + @Nullable + public byte[] popPacket(long timeoutMs) { + return mReadHead.getValue().poll(timeoutMs, packet -> true); + } + + /** + * Get the next packet that was received on the interface and matches the specified filter. + */ + @Nullable + public byte[] popPacket(long timeoutMs, @NonNull Predicate filter) { + return mReadHead.getValue().poll(timeoutMs, filter::test); + } + + /** + * Get the {@link ArrayTrackRecord} that records all packets received by the reader since its + * creation. + */ + public ArrayTrackRecord getReceivedPackets() { + return mReceivedPackets; + } + + public void sendResponse(final ByteBuffer packet) throws IOException { + try (FileOutputStream out = new FileOutputStream(mTapFd)) { + byte[] packetBytes = new byte[packet.limit()]; + packet.get(packetBytes); + packet.flip(); // So we can reuse it in the future. + out.write(packetBytes); + } + } +} diff --git a/staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt b/staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt new file mode 100644 index 0000000000..4bd9ae8eae --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2020 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 com.android.testutils + +import android.content.Context +import android.net.ConnectivityManager +import android.net.ConnectivityManager.NetworkCallback +import android.net.LinkAddress +import android.net.Network +import android.net.NetworkCapabilities +import android.net.NetworkRequest +import android.net.StringNetworkSpecifier +import android.net.TestNetworkInterface +import android.net.TestNetworkManager +import android.os.Binder +import java.util.concurrent.CompletableFuture +import java.util.concurrent.TimeUnit + +/** + * Create a test network based on a TUN interface. + * + * This method will block until the test network is available. Requires + * [android.Manifest.permission.CHANGE_NETWORK_STATE] and + * [android.Manifest.permission.MANAGE_TEST_NETWORKS]. + */ +fun initTestNetwork(context: Context, interfaceAddr: LinkAddress, setupTimeoutMs: Long = 10_000L): + TestNetworkTracker { + val tnm = context.getSystemService(TestNetworkManager::class.java) + val iface = tnm.createTunInterface(arrayOf(interfaceAddr)) + return TestNetworkTracker(context, iface, tnm, setupTimeoutMs) +} + +/** + * Utility class to create and track test networks. + * + * This class is not thread-safe. + */ +class TestNetworkTracker internal constructor( + val context: Context, + val iface: TestNetworkInterface, + tnm: TestNetworkManager, + setupTimeoutMs: Long +) { + private val cm = context.getSystemService(ConnectivityManager::class.java) + private val binder = Binder() + + private val networkCallback: NetworkCallback + val network: Network + + init { + val networkFuture = CompletableFuture() + val networkRequest = NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + // Test networks do not have NOT_VPN or TRUSTED capabilities by default + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .setNetworkSpecifier(StringNetworkSpecifier(iface.interfaceName)) + .build() + networkCallback = object : NetworkCallback() { + override fun onAvailable(network: Network) { + networkFuture.complete(network) + } + } + cm.requestNetwork(networkRequest, networkCallback) + + try { + tnm.setupTestNetwork(iface.interfaceName, binder) + network = networkFuture.get(setupTimeoutMs, TimeUnit.MILLISECONDS) + } catch (e: Throwable) { + teardown() + throw e + } + } + + fun teardown() { + cm.unregisterNetworkCallback(networkCallback) + } +} \ No newline at end of file diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt new file mode 100644 index 0000000000..959a837d4a --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2019 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 com.android.testutils + +import android.net.ConnectivityManager.NetworkCallback +import android.net.LinkProperties +import android.net.Network +import android.net.NetworkCapabilities +import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED +import com.android.net.module.util.ArrayTrackRecord +import com.android.testutils.RecorderCallback.CallbackEntry.Available +import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatus +import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged +import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged +import com.android.testutils.RecorderCallback.CallbackEntry.Losing +import com.android.testutils.RecorderCallback.CallbackEntry.Lost +import com.android.testutils.RecorderCallback.CallbackEntry.Resumed +import com.android.testutils.RecorderCallback.CallbackEntry.Suspended +import com.android.testutils.RecorderCallback.CallbackEntry.Unavailable +import kotlin.reflect.KClass +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertTrue +import kotlin.test.fail + +object NULL_NETWORK : Network(-1) +object ANY_NETWORK : Network(-2) + +private val Int.capabilityName get() = NetworkCapabilities.capabilityNameOf(this) + +open class RecorderCallback private constructor( + private val backingRecord: ArrayTrackRecord +) : NetworkCallback() { + public constructor() : this(ArrayTrackRecord()) + protected constructor(src: RecorderCallback?): this(src?.backingRecord ?: ArrayTrackRecord()) + + sealed class CallbackEntry { + // To get equals(), hashcode(), componentN() etc for free, the child classes of + // this class are data classes. But while data classes can inherit from other classes, + // they may only have visible members in the constructors, so they couldn't declare + // a constructor with a non-val arg to pass to CallbackEntry. Instead, force all + // subclasses to implement a `network' property, which can be done in a data class + // constructor by specifying override. + abstract val network: Network + + data class Available(override val network: Network) : CallbackEntry() + data class CapabilitiesChanged( + override val network: Network, + val caps: NetworkCapabilities + ) : CallbackEntry() + data class LinkPropertiesChanged( + override val network: Network, + val lp: LinkProperties + ) : CallbackEntry() + data class Suspended(override val network: Network) : CallbackEntry() + data class Resumed(override val network: Network) : CallbackEntry() + data class Losing(override val network: Network, val maxMsToLive: Int) : CallbackEntry() + data class Lost(override val network: Network) : CallbackEntry() + data class Unavailable private constructor( + override val network: Network + ) : CallbackEntry() { + constructor() : this(NULL_NETWORK) + } + data class BlockedStatus( + override val network: Network, + val blocked: Boolean + ) : CallbackEntry() + + // Convenience constants for expecting a type + companion object { + @JvmField + val AVAILABLE = Available::class + @JvmField + val NETWORK_CAPS_UPDATED = CapabilitiesChanged::class + @JvmField + val LINK_PROPERTIES_CHANGED = LinkPropertiesChanged::class + @JvmField + val SUSPENDED = Suspended::class + @JvmField + val RESUMED = Resumed::class + @JvmField + val LOSING = Losing::class + @JvmField + val LOST = Lost::class + @JvmField + val UNAVAILABLE = Unavailable::class + @JvmField + val BLOCKED_STATUS = BlockedStatus::class + } + } + + val history = backingRecord.newReadHead() + val mark get() = history.mark + + override fun onAvailable(network: Network) { + history.add(Available(network)) + } + + // PreCheck is not used in the tests today. For backward compatibility with existing tests that + // expect the callbacks not to record this, do not listen to PreCheck here. + + override fun onCapabilitiesChanged(network: Network, caps: NetworkCapabilities) { + history.add(CapabilitiesChanged(network, caps)) + } + + override fun onLinkPropertiesChanged(network: Network, lp: LinkProperties) { + history.add(LinkPropertiesChanged(network, lp)) + } + + override fun onBlockedStatusChanged(network: Network, blocked: Boolean) { + history.add(BlockedStatus(network, blocked)) + } + + override fun onNetworkSuspended(network: Network) { + history.add(Suspended(network)) + } + + override fun onNetworkResumed(network: Network) { + history.add(Resumed(network)) + } + + override fun onLosing(network: Network, maxMsToLive: Int) { + history.add(Losing(network, maxMsToLive)) + } + + override fun onLost(network: Network) { + history.add(Lost(network)) + } + + override fun onUnavailable() { + history.add(Unavailable()) + } +} + +private const val DEFAULT_TIMEOUT = 200L // ms + +open class TestableNetworkCallback private constructor( + src: TestableNetworkCallback?, + val defaultTimeoutMs: Long = DEFAULT_TIMEOUT +) : RecorderCallback(src) { + @JvmOverloads + constructor(timeoutMs: Long = DEFAULT_TIMEOUT): this(null, timeoutMs) + + fun createLinkedCopy() = TestableNetworkCallback(this, defaultTimeoutMs) + + // The last available network, or null if any network was lost since the last call to + // onAvailable. TODO : fix this by fixing the tests that rely on this behavior + val lastAvailableNetwork: Network? + get() = when (val it = history.lastOrNull { it is Available || it is Lost }) { + is Available -> it.network + else -> null + } + + fun pollForNextCallback(timeoutMs: Long = defaultTimeoutMs): CallbackEntry { + return history.poll(timeoutMs) ?: fail("Did not receive callback after ${timeoutMs}ms") + } + + // Make open for use in ConnectivityServiceTest which is the only one knowing its handlers. + @JvmOverloads + open fun assertNoCallback(timeoutMs: Long = defaultTimeoutMs) { + val cb = history.poll(timeoutMs) + if (null != cb) fail("Expected no callback but got $cb") + } + + // Expects a callback of the specified type on the specified network within the timeout. + // If no callback arrives, or a different callback arrives, fail. Returns the callback. + inline fun expectCallback( + network: Network = ANY_NETWORK, + timeoutMs: Long = defaultTimeoutMs + ): T = pollForNextCallback(timeoutMs).let { + if (it !is T || (ANY_NETWORK !== network && it.network != network)) { + fail("Unexpected callback : $it, expected ${T::class} with Network[$network]") + } else { + it + } + } + + // Expects a callback of the specified type matching the predicate within the timeout. + // Any callback that doesn't match the predicate will be skipped. Fails only if + // no matching callback is received within the timeout. + inline fun eventuallyExpect( + timeoutMs: Long = defaultTimeoutMs, + from: Int = mark, + crossinline predicate: (T) -> Boolean = { true } + ): T = eventuallyExpectOrNull(timeoutMs, from, predicate).also { + assertNotNull(it, "Callback ${T::class} not received within ${timeoutMs}ms") + } as T + + // TODO (b/157405399) straighten and unify the method names + inline fun eventuallyExpectOrNull( + timeoutMs: Long = defaultTimeoutMs, + from: Int = mark, + crossinline predicate: (T) -> Boolean = { true } + ) = history.poll(timeoutMs, from) { it is T && predicate(it) } as T? + + fun expectCallbackThat( + timeoutMs: Long = defaultTimeoutMs, + valid: (CallbackEntry) -> Boolean + ) = pollForNextCallback(timeoutMs).also { assertTrue(valid(it), "Unexpected callback : $it") } + + fun expectCapabilitiesThat( + net: Network, + tmt: Long = defaultTimeoutMs, + valid: (NetworkCapabilities) -> Boolean + ): CapabilitiesChanged { + return expectCallback(net, tmt).also { + assertTrue(valid(it.caps), "Capabilities don't match expectations ${it.caps}") + } + } + + fun expectLinkPropertiesThat( + net: Network, + tmt: Long = defaultTimeoutMs, + valid: (LinkProperties) -> Boolean + ): LinkPropertiesChanged { + return expectCallback(net, tmt).also { + assertTrue(valid(it.lp), "LinkProperties don't match expectations ${it.lp}") + } + } + + // Expects onAvailable and the callbacks that follow it. These are: + // - onSuspended, iff the network was suspended when the callbacks fire. + // - onCapabilitiesChanged. + // - onLinkPropertiesChanged. + // - onBlockedStatusChanged. + // + // @param network the network to expect the callbacks on. + // @param suspended whether to expect a SUSPENDED callback. + // @param validated the expected value of the VALIDATED capability in the + // onCapabilitiesChanged callback. + // @param tmt how long to wait for the callbacks. + fun expectAvailableCallbacks( + net: Network, + suspended: Boolean = false, + validated: Boolean = true, + blocked: Boolean = false, + tmt: Long = defaultTimeoutMs + ) { + expectCallback(net, tmt) + if (suspended) { + expectCallback(net, tmt) + } + expectCapabilitiesThat(net, tmt) { validated == it.hasCapability(NET_CAPABILITY_VALIDATED) } + expectCallback(net, tmt) + expectBlockedStatusCallback(blocked, net) + } + + // Backward compatibility for existing Java code. Use named arguments instead and remove all + // these when there is no user left. + fun expectAvailableAndSuspendedCallbacks( + net: Network, + validated: Boolean, + tmt: Long = defaultTimeoutMs + ) = expectAvailableCallbacks(net, suspended = true, validated = validated, tmt = tmt) + + fun expectBlockedStatusCallback(blocked: Boolean, net: Network, tmt: Long = defaultTimeoutMs) { + expectCallback(net, tmt).also { + assertEquals(it.blocked, blocked, "Unexpected blocked status ${it.blocked}") + } + } + + // Expects the available callbacks (where the onCapabilitiesChanged must contain the + // VALIDATED capability), plus another onCapabilitiesChanged which is identical to the + // one we just sent. + // TODO: this is likely a bug. Fix it and remove this method. + fun expectAvailableDoubleValidatedCallbacks(net: Network, tmt: Long = defaultTimeoutMs) { + val mark = history.mark + expectAvailableCallbacks(net, tmt = tmt) + val firstCaps = history.poll(tmt, mark) { it is CapabilitiesChanged } + assertEquals(firstCaps, expectCallback(net, tmt)) + } + + // Expects the available callbacks where the onCapabilitiesChanged must not have validated, + // then expects another onCapabilitiesChanged that has the validated bit set. This is used + // when a network connects and satisfies a callback, and then immediately validates. + fun expectAvailableThenValidatedCallbacks(net: Network, tmt: Long = defaultTimeoutMs) { + expectAvailableCallbacks(net, validated = false, tmt = tmt) + expectCapabilitiesThat(net, tmt) { it.hasCapability(NET_CAPABILITY_VALIDATED) } + } + + // Temporary Java compat measure : have MockNetworkAgent implement this so that all existing + // calls with networkAgent can be routed through here without moving MockNetworkAgent. + // TODO: clean this up, remove this method. + interface HasNetwork { + val network: Network + } + + @JvmOverloads + open fun expectCallback( + type: KClass, + n: Network?, + timeoutMs: Long = defaultTimeoutMs + ) = pollForNextCallback(timeoutMs).also { + val network = n ?: NULL_NETWORK + // TODO : remove this .java access if the tests ever use kotlin-reflect. At the time of + // this writing this would be the only use of this library in the tests. + assertTrue(type.java.isInstance(it) && it.network == network, + "Unexpected callback : $it, expected ${type.java} with Network[$network]") + } as T + + @JvmOverloads + open fun expectCallback( + type: KClass, + n: HasNetwork?, + timeoutMs: Long = defaultTimeoutMs + ) = expectCallback(type, n?.network, timeoutMs) + + fun expectAvailableCallbacks( + n: HasNetwork, + suspended: Boolean, + validated: Boolean, + blocked: Boolean, + timeoutMs: Long + ) = expectAvailableCallbacks(n.network, suspended, validated, blocked, timeoutMs) + + fun expectAvailableAndSuspendedCallbacks(n: HasNetwork, expectValidated: Boolean) { + expectAvailableAndSuspendedCallbacks(n.network, expectValidated) + } + + fun expectAvailableCallbacksValidated(n: HasNetwork) { + expectAvailableCallbacks(n.network) + } + + fun expectAvailableCallbacksValidatedAndBlocked(n: HasNetwork) { + expectAvailableCallbacks(n.network, blocked = true) + } + + fun expectAvailableCallbacksUnvalidated(n: HasNetwork) { + expectAvailableCallbacks(n.network, validated = false) + } + + fun expectAvailableCallbacksUnvalidatedAndBlocked(n: HasNetwork) { + expectAvailableCallbacks(n.network, validated = false, blocked = true) + } + + fun expectAvailableDoubleValidatedCallbacks(n: HasNetwork) { + expectAvailableDoubleValidatedCallbacks(n.network, defaultTimeoutMs) + } + + fun expectAvailableThenValidatedCallbacks(n: HasNetwork) { + expectAvailableThenValidatedCallbacks(n.network, defaultTimeoutMs) + } + + @JvmOverloads + fun expectLinkPropertiesThat( + n: HasNetwork, + tmt: Long = defaultTimeoutMs, + valid: (LinkProperties) -> Boolean + ) = expectLinkPropertiesThat(n.network, tmt, valid) + + @JvmOverloads + fun expectCapabilitiesThat( + n: HasNetwork, + tmt: Long = defaultTimeoutMs, + valid: (NetworkCapabilities) -> Boolean + ) = expectCapabilitiesThat(n.network, tmt, valid) + + @JvmOverloads + fun expectCapabilitiesWith( + capability: Int, + n: HasNetwork, + timeoutMs: Long = defaultTimeoutMs + ): NetworkCapabilities { + return expectCapabilitiesThat(n.network, timeoutMs) { it.hasCapability(capability) }.caps + } + + @JvmOverloads + fun expectCapabilitiesWithout( + capability: Int, + n: HasNetwork, + timeoutMs: Long = defaultTimeoutMs + ): NetworkCapabilities { + return expectCapabilitiesThat(n.network, timeoutMs) { !it.hasCapability(capability) }.caps + } + + fun expectBlockedStatusCallback(expectBlocked: Boolean, n: HasNetwork) { + expectBlockedStatusCallback(expectBlocked, n.network, defaultTimeoutMs) + } +} diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt new file mode 100644 index 0000000000..d5c3a2a05d --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2020 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 com.android.testutils + +import android.net.netstats.provider.NetworkStatsProvider +import com.android.net.module.util.ArrayTrackRecord +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import kotlin.test.fail + +private const val DEFAULT_TIMEOUT_MS = 200L + +open class TestableNetworkStatsProvider( + val defaultTimeoutMs: Long = DEFAULT_TIMEOUT_MS +) : NetworkStatsProvider() { + sealed class CallbackType { + data class OnRequestStatsUpdate(val token: Int) : CallbackType() + data class OnSetLimit(val iface: String?, val quotaBytes: Long) : CallbackType() + data class OnSetAlert(val quotaBytes: Long) : CallbackType() + } + + val history = ArrayTrackRecord().newReadHead() + // See ReadHead#mark + val mark get() = history.mark + + override fun onRequestStatsUpdate(token: Int) { + history.add(CallbackType.OnRequestStatsUpdate(token)) + } + + override fun onSetLimit(iface: String, quotaBytes: Long) { + history.add(CallbackType.OnSetLimit(iface, quotaBytes)) + } + + override fun onSetAlert(quotaBytes: Long) { + history.add(CallbackType.OnSetAlert(quotaBytes)) + } + + fun expectOnRequestStatsUpdate(token: Int, timeout: Long = defaultTimeoutMs) { + assertEquals(CallbackType.OnRequestStatsUpdate(token), history.poll(timeout)) + } + + fun expectOnSetLimit(iface: String?, quotaBytes: Long, timeout: Long = defaultTimeoutMs) { + assertEquals(CallbackType.OnSetLimit(iface, quotaBytes), history.poll(timeout)) + } + + fun expectOnSetAlert(quotaBytes: Long, timeout: Long = defaultTimeoutMs) { + assertEquals(CallbackType.OnSetAlert(quotaBytes), history.poll(timeout)) + } + + fun pollForNextCallback(timeout: Long = defaultTimeoutMs) = + history.poll(timeout) ?: fail("Did not receive callback after ${timeout}ms") + + inline fun expectCallback( + timeout: Long = defaultTimeoutMs, + predicate: (T) -> Boolean = { true } + ): T { + return pollForNextCallback(timeout).also { assertTrue(it is T && predicate(it)) } as T + } + + // Expects a callback of the specified type matching the predicate within the timeout. + // Any callback that doesn't match the predicate will be skipped. Fails only if + // no matching callback is received within the timeout. + // TODO : factorize the code for this with the identical call in TestableNetworkCallback. + // There should be a common superclass doing this generically. + // TODO : have a better error message to have this fail. Right now the failure when no + // matching callback arrives comes from the casting to a non-nullable T. + // TODO : in fact, completely removing this method and have clients use + // history.poll(timeout, index, predicate) directly might be simpler. + inline fun eventuallyExpect( + timeoutMs: Long = defaultTimeoutMs, + from: Int = mark, + crossinline predicate: (T) -> Boolean = { true } + ) = history.poll(timeoutMs, from) { it is T && predicate(it) } as T + + fun drainCallbacks() { + history.mark = history.size + } + + @JvmOverloads + fun assertNoCallback(timeout: Long = defaultTimeoutMs) { + val cb = history.poll(timeout) + cb?.let { fail("Expected no callback but got $cb") } + } +} diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt new file mode 100644 index 0000000000..02922d87ea --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2020 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 com.android.testutils + +import android.net.netstats.provider.INetworkStatsProvider +import com.android.net.module.util.ArrayTrackRecord +import kotlin.test.assertEquals +import kotlin.test.fail + +private const val DEFAULT_TIMEOUT_MS = 200L + +open class TestableNetworkStatsProviderBinder : INetworkStatsProvider.Stub() { + sealed class CallbackType { + data class OnRequestStatsUpdate(val token: Int) : CallbackType() + data class OnSetLimit(val iface: String?, val quotaBytes: Long) : CallbackType() + data class OnSetAlert(val quotaBytes: Long) : CallbackType() + } + + private val history = ArrayTrackRecord().ReadHead() + + override fun onRequestStatsUpdate(token: Int) { + history.add(CallbackType.OnRequestStatsUpdate(token)) + } + + override fun onSetLimit(iface: String?, quotaBytes: Long) { + history.add(CallbackType.OnSetLimit(iface, quotaBytes)) + } + + override fun onSetAlert(quotaBytes: Long) { + history.add(CallbackType.OnSetAlert(quotaBytes)) + } + + fun expectOnRequestStatsUpdate(token: Int) { + assertEquals(CallbackType.OnRequestStatsUpdate(token), history.poll(DEFAULT_TIMEOUT_MS)) + } + + fun expectOnSetLimit(iface: String?, quotaBytes: Long) { + assertEquals(CallbackType.OnSetLimit(iface, quotaBytes), history.poll(DEFAULT_TIMEOUT_MS)) + } + + fun expectOnSetAlert(quotaBytes: Long) { + assertEquals(CallbackType.OnSetAlert(quotaBytes), history.poll(DEFAULT_TIMEOUT_MS)) + } + + @JvmOverloads + fun assertNoCallback(timeout: Long = DEFAULT_TIMEOUT_MS) { + val cb = history.poll(timeout) + cb?.let { fail("Expected no callback but got $cb") } + } +} diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt new file mode 100644 index 0000000000..163473a362 --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2020 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 com.android.testutils + +import android.net.NetworkStats +import android.net.netstats.provider.INetworkStatsProviderCallback +import com.android.net.module.util.ArrayTrackRecord +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import kotlin.test.fail + +private const val DEFAULT_TIMEOUT_MS = 3000L + +open class TestableNetworkStatsProviderCbBinder : INetworkStatsProviderCallback.Stub() { + sealed class CallbackType { + data class NotifyStatsUpdated( + val token: Int, + val ifaceStats: NetworkStats, + val uidStats: NetworkStats + ) : CallbackType() + object NotifyLimitReached : CallbackType() + object NotifyAlertReached : CallbackType() + object Unregister : CallbackType() + } + + private val history = ArrayTrackRecord().ReadHead() + + override fun notifyStatsUpdated(token: Int, ifaceStats: NetworkStats, uidStats: NetworkStats) { + history.add(CallbackType.NotifyStatsUpdated(token, ifaceStats, uidStats)) + } + + override fun notifyLimitReached() { + history.add(CallbackType.NotifyLimitReached) + } + + override fun notifyAlertReached() { + history.add(CallbackType.NotifyAlertReached) + } + + override fun unregister() { + history.add(CallbackType.Unregister) + } + + fun expectNotifyStatsUpdated() { + val event = history.poll(DEFAULT_TIMEOUT_MS) + assertTrue(event is CallbackType.NotifyStatsUpdated) + } + + fun expectNotifyStatsUpdated(ifaceStats: NetworkStats, uidStats: NetworkStats) { + val event = history.poll(DEFAULT_TIMEOUT_MS)!! + if (event !is CallbackType.NotifyStatsUpdated) { + throw Exception("Expected NotifyStatsUpdated callback, but got ${event::class}") + } + // TODO: verify token. + assertNetworkStatsEquals(ifaceStats, event.ifaceStats) + assertNetworkStatsEquals(uidStats, event.uidStats) + } + + fun expectNotifyLimitReached() = + assertEquals(CallbackType.NotifyLimitReached, history.poll(DEFAULT_TIMEOUT_MS)) + + fun expectNotifyAlertReached() = + assertEquals(CallbackType.NotifyAlertReached, history.poll(DEFAULT_TIMEOUT_MS)) + + // Assert there is no callback in current queue. + fun assertNoCallback() { + val cb = history.poll(0) + cb?.let { fail("Expected no callback but got $cb") } + } +} diff --git a/staticlibs/src_frameworkcommon/android/net/util/IpRange.java b/staticlibs/framework/android/net/util/IpRange.java similarity index 100% rename from staticlibs/src_frameworkcommon/android/net/util/IpRange.java rename to staticlibs/framework/android/net/util/IpRange.java diff --git a/staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java b/staticlibs/framework/android/net/util/LinkPropertiesUtils.java similarity index 100% rename from staticlibs/src_frameworkcommon/android/net/util/LinkPropertiesUtils.java rename to staticlibs/framework/android/net/util/LinkPropertiesUtils.java diff --git a/staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java b/staticlibs/framework/android/net/util/MacAddressUtils.java similarity index 100% rename from staticlibs/src_frameworkcommon/android/net/util/MacAddressUtils.java rename to staticlibs/framework/android/net/util/MacAddressUtils.java diff --git a/staticlibs/src_frameworkcommon/android/net/util/NetUtils.java b/staticlibs/framework/android/net/util/NetUtils.java similarity index 100% rename from staticlibs/src_frameworkcommon/android/net/util/NetUtils.java rename to staticlibs/framework/android/net/util/NetUtils.java diff --git a/staticlibs/src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java b/staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java similarity index 100% rename from staticlibs/src_frameworkcommon/android/net/util/nsd/DnsSdTxtRecord.java rename to staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java diff --git a/staticlibs/src_frameworkcommon/com/android/net/module/util/DnsPacket.java b/staticlibs/framework/com/android/net/module/util/DnsPacket.java similarity index 100% rename from staticlibs/src_frameworkcommon/com/android/net/module/util/DnsPacket.java rename to staticlibs/framework/com/android/net/module/util/DnsPacket.java diff --git a/staticlibs/src_frameworkcommon/com/android/net/module/util/Inet4AddressUtils.java b/staticlibs/framework/com/android/net/module/util/Inet4AddressUtils.java similarity index 100% rename from staticlibs/src_frameworkcommon/com/android/net/module/util/Inet4AddressUtils.java rename to staticlibs/framework/com/android/net/module/util/Inet4AddressUtils.java diff --git a/staticlibs/src_frameworkcommon/com/android/net/module/util/InetAddressUtils.java b/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java similarity index 100% rename from staticlibs/src_frameworkcommon/com/android/net/module/util/InetAddressUtils.java rename to staticlibs/framework/com/android/net/module/util/InetAddressUtils.java diff --git a/staticlibs/hostdevice/com/android/net/module/util/TrackRecord.kt b/staticlibs/hostdevice/com/android/net/module/util/TrackRecord.kt new file mode 100644 index 0000000000..b647d991fd --- /dev/null +++ b/staticlibs/hostdevice/com/android/net/module/util/TrackRecord.kt @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util + +import java.util.concurrent.TimeUnit +import java.util.concurrent.locks.Condition +import java.util.concurrent.locks.ReentrantLock +import kotlin.concurrent.withLock + +/** + * A List that additionally offers the ability to append via the add() method, and to retrieve + * an element by its index optionally waiting for it to become available. + */ +interface TrackRecord : List { + /** + * Adds an element to this queue, waking up threads waiting for one. Returns true, as + * per the contract for List. + */ + fun add(e: E): Boolean + + /** + * Returns the first element after {@param pos}, possibly blocking until one is available, or + * null if no such element can be found within the timeout. + * If a predicate is given, only elements matching the predicate are returned. + * + * @param timeoutMs how long, in milliseconds, to wait at most (best effort approximation). + * @param pos the position at which to start polling. + * @param predicate an optional predicate to filter elements to be returned. + * @return an element matching the predicate, or null if timeout. + */ + fun poll(timeoutMs: Long, pos: Int, predicate: (E) -> Boolean = { true }): E? +} + +/** + * A thread-safe implementation of TrackRecord that is backed by an ArrayList. + * + * This class also supports the creation of a read-head for easier single-thread access. + * Refer to the documentation of {@link ArrayTrackRecord.ReadHead}. + */ +class ArrayTrackRecord : TrackRecord { + private val lock = ReentrantLock() + private val condition = lock.newCondition() + // Backing store. This stores the elements in this ArrayTrackRecord. + private val elements = ArrayList() + + // The list iterator for RecordingQueue iterates over a snapshot of the collection at the + // time the operator is created. Because TrackRecord is only ever mutated by appending, + // that makes this iterator thread-safe as it sees an effectively immutable List. + class ArrayTrackRecordIterator( + private val list: ArrayList, + start: Int, + private val end: Int + ) : ListIterator { + var index = start + override fun hasNext() = index < end + override fun next() = list[index++] + override fun hasPrevious() = index > 0 + override fun nextIndex() = index + 1 + override fun previous() = list[--index] + override fun previousIndex() = index - 1 + } + + // List implementation + override val size get() = lock.withLock { elements.size } + override fun contains(element: E) = lock.withLock { elements.contains(element) } + override fun containsAll(elements: Collection) = lock.withLock { + this.elements.containsAll(elements) + } + override operator fun get(index: Int) = lock.withLock { elements[index] } + override fun indexOf(element: E): Int = lock.withLock { elements.indexOf(element) } + override fun lastIndexOf(element: E): Int = lock.withLock { elements.lastIndexOf(element) } + override fun isEmpty() = lock.withLock { elements.isEmpty() } + override fun listIterator(index: Int) = ArrayTrackRecordIterator(elements, index, size) + override fun listIterator() = listIterator(0) + override fun iterator() = listIterator() + override fun subList(fromIndex: Int, toIndex: Int): List = lock.withLock { + elements.subList(fromIndex, toIndex) + } + + // TrackRecord implementation + override fun add(e: E): Boolean { + lock.withLock { + elements.add(e) + condition.signalAll() + } + return true + } + override fun poll(timeoutMs: Long, pos: Int, predicate: (E) -> Boolean) = lock.withLock { + elements.getOrNull(pollForIndexReadLocked(timeoutMs, pos, predicate)) + } + + // For convenience + fun getOrNull(pos: Int, predicate: (E) -> Boolean) = lock.withLock { + if (pos < 0 || pos > size) null else elements.subList(pos, size).find(predicate) + } + + // Returns the index of the next element whose position is >= pos matching the predicate, if + // necessary waiting until such a time that such an element is available, with a timeout. + // If no such element is found within the timeout -1 is returned. + private fun pollForIndexReadLocked(timeoutMs: Long, pos: Int, predicate: (E) -> Boolean): Int { + val deadline = System.currentTimeMillis() + timeoutMs + var index = pos + do { + while (index < elements.size) { + if (predicate(elements[index])) return index + ++index + } + } while (condition.await(deadline - System.currentTimeMillis())) + return -1 + } + + /** + * Returns a ReadHead over this ArrayTrackRecord. The returned ReadHead is tied to the + * current thread. + */ + fun newReadHead() = ReadHead() + + /** + * ReadHead is an object that helps users of ArrayTrackRecord keep track of how far + * it has read this far in the ArrayTrackRecord. A ReadHead is always associated with + * a single instance of ArrayTrackRecord. Multiple ReadHeads can be created and used + * on the same instance of ArrayTrackRecord concurrently, and the ArrayTrackRecord + * instance can also be used concurrently. ReadHead maintains the current index that is + * the next to be read, and calls this the "mark". + * + * A ReadHead delegates all TrackRecord methods to its associated ArrayTrackRecord, and + * inherits its thread-safe properties. However, the additional methods that ReadHead + * offers on top of TrackRecord do not share these properties and can only be used by + * the thread that created the ReadHead. This is because by construction it does not + * make sense to use a ReadHead on multiple threads concurrently (see below for details). + * + * In a ReadHead, {@link poll(Long, (E) -> Boolean)} works similarly to a LinkedBlockingQueue. + * It can be called repeatedly and will return the elements as they arrive. + * + * Intended usage looks something like this : + * val TrackRecord record = ArrayTrackRecord().newReadHead() + * Thread().start { + * // do stuff + * record.add(something) + * // do stuff + * } + * + * val obj1 = record.poll(timeout) + * // do something with obj1 + * val obj2 = record.poll(timeout) + * // do something with obj2 + * + * The point is that the caller does not have to track the mark like it would have to if + * it was using ArrayTrackRecord directly. + * + * Note that if multiple threads were using poll() concurrently on the same ReadHead, what + * happens to the mark and the return values could be well defined, but it could not + * be useful because there is no way to provide either a guarantee not to skip objects nor + * a guarantee about the mark position at the exit of poll(). This is even more true in the + * presence of a predicate to filter returned elements, because one thread might be + * filtering out the events the other is interested in. + * Instead, this use case is supported by creating multiple ReadHeads on the same instance + * of ArrayTrackRecord. Each ReadHead is then guaranteed to see all events always and + * guarantees are made on the value of the mark upon return. {@see poll(Long, (E) -> Boolean)} + * for details. Be careful to create each ReadHead on the thread it is meant to be used on. + * + * Users of a ReadHead can ask for the current position of the mark at any time. This mark + * can be used later to replay the history of events either on this ReadHead, on the associated + * ArrayTrackRecord or on another ReadHead associated with the same ArrayTrackRecord. It + * might look like this in the reader thread : + * + * val markAtStart = record.mark + * // Start processing interesting events + * while (val element = record.poll(timeout) { it.isInteresting() }) { + * // Do something with element + * } + * // Look for stuff that happened while searching for interesting events + * val firstElementReceived = record.getOrNull(markAtStart) + * val firstSpecialElement = record.getOrNull(markAtStart) { it.isSpecial() } + * // Get the first special element since markAtStart, possibly blocking until one is available + * val specialElement = record.poll(timeout, markAtStart) { it.isSpecial() } + */ + inner class ReadHead : TrackRecord by this@ArrayTrackRecord { + private val owningThread = Thread.currentThread() + private var readHead = 0 + + /** + * @return the current value of the mark. + */ + var mark + get() = readHead.also { checkThread() } + set(v: Int) = rewind(v) + fun rewind(v: Int) { + checkThread() + readHead = v + } + + private fun checkThread() = check(Thread.currentThread() == owningThread) { + "Must be called by the thread that created this object" + } + + /** + * Returns the first element after the mark, optionally blocking until one is available, or + * null if no such element can be found within the timeout. + * If a predicate is given, only elements matching the predicate are returned. + * + * Upon return the mark will be set to immediately after the returned element, or after + * the last element in the queue if null is returned. This means this method will always + * skip elements that do not match the predicate, even if it returns null. + * + * This method can only be used by the thread that created this ManagedRecordingQueue. + * If used on another thread, this throws IllegalStateException. + * + * @param timeoutMs how long, in milliseconds, to wait at most (best effort approximation). + * @param predicate an optional predicate to filter elements to be returned. + * @return an element matching the predicate, or null if timeout. + */ + fun poll(timeoutMs: Long, predicate: (E) -> Boolean = { true }): E? { + checkThread() + lock.withLock { + val index = pollForIndexReadLocked(timeoutMs, readHead, predicate) + readHead = if (index < 0) size else index + 1 + return getOrNull(index) + } + } + + /** + * Returns the first element after the mark or null. This never blocks. + * + * This method can only be used by the thread that created this ManagedRecordingQueue. + * If used on another thread, this throws IllegalStateException. + */ + fun peek(): E? = getOrNull(readHead).also { checkThread() } + } +} + +// Private helper +private fun Condition.await(timeoutMs: Long) = this.await(timeoutMs, TimeUnit.MILLISECONDS) diff --git a/staticlibs/hostdevice/com/android/testutils/ConcurrentUtils.kt b/staticlibs/hostdevice/com/android/testutils/ConcurrentUtils.kt new file mode 100644 index 0000000000..a365af59e2 --- /dev/null +++ b/staticlibs/hostdevice/com/android/testutils/ConcurrentUtils.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2019 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 com.android.testutils + +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit +import kotlin.system.measureTimeMillis + +// For Java usage +fun durationOf(fn: Runnable) = measureTimeMillis { fn.run() } + +fun CountDownLatch.await(timeoutMs: Long): Boolean = await(timeoutMs, TimeUnit.MILLISECONDS) diff --git a/staticlibs/hostdevice/com/android/testutils/ExceptionUtils.java b/staticlibs/hostdevice/com/android/testutils/ExceptionUtils.java new file mode 100644 index 0000000000..e7dbed5dd1 --- /dev/null +++ b/staticlibs/hostdevice/com/android/testutils/ExceptionUtils.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2019 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 com.android.testutils; + +import java.util.function.Supplier; + +public class ExceptionUtils { + /** + * Like a Consumer, but declared to throw an exception. + * @param + */ + @FunctionalInterface + public interface ThrowingConsumer { + void accept(T t) throws Exception; + } + + /** + * Like a Supplier, but declared to throw an exception. + * @param + */ + @FunctionalInterface + public interface ThrowingSupplier { + T get() throws Exception; + } + + /** + * Like a Runnable, but declared to throw an exception. + */ + @FunctionalInterface + public interface ThrowingRunnable { + void run() throws Exception; + } + + + public static Supplier ignoreExceptions(ThrowingSupplier func) { + return () -> { + try { + return func.get(); + } catch (Exception e) { + return null; + } + }; + } + + public static Runnable ignoreExceptions(ThrowingRunnable r) { + return () -> { + try { + r.run(); + } catch (Exception e) { + } + }; + } +} diff --git a/staticlibs/hostdevice/com/android/testutils/FileUtils.kt b/staticlibs/hostdevice/com/android/testutils/FileUtils.kt new file mode 100644 index 0000000000..678f9774fd --- /dev/null +++ b/staticlibs/hostdevice/com/android/testutils/FileUtils.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019 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 com.android.testutils + +// This function is private because the 2 is hardcoded here, and is not correct if not called +// directly from __LINE__ or __FILE__. +private fun callerStackTrace(): StackTraceElement = try { + throw RuntimeException() +} catch (e: RuntimeException) { + e.stackTrace[2] // 0 is here, 1 is get() in __FILE__ or __LINE__ +} +val __FILE__: String get() = callerStackTrace().fileName +val __LINE__: Int get() = callerStackTrace().lineNumber diff --git a/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt b/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt new file mode 100644 index 0000000000..32c22c28da --- /dev/null +++ b/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2019 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 com.android.testutils + +import com.android.testutils.ExceptionUtils.ThrowingRunnable +import java.lang.reflect.Modifier +import kotlin.system.measureTimeMillis +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +private const val TAG = "Connectivity unit test" + +fun assertEmpty(ts: Array) = ts.size.let { len -> + assertEquals(0, len, "Expected empty array, but length was $len") +} + +fun assertLength(expected: Int, got: Array) = got.size.let { len -> + assertEquals(expected, len, "Expected array of length $expected, but was $len for $got") +} + +// Bridge method to help write this in Java. If you're writing Kotlin, consider using native +// kotlin.test.assertFailsWith instead, as that method is reified and inlined. +fun assertThrows(expected: Class, block: ThrowingRunnable): T { + return assertFailsWith(expected.kotlin) { block.run() } +} + +fun assertThrows(msg: String, expected: Class, block: ThrowingRunnable): T { + return assertFailsWith(expected.kotlin, msg) { block.run() } +} + +fun assertEqualBothWays(o1: T, o2: T) { + assertTrue(o1 == o2) + assertTrue(o2 == o1) +} + +fun assertNotEqualEitherWay(o1: T, o2: T) { + assertFalse(o1 == o2) + assertFalse(o2 == o1) +} + +fun assertStringContains(got: String, want: String) { + assertTrue(got.contains(want), "$got did not contain \"${want}\"") +} + +fun assertContainsExactly(actual: IntArray, vararg expected: Int) { + // IntArray#sorted() returns a list, so it's fine to test with equals() + assertEquals(actual.sorted(), expected.sorted(), + "$actual does not contain exactly $expected") +} + +fun assertContainsStringsExactly(actual: Array, vararg expected: String) { + assertEquals(actual.sorted(), expected.sorted(), + "$actual does not contain exactly $expected") +} + +fun assertContainsAll(list: Collection, vararg elems: T) { + assertContainsAll(list, elems.asList()) +} + +fun assertContainsAll(list: Collection, elems: Collection) { + elems.forEach { assertTrue(list.contains(it), "$it not in list") } +} + +fun assertRunsInAtMost(descr: String, timeLimit: Long, fn: Runnable) { + assertRunsInAtMost(descr, timeLimit) { fn.run() } +} + +fun assertRunsInAtMost(descr: String, timeLimit: Long, fn: () -> Unit) { + val timeTaken = measureTimeMillis(fn) + val msg = String.format("%s: took %dms, limit was %dms", descr, timeTaken, timeLimit) + assertTrue(timeTaken <= timeLimit, msg) +} + +/** + * Verifies that the number of nonstatic fields in a java class equals a given count. + * Note: this is essentially not useful for Kotlin code where fields are not really a thing. + * + * This assertion serves as a reminder to update test code around it if fields are added + * after the test is written. + * @param count Expected number of nonstatic fields in the class. + * @param clazz Class to test. + */ +fun assertFieldCountEquals(count: Int, clazz: Class) { + assertEquals(count, clazz.declaredFields.filter { + !Modifier.isStatic(it.modifiers) && !Modifier.isTransient(it.modifiers) + }.size) +} diff --git a/staticlibs/hostdevice/com/android/testutils/PacketFilter.kt b/staticlibs/hostdevice/com/android/testutils/PacketFilter.kt new file mode 100644 index 0000000000..cd8d6a55c2 --- /dev/null +++ b/staticlibs/hostdevice/com/android/testutils/PacketFilter.kt @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2020 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 com.android.testutils + +import java.util.function.Predicate + +const val ETHER_TYPE_OFFSET = 12 +const val ETHER_HEADER_LENGTH = 14 +const val IPV4_PROTOCOL_OFFSET = ETHER_HEADER_LENGTH + 9 +const val IPV4_CHECKSUM_OFFSET = ETHER_HEADER_LENGTH + 10 +const val IPV4_HEADER_LENGTH = 20 +const val IPV4_UDP_OFFSET = ETHER_HEADER_LENGTH + IPV4_HEADER_LENGTH +const val BOOTP_OFFSET = IPV4_UDP_OFFSET + 8 +const val BOOTP_TID_OFFSET = BOOTP_OFFSET + 4 +const val BOOTP_CLIENT_MAC_OFFSET = BOOTP_OFFSET + 28 +const val DHCP_OPTIONS_OFFSET = BOOTP_OFFSET + 240 + +/** + * A [Predicate] that matches a [ByteArray] if it contains the specified [bytes] at the specified + * [offset]. + */ +class OffsetFilter(val offset: Int, vararg val bytes: Byte) : Predicate { + override fun test(packet: ByteArray) = + bytes.withIndex().all { it.value == packet[offset + it.index] } +} + +/** + * A [Predicate] that matches ethernet-encapped packets that contain an UDP over IPv4 datagram. + */ +class IPv4UdpFilter : Predicate { + private val impl = OffsetFilter(ETHER_TYPE_OFFSET, 0x08, 0x00 /* IPv4 */).and( + OffsetFilter(IPV4_PROTOCOL_OFFSET, 17 /* UDP */)) + override fun test(t: ByteArray) = impl.test(t) +} + +/** + * A [Predicate] that matches ethernet-encapped DHCP packets sent from a DHCP client. + */ +class DhcpClientPacketFilter : Predicate { + private val impl = IPv4UdpFilter() + .and(OffsetFilter(IPV4_UDP_OFFSET /* source port */, 0x00, 0x44 /* 68 */)) + .and(OffsetFilter(IPV4_UDP_OFFSET + 2 /* dest port */, 0x00, 0x43 /* 67 */)) + override fun test(t: ByteArray) = impl.test(t) +} + +/** + * A [Predicate] that matches a [ByteArray] if it contains a ethernet-encapped DHCP packet that + * contains the specified option with the specified [bytes] as value. + */ +class DhcpOptionFilter(val option: Byte, vararg val bytes: Byte) : Predicate { + override fun test(packet: ByteArray): Boolean { + val option = findDhcpOption(packet, option) ?: return false + return option.contentEquals(bytes) + } +} + +/** + * Find a DHCP option in a packet and return its value, if found. + */ +fun findDhcpOption(packet: ByteArray, option: Byte): ByteArray? = + findOptionOffset(packet, option, DHCP_OPTIONS_OFFSET)?.let { + val optionLen = packet[it + 1] + return packet.copyOfRange(it + 2 /* type, length bytes */, it + 2 + optionLen) + } + +private tailrec fun findOptionOffset(packet: ByteArray, option: Byte, searchOffset: Int): Int? { + if (packet.size <= searchOffset + 2 /* type, length bytes */) return null + + return if (packet[searchOffset] == option) searchOffset else { + val optionLen = packet[searchOffset + 1] + findOptionOffset(packet, option, searchOffset + 2 + optionLen) + } +} diff --git a/staticlibs/hostdevice/com/android/testutils/SkipPresubmit.kt b/staticlibs/hostdevice/com/android/testutils/SkipPresubmit.kt new file mode 100644 index 0000000000..69ed048f5f --- /dev/null +++ b/staticlibs/hostdevice/com/android/testutils/SkipPresubmit.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2020 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 com.android.testutils + +/** + * Skip the test in presubmit runs for the reason specified in [reason]. + * + * This annotation is typically used to document hardware or test bench limitations. + */ +annotation class SkipPresubmit(val reason: String) \ No newline at end of file diff --git a/staticlibs/jarjar-rules-shared.txt b/staticlibs/jarjar-rules-shared.txt index b22771d17f..9e618db19b 100644 --- a/staticlibs/jarjar-rules-shared.txt +++ b/staticlibs/jarjar-rules-shared.txt @@ -1,3 +1,8 @@ -rule android.net.util.** com.android.net.module.util.@1 +# TODO: move the classes to the target package in java +rule android.net.util.IpRange* com.android.net.module.util.IpRange@1 +rule android.net.util.MacAddressUtils* com.android.net.module.util.MacAddressUtils@1 +rule android.net.util.LinkPropertiesUtils* com.android.net.module.util.LinkPropertiesUtils@1 +rule android.net.util.NetUtils* com.android.net.module.util.NetUtils@1 +rule android.net.util.nsd.** com.android.net.module.util.nsd.@1 rule android.annotation.** com.android.net.module.annotation.@1 -rule com.android.internal.annotations.** com.android.net.module.annotation.@1 \ No newline at end of file +rule com.android.internal.annotations.** com.android.net.module.annotation.@1 diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index cb15277324..f18ffcfdd5 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -10,6 +10,8 @@ android_library { static_libs: [ "net-utils-framework-common", "androidx.test.rules", + "net-utils-device-common", + "net-tests-utils-host-device-common", ], libs: [ "android.test.runner", diff --git a/staticlibs/tests/unit/jarjar-rules.txt b/staticlibs/tests/unit/jarjar-rules.txt index dbb3974f7a..fceccfb755 100644 --- a/staticlibs/tests/unit/jarjar-rules.txt +++ b/staticlibs/tests/unit/jarjar-rules.txt @@ -1,4 +1,6 @@ -# Ensure that the tests can directly use the version of classes from the library. Otherwise, they -# will use whatever version is currently in the bootclasspath on the device running the test. -# These rules must match the jarjar rules used to build the library. -rule android.net.util.** com.android.net.module.util.@1 +# TODO: move the classes to the target package in java +rule android.net.util.IpRange* com.android.net.module.util.IpRange@1 +rule android.net.util.MacAddressUtils* com.android.net.module.util.MacAddressUtils@1 +rule android.net.util.LinkPropertiesUtils* com.android.net.module.util.LinkPropertiesUtils@1 +rule android.net.util.NetUtils* com.android.net.module.util.NetUtils@1 +rule android.net.util.nsd.** com.android.net.module.util.nsd.@1 diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java new file mode 100644 index 0000000000..e3af97eeb2 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2016 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 com.android.net.module.util; + +import static android.net.util.PacketReader.DEFAULT_RECV_BUF_SIZE; +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.IPPROTO_UDP; +import static android.system.OsConstants.SOCK_DGRAM; +import static android.system.OsConstants.SOCK_NONBLOCK; +import static android.system.OsConstants.SOL_SOCKET; +import static android.system.OsConstants.SO_SNDTIMEO; + +import static com.android.testutils.MiscAssertsKt.assertThrows; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.net.util.PacketReader; +import android.os.Handler; +import android.os.HandlerThread; +import android.system.ErrnoException; +import android.system.Os; +import android.system.StructTimeval; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.FileDescriptor; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.util.Arrays; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * Tests for PacketReader. + * + * @hide + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class PacketReaderTest { + static final InetAddress LOOPBACK6 = Inet6Address.getLoopbackAddress(); + static final StructTimeval TIMEO = StructTimeval.fromMillis(500); + + // TODO : reassigning the latch voids its synchronization properties, which means this + // scheme just doesn't work. Latches almost always need to be final to work. + protected CountDownLatch mLatch; + protected FileDescriptor mLocalSocket; + protected InetSocketAddress mLocalSockName; + protected byte[] mLastRecvBuf; + protected boolean mStopped; + protected HandlerThread mHandlerThread; + protected PacketReader mReceiver; + + class UdpLoopbackReader extends PacketReader { + UdpLoopbackReader(Handler h) { + super(h); + } + + @Override + protected FileDescriptor createFd() { + FileDescriptor s = null; + try { + s = Os.socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); + Os.bind(s, LOOPBACK6, 0); + mLocalSockName = (InetSocketAddress) Os.getsockname(s); + Os.setsockoptTimeval(s, SOL_SOCKET, SO_SNDTIMEO, TIMEO); + } catch (ErrnoException | SocketException e) { + closeFd(s); + fail(); + return null; + } + + mLocalSocket = s; + return s; + } + + @Override + protected void handlePacket(byte[] recvbuf, int length) { + mLastRecvBuf = Arrays.copyOf(recvbuf, length); + mLatch.countDown(); + } + + @Override + protected void onStart() { + mStopped = false; + mLatch.countDown(); + } + + @Override + protected void onStop() { + mStopped = true; + mLatch.countDown(); + } + }; + + @Before + public void setUp() { + resetLatch(); + mLocalSocket = null; + mLocalSockName = null; + mLastRecvBuf = null; + mStopped = false; + + mHandlerThread = new HandlerThread(PacketReaderTest.class.getSimpleName()); + mHandlerThread.start(); + } + + @After + public void tearDown() throws Exception { + if (mReceiver != null) { + mHandlerThread.getThreadHandler().post(() -> mReceiver.stop()); + waitForActivity(); + } + mReceiver = null; + mHandlerThread.quit(); + mHandlerThread = null; + } + + void resetLatch() { + mLatch = new CountDownLatch(1); + } + + void waitForActivity() throws Exception { + try { + mLatch.await(1000, TimeUnit.MILLISECONDS); + } finally { + resetLatch(); + } + } + + void sendPacket(byte[] contents) throws Exception { + final DatagramSocket sender = new DatagramSocket(); + sender.connect(mLocalSockName); + sender.send(new DatagramPacket(contents, contents.length)); + sender.close(); + } + + @Test + public void testBasicWorking() throws Exception { + final Handler h = mHandlerThread.getThreadHandler(); + mReceiver = new UdpLoopbackReader(h); + + h.post(() -> mReceiver.start()); + waitForActivity(); + assertTrue(mLocalSockName != null); + assertEquals(LOOPBACK6, mLocalSockName.getAddress()); + assertTrue(0 < mLocalSockName.getPort()); + assertTrue(mLocalSocket != null); + assertFalse(mStopped); + + final byte[] one = "one 1".getBytes("UTF-8"); + sendPacket(one); + waitForActivity(); + assertEquals(1, mReceiver.numPacketsReceived()); + assertTrue(Arrays.equals(one, mLastRecvBuf)); + assertFalse(mStopped); + + final byte[] two = "two 2".getBytes("UTF-8"); + sendPacket(two); + waitForActivity(); + assertEquals(2, mReceiver.numPacketsReceived()); + assertTrue(Arrays.equals(two, mLastRecvBuf)); + assertFalse(mStopped); + + h.post(() -> mReceiver.stop()); + waitForActivity(); + assertEquals(2, mReceiver.numPacketsReceived()); + assertTrue(Arrays.equals(two, mLastRecvBuf)); + assertTrue(mStopped); + mReceiver = null; + } + + class NullPacketReader extends PacketReader { + NullPacketReader(Handler h, int recvbufsize) { + super(h, recvbufsize); + } + + @Override + public FileDescriptor createFd() { + return null; + } + } + + @Test + public void testMinimalRecvBufSize() throws Exception { + final Handler h = mHandlerThread.getThreadHandler(); + + for (int i : new int[] { -1, 0, 1, DEFAULT_RECV_BUF_SIZE - 1 }) { + final PacketReader b = new NullPacketReader(h, i); + assertEquals(DEFAULT_RECV_BUF_SIZE, b.recvBufSize()); + } + } + + @Test + public void testStartingFromWrongThread() throws Exception { + final Handler h = mHandlerThread.getThreadHandler(); + final PacketReader b = new NullPacketReader(h, DEFAULT_RECV_BUF_SIZE); + assertThrows(IllegalStateException.class, () -> b.start()); + } + + @Test + public void testStoppingFromWrongThread() throws Exception { + final Handler h = mHandlerThread.getThreadHandler(); + final PacketReader b = new NullPacketReader(h, DEFAULT_RECV_BUF_SIZE); + assertThrows(IllegalStateException.class, () -> b.stop()); + } + + @Test + public void testSuccessToCreateSocket() throws Exception { + final Handler h = mHandlerThread.getThreadHandler(); + final PacketReader b = new UdpLoopbackReader(h); + h.post(() -> assertTrue(b.start())); + } + + @Test + public void testFailToCreateSocket() throws Exception { + final Handler h = mHandlerThread.getThreadHandler(); + final PacketReader b = new NullPacketReader(h, DEFAULT_RECV_BUF_SIZE); + h.post(() -> assertFalse(b.start())); + } +} From e06c5c8fc01fa52fe78d30195218b9c2adeed425 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 26 Jun 2020 00:16:27 +0900 Subject: [PATCH 048/777] Fix issues reported by checkstyle Test: builds Change-Id: I41979cc8096a682c6844df0825ee56ab00a828b5 --- .../com/android/testutils/HandlerUtils.kt | 1 - .../com/android/testutils/TapPacketReader.java | 13 +++++++++++++ .../com/android/testutils/ExceptionUtils.java | 17 ++++++++++++++++- .../com/android/testutils/MiscAsserts.kt | 2 +- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/staticlibs/devicetests/com/android/testutils/HandlerUtils.kt b/staticlibs/devicetests/com/android/testutils/HandlerUtils.kt index fa36209462..336e12c1d9 100644 --- a/staticlibs/devicetests/com/android/testutils/HandlerUtils.kt +++ b/staticlibs/devicetests/com/android/testutils/HandlerUtils.kt @@ -20,7 +20,6 @@ import android.os.ConditionVariable import android.os.Handler import android.os.HandlerThread import java.util.concurrent.Executor -import kotlin.system.measureTimeMillis import kotlin.test.fail /** diff --git a/staticlibs/devicetests/com/android/testutils/TapPacketReader.java b/staticlibs/devicetests/com/android/testutils/TapPacketReader.java index fea1cd9a5a..c36f144584 100644 --- a/staticlibs/devicetests/com/android/testutils/TapPacketReader.java +++ b/staticlibs/devicetests/com/android/testutils/TapPacketReader.java @@ -34,6 +34,11 @@ import java.util.function.Predicate; import kotlin.Lazy; import kotlin.LazyKt; +/** + * A packet reader that runs on a TAP interface. + * + * It also implements facilities to reply to received packets. + */ public class TapPacketReader extends PacketReader { private final FileDescriptor mTapFd; private final ArrayTrackRecord mReceivedPackets = new ArrayTrackRecord<>(); @@ -82,6 +87,14 @@ public class TapPacketReader extends PacketReader { return mReceivedPackets; } + /* + * Send a response on the TAP interface. + * + * The passed ByteBuffer is flipped after use. + * + * @param packet The packet to send. + * @throws IOException if the interface can't be written to. + */ public void sendResponse(final ByteBuffer packet) throws IOException { try (FileOutputStream out = new FileOutputStream(mTapFd)) { byte[] packetBytes = new byte[packet.limit()]; diff --git a/staticlibs/hostdevice/com/android/testutils/ExceptionUtils.java b/staticlibs/hostdevice/com/android/testutils/ExceptionUtils.java index e7dbed5dd1..d3bda98cb0 100644 --- a/staticlibs/hostdevice/com/android/testutils/ExceptionUtils.java +++ b/staticlibs/hostdevice/com/android/testutils/ExceptionUtils.java @@ -18,6 +18,9 @@ package com.android.testutils; import java.util.function.Supplier; +/** + * A class grouping some utilities to deal with exceptions. + */ public class ExceptionUtils { /** * Like a Consumer, but declared to throw an exception. @@ -25,6 +28,7 @@ public class ExceptionUtils { */ @FunctionalInterface public interface ThrowingConsumer { + /** @see java.util.function.Consumer */ void accept(T t) throws Exception; } @@ -34,6 +38,7 @@ public class ExceptionUtils { */ @FunctionalInterface public interface ThrowingSupplier { + /** @see java.util.function.Supplier */ T get() throws Exception; } @@ -42,10 +47,15 @@ public class ExceptionUtils { */ @FunctionalInterface public interface ThrowingRunnable { + /** @see java.lang.Runnable */ void run() throws Exception; } - + /** + * Convert a supplier that throws into one that doesn't. + * + * The returned supplier returns null in cases where the source throws. + */ public static Supplier ignoreExceptions(ThrowingSupplier func) { return () -> { try { @@ -56,6 +66,11 @@ public class ExceptionUtils { }; } + /** + * Convert a runnable that throws into one that doesn't. + * + * All exceptions are ignored by the returned Runnable. + */ public static Runnable ignoreExceptions(ThrowingRunnable r) { return () -> { try { diff --git a/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt b/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt index 32c22c28da..4e8636028b 100644 --- a/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt +++ b/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt @@ -34,7 +34,7 @@ fun assertLength(expected: Int, got: Array) = got.size.let { len -> assertEquals(expected, len, "Expected array of length $expected, but was $len for $got") } -// Bridge method to help write this in Java. If you're writing Kotlin, consider using native +// Bridge method to help write this in Java. If you're writing Kotlin, consider using // kotlin.test.assertFailsWith instead, as that method is reified and inlined. fun assertThrows(expected: Class, block: ThrowingRunnable): T { return assertFailsWith(expected.kotlin) { block.run() } From b1856fe06bdb9aafb1178c86ecdff0ff980fd301 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 26 Jun 2020 00:42:01 +0900 Subject: [PATCH 049/777] Rename utils to remove the Kt suffix Nobody cares what language this is written in Test: builds Change-Id: I3ed3bce276479fd503e716a06fd4912da8c49eda --- staticlibs/devicetests/com/android/testutils/HandlerUtils.kt | 2 ++ staticlibs/devicetests/com/android/testutils/ParcelUtils.kt | 2 ++ staticlibs/hostdevice/com/android/testutils/ConcurrentUtils.kt | 2 ++ staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt | 2 ++ .../unit/src/com/android/net/module/util/PacketReaderTest.java | 2 +- 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/staticlibs/devicetests/com/android/testutils/HandlerUtils.kt b/staticlibs/devicetests/com/android/testutils/HandlerUtils.kt index 336e12c1d9..861f45ee3c 100644 --- a/staticlibs/devicetests/com/android/testutils/HandlerUtils.kt +++ b/staticlibs/devicetests/com/android/testutils/HandlerUtils.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:JvmName("HandlerUtils") + package com.android.testutils import android.os.ConditionVariable diff --git a/staticlibs/devicetests/com/android/testutils/ParcelUtils.kt b/staticlibs/devicetests/com/android/testutils/ParcelUtils.kt index 5784f7cbcc..14ed8e9e3a 100644 --- a/staticlibs/devicetests/com/android/testutils/ParcelUtils.kt +++ b/staticlibs/devicetests/com/android/testutils/ParcelUtils.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:JvmName("ParcelUtils") + package com.android.testutils import android.os.Parcel diff --git a/staticlibs/hostdevice/com/android/testutils/ConcurrentUtils.kt b/staticlibs/hostdevice/com/android/testutils/ConcurrentUtils.kt index a365af59e2..af4f96dce4 100644 --- a/staticlibs/hostdevice/com/android/testutils/ConcurrentUtils.kt +++ b/staticlibs/hostdevice/com/android/testutils/ConcurrentUtils.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:JvmName("ConcurrentUtils") + package com.android.testutils import java.util.concurrent.CountDownLatch diff --git a/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt b/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt index 4e8636028b..09126d7992 100644 --- a/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt +++ b/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:JvmName("MiscAsserts") + package com.android.testutils import com.android.testutils.ExceptionUtils.ThrowingRunnable diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java index e3af97eeb2..046a1d9d15 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java @@ -24,7 +24,7 @@ import static android.system.OsConstants.SOCK_NONBLOCK; import static android.system.OsConstants.SOL_SOCKET; import static android.system.OsConstants.SO_SNDTIMEO; -import static com.android.testutils.MiscAssertsKt.assertThrows; +import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; From 2f2a3b467c9a0b861a94a343d76508c9f6859e54 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 6 Aug 2020 15:24:47 +0900 Subject: [PATCH 050/777] Add PacketFilter utilities for DNS testing Add packet filters that are useful for filtering / testing DNS queries and ARP requests. This change is a prerequisite for tests verifying DNS and validation metrics. Test: tests using these utilities Bug: 160617623 Bug: 160656765 Change-Id: I4216f4ec60d1a427f60fad6eb8017e36b082665f --- .../com/android/testutils/PacketFilter.kt | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/staticlibs/hostdevice/com/android/testutils/PacketFilter.kt b/staticlibs/hostdevice/com/android/testutils/PacketFilter.kt index cd8d6a55c2..7c615d0b25 100644 --- a/staticlibs/hostdevice/com/android/testutils/PacketFilter.kt +++ b/staticlibs/hostdevice/com/android/testutils/PacketFilter.kt @@ -16,19 +16,28 @@ package com.android.testutils +import java.net.Inet4Address import java.util.function.Predicate const val ETHER_TYPE_OFFSET = 12 const val ETHER_HEADER_LENGTH = 14 const val IPV4_PROTOCOL_OFFSET = ETHER_HEADER_LENGTH + 9 const val IPV4_CHECKSUM_OFFSET = ETHER_HEADER_LENGTH + 10 +const val IPV4_DST_OFFSET = ETHER_HEADER_LENGTH + 16 const val IPV4_HEADER_LENGTH = 20 const val IPV4_UDP_OFFSET = ETHER_HEADER_LENGTH + IPV4_HEADER_LENGTH -const val BOOTP_OFFSET = IPV4_UDP_OFFSET + 8 +const val IPV4_UDP_SRCPORT_OFFSET = IPV4_UDP_OFFSET +const val IPV4_UDP_DSTPORT_OFFSET = IPV4_UDP_OFFSET + 2 +const val UDP_HEADER_LENGTH = 8 +const val BOOTP_OFFSET = IPV4_UDP_OFFSET + UDP_HEADER_LENGTH const val BOOTP_TID_OFFSET = BOOTP_OFFSET + 4 const val BOOTP_CLIENT_MAC_OFFSET = BOOTP_OFFSET + 28 const val DHCP_OPTIONS_OFFSET = BOOTP_OFFSET + 240 +const val ARP_OPCODE_OFFSET = ETHER_HEADER_LENGTH + 6 +const val ARP_SENDER_MAC_OFFSET = ETHER_HEADER_LENGTH + 8 +const val ARP_TARGET_IPADDR_OFFSET = ETHER_HEADER_LENGTH + 24 + /** * A [Predicate] that matches a [ByteArray] if it contains the specified [bytes] at the specified * [offset]. @@ -47,13 +56,30 @@ class IPv4UdpFilter : Predicate { override fun test(t: ByteArray) = impl.test(t) } +/** + * A [Predicate] that matches ethernet-encapped packets sent to the specified IPv4 destination. + */ +class IPv4DstFilter(dst: Inet4Address) : Predicate { + private val impl = OffsetFilter(IPV4_DST_OFFSET, *dst.address) + override fun test(t: ByteArray) = impl.test(t) +} + +/** + * A [Predicate] that matches ethernet-encapped ARP requests. + */ +class ArpRequestFilter : Predicate { + private val impl = OffsetFilter(ETHER_TYPE_OFFSET, 0x08, 0x06 /* ARP */) + .and(OffsetFilter(ARP_OPCODE_OFFSET, 0x00, 0x01 /* request */)) + override fun test(t: ByteArray) = impl.test(t) +} + /** * A [Predicate] that matches ethernet-encapped DHCP packets sent from a DHCP client. */ class DhcpClientPacketFilter : Predicate { private val impl = IPv4UdpFilter() - .and(OffsetFilter(IPV4_UDP_OFFSET /* source port */, 0x00, 0x44 /* 68 */)) - .and(OffsetFilter(IPV4_UDP_OFFSET + 2 /* dest port */, 0x00, 0x43 /* 67 */)) + .and(OffsetFilter(IPV4_UDP_SRCPORT_OFFSET, 0x00, 0x44 /* 68 */)) + .and(OffsetFilter(IPV4_UDP_DSTPORT_OFFSET, 0x00, 0x43 /* 67 */)) override fun test(t: ByteArray) = impl.test(t) } From 7995b438ebeb2bb6e5a09a05076988b221b4be67 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 14 Aug 2020 12:49:56 +0900 Subject: [PATCH 051/777] Add utilities to test tap interface networks Add an ArpResponder based on a generic PacketResponder class, and a TestHttpServer based on NanoHttpd. Test: tests based on these utilities Bug: 160617623 Bug: 160656765 Change-Id: I50b872a8b23e8df997e8f62f0adc7c0256c4d74d --- staticlibs/Android.bp | 1 + .../com/android/testutils/ArpResponder.kt | 60 +++++++++++++ .../com/android/testutils/PacketResponder.kt | 74 ++++++++++++++++ .../com/android/testutils/TestHttpServer.kt | 86 +++++++++++++++++++ 4 files changed, 221 insertions(+) create mode 100644 staticlibs/devicetests/com/android/testutils/ArpResponder.kt create mode 100644 staticlibs/devicetests/com/android/testutils/PacketResponder.kt create mode 100644 staticlibs/devicetests/com/android/testutils/TestHttpServer.kt diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 4b15b16980..f4799f0c50 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -98,6 +98,7 @@ java_library { ], static_libs: [ "androidx.test.ext.junit", + "libnanohttpd", "net-tests-utils-host-device-common", "net-utils-device-common", ], diff --git a/staticlibs/devicetests/com/android/testutils/ArpResponder.kt b/staticlibs/devicetests/com/android/testutils/ArpResponder.kt new file mode 100644 index 0000000000..86631c3d4b --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/ArpResponder.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 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 com.android.testutils + +import android.net.MacAddress +import java.net.Inet4Address +import java.net.InetAddress +import java.nio.ByteBuffer + +private val TYPE_ARP = byteArrayOf(0x08, 0x06) +// Arp reply header for IPv4 over ethernet +private val ARP_REPLY_IPV4 = byteArrayOf(0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02) + +/** + * A class that can be used to reply to ARP packets on a [TapPacketReader]. + */ +class ArpResponder( + reader: TapPacketReader, + table: Map, + name: String = ArpResponder::class.java.simpleName +) : PacketResponder(reader, ArpRequestFilter(), name) { + // Copy the map if not already immutable (toMap) to make sure it is not modified + private val table = table.toMap() + + override fun replyToPacket(packet: ByteArray, reader: TapPacketReader) { + val targetIp = InetAddress.getByAddress( + packet.copyFromIndexWithLength(ARP_TARGET_IPADDR_OFFSET, 4)) + as Inet4Address + + val macAddr = table[targetIp]?.toByteArray() ?: return + val senderMac = packet.copyFromIndexWithLength(ARP_SENDER_MAC_OFFSET, 6) + reader.sendResponse(ByteBuffer.wrap( + // Ethernet header + senderMac + macAddr + TYPE_ARP + + // ARP message + ARP_REPLY_IPV4 + + macAddr /* sender MAC */ + + targetIp.address /* sender IP addr */ + + macAddr /* target mac */ + + targetIp.address /* target IP addr */ + )) + } +} + +private fun ByteArray.copyFromIndexWithLength(start: Int, len: Int) = + copyOfRange(start, start + len) diff --git a/staticlibs/devicetests/com/android/testutils/PacketResponder.kt b/staticlibs/devicetests/com/android/testutils/PacketResponder.kt new file mode 100644 index 0000000000..daf29e4363 --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/PacketResponder.kt @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2020 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 com.android.testutils + +import java.util.function.Predicate + +private const val POLL_FREQUENCY_MS = 1000L + +/** + * A class that can be used to reply to packets from a [TapPacketReader]. + * + * A reply thread will be created to reply to incoming packets asynchronously. + * The receiver creates a new read head on the [TapPacketReader], to read packets, so it does not + * affect packets obtained through [TapPacketReader.popPacket]. + * + * @param reader a [TapPacketReader] to obtain incoming packets and reply to them. + * @param packetFilter A filter to apply to incoming packets. + * @param name Name to use for the internal responder thread. + */ +abstract class PacketResponder( + private val reader: TapPacketReader, + private val packetFilter: Predicate, + name: String +) { + private val replyThread = ReplyThread(name) + + protected abstract fun replyToPacket(packet: ByteArray, reader: TapPacketReader) + + /** + * Start the [PacketResponder]. + */ + fun start() { + replyThread.start() + } + + /** + * Stop the [PacketResponder]. + * + * The responder cannot be used anymore after being stopped. + */ + fun stop() { + replyThread.interrupt() + } + + private inner class ReplyThread(name: String) : Thread(name) { + override fun run() { + try { + // Create a new ReadHead so other packets polled on the reader are not affected + val recvPackets = reader.receivedPackets.newReadHead() + while (!isInterrupted) { + recvPackets.poll(POLL_FREQUENCY_MS, packetFilter::test)?.let { + replyToPacket(it, reader) + } + } + } catch (e: InterruptedException) { + // Exit gracefully + } + } + } +} diff --git a/staticlibs/devicetests/com/android/testutils/TestHttpServer.kt b/staticlibs/devicetests/com/android/testutils/TestHttpServer.kt new file mode 100644 index 0000000000..7aae8e3b59 --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/TestHttpServer.kt @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 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 com.android.testutils + +import android.net.Uri +import com.android.net.module.util.ArrayTrackRecord +import fi.iki.elonen.NanoHTTPD + +/** + * A minimal HTTP server running on a random available port. + * + * @param host The host to listen to, or null to listen on all hosts + */ +class TestHttpServer(host: String? = null) : NanoHTTPD(host, 0 /* auto-select the port */) { + // Map of URL path -> HTTP response code + private val responses = HashMap() + + /** + * A record of all requests received by the server since it was started. + */ + val requestsRecord = ArrayTrackRecord() + + /** + * A request received by the test server. + */ + data class Request( + val path: String, + val method: Method = Method.GET, + val queryParameters: String = "" + ) { + /** + * Returns whether the specified [Uri] matches parameters of this request. + */ + fun matches(uri: Uri) = (uri.path ?: "") == path && (uri.query ?: "") == queryParameters + } + + /** + * Add a response for GET requests with the path and query parameters of the specified [Uri]. + */ + fun addResponse( + uri: Uri, + statusCode: Response.IStatus, + locationHeader: String? = null, + content: String = "" + ) { + addResponse(Request(uri.path + ?: "", Method.GET, uri.query ?: ""), + statusCode, locationHeader, content) + } + + /** + * Add a response for the given request. + */ + fun addResponse( + request: Request, + statusCode: Response.IStatus, + locationHeader: String? = null, + content: String = "" + ) { + val response = newFixedLengthResponse(statusCode, "text/plain", content) + locationHeader?.let { response.addHeader("Location", it) } + responses[request] = response + } + + override fun serve(session: IHTTPSession): Response { + val request = Request(session.uri + ?: "", session.method, session.queryParameterString ?: "") + requestsRecord.add(request) + // Default response is a 404 + return responses[request] ?: super.serve(session) + } +} \ No newline at end of file From 33ed824e8073af8ee8e867fae366145f39eb37aa Mon Sep 17 00:00:00 2001 From: Aurimas Liutikas Date: Wed, 26 Aug 2020 10:16:33 -0700 Subject: [PATCH 052/777] Add workaround for Kotlin 1.4 upgrade This library is not yet compatible with Kotlin 1.4 new @JvmOverloads behavior. This change forces this library to the legacy behavior. See https://kotlinlang.org/docs/reference/compatibility-guide-14.html#generated-overloads-for-jvmoverloads-on-open-methods-should-be-final Bug: 166499531 Test: make Change-Id: I9d675c7bd7a8ff223332dfbdf519c476f4c59c8a --- staticlibs/Android.bp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index f4799f0c50..1143e05bfb 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -102,6 +102,9 @@ java_library { "net-tests-utils-host-device-common", "net-utils-device-common", ], + kotlincflags: [ + "-XXLanguage:-GenerateJvmOverloadsAsFinal" + ] } filegroup { From d59af18458ee823d2a9b4e61dc9eb79e87bfdbc5 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 28 Aug 2020 16:54:40 +0900 Subject: [PATCH 053/777] Remove backward compatibility flag Kotlin updates to 1.4 and fixes an issue where @JvmOverload methods were not final. See https://kotlinlang.org/docs/reference/compatibility-guide-14.html#generated-overloads-for-jvmoverloads-on-open-methods-should-be-final Remove the backward compatibility flag by special-casing the method that needs to be overridden at this time, which gets rid of the local concern. Bug: 166499531 Test: Builds, atest ConnectivityServiceTest Change-Id: Ia13c67876f99dafd77d890e82d62453713b7b5fe --- staticlibs/Android.bp | 3 --- .../com/android/testutils/TestableNetworkCallback.kt | 7 +++++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 1143e05bfb..f4799f0c50 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -102,9 +102,6 @@ java_library { "net-tests-utils-host-device-common", "net-utils-device-common", ], - kotlincflags: [ - "-XXLanguage:-GenerateJvmOverloadsAsFinal" - ] } filegroup { diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt index 959a837d4a..3c038fa420 100644 --- a/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -170,8 +170,11 @@ open class TestableNetworkCallback private constructor( } // Make open for use in ConnectivityServiceTest which is the only one knowing its handlers. - @JvmOverloads - open fun assertNoCallback(timeoutMs: Long = defaultTimeoutMs) { + // TODO : remove the necessity to overload this, remove the open qualifier, and give a + // default argument to assertNoCallback instead, possibly with @JvmOverloads if necessary. + open fun assertNoCallback() = assertNoCallback(defaultTimeoutMs) + + fun assertNoCallback(timeoutMs: Long) { val cb = history.poll(timeoutMs) if (null != cb) fail("Expected no callback but got $cb") } From dea21b79a38d34722fda114e341c680692755a62 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 27 Aug 2020 20:50:03 +0800 Subject: [PATCH 054/777] Add eventuallyExpect overload eventuallyExpect is inline function with reified type which is not accessible from java. Add an open overloaded method to support the usage. Bug: 162323152 Test: atest CtsNetTestCasesLatestSdk:ConnectivityManagerTest Test: atest TestableNetworkCallbackTest Change-Id: Ifd2256e08d7e5d092d57594350ac8ed1c1727afb --- .../com/android/testutils/TestableNetworkCallback.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt index 3c038fa420..7cd5419b73 100644 --- a/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -203,6 +203,14 @@ open class TestableNetworkCallback private constructor( assertNotNull(it, "Callback ${T::class} not received within ${timeoutMs}ms") } as T + fun eventuallyExpect( + type: KClass, + timeoutMs: Long = defaultTimeoutMs, + predicate: (T: CallbackEntry) -> Boolean = { true } + ) = history.poll(timeoutMs) { type.java.isInstance(it) && predicate(it) }.also { + assertNotNull(it, "Callback ${type.java} not received within ${timeoutMs}ms") + } as T + // TODO (b/157405399) straighten and unify the method names inline fun eventuallyExpectOrNull( timeoutMs: Long = defaultTimeoutMs, From a60293a5e91b8ac27f78e0599ef2a04914cbcc6f Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 23 Sep 2020 15:11:42 +0900 Subject: [PATCH 055/777] Add test utilities for shell permission identity Add utilities allowing to run lambdas with shell permissions, in kotlin and java tests. Bug: 168868607 Test: m Change-Id: Iaab38d498338b9e95d263789119cd0813983087d --- .../android/testutils/TestPermissionUtil.kt | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 staticlibs/devicetests/com/android/testutils/TestPermissionUtil.kt diff --git a/staticlibs/devicetests/com/android/testutils/TestPermissionUtil.kt b/staticlibs/devicetests/com/android/testutils/TestPermissionUtil.kt new file mode 100644 index 0000000000..f557f1865b --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/TestPermissionUtil.kt @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2020 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. + */ + +@file:JvmName("TestPermissionUtil") + +package com.android.testutils + +import androidx.test.platform.app.InstrumentationRegistry +import com.android.testutils.ExceptionUtils.ThrowingRunnable +import com.android.testutils.ExceptionUtils.ThrowingSupplier + +/** + * Run the specified [task] with the specified [permissions] obtained through shell + * permission identity. + * + * Passing in an empty list of permissions can grant all shell permissions, but this is + * discouraged as it also causes the process to temporarily lose non-shell permissions. + */ +fun runAsShell(vararg permissions: String, task: () -> T): T { + val autom = InstrumentationRegistry.getInstrumentation().uiAutomation + autom.adoptShellPermissionIdentity(*permissions) + try { + return task() + } finally { + autom.dropShellPermissionIdentity() + } +} + +/** + * Convenience overload of [runAsShell] that uses a [ThrowingSupplier] for Java callers, when + * only one/two/three permissions are needed. + */ +@JvmOverloads +fun runAsShell( + perm1: String, + perm2: String = "", + perm3: String = "", + supplier: ThrowingSupplier +): T = runAsShell(*getNonEmptyVarargs(perm1, perm2, perm3)) { supplier.get() } + +/** + * Convenience overload of [runAsShell] that uses a [ThrowingRunnable] for Java callers, when + * only one/two/three permissions are needed. + */ +@JvmOverloads +fun runAsShell( + perm1: String, + perm2: String = "", + perm3: String = "", + runnable: ThrowingRunnable +): Unit = runAsShell(*getNonEmptyVarargs(perm1, perm2, perm3)) { runnable.run() } + +/** + * Get an array containing the first consecutive non-empty arguments out of three arguments. + * + * The first argument is assumed to be non-empty. + */ +private fun getNonEmptyVarargs(arg1: String, arg2: String, arg3: String): Array { + return when { + arg2 == "" -> arrayOf(arg1) + arg3 == "" -> arrayOf(arg1, arg2) + else -> arrayOf(arg1, arg2, arg3) + } +} \ No newline at end of file From 3b1e9265eba68b8c4b9e831d624f1ddc7d412e18 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 23 Sep 2020 15:13:40 +0900 Subject: [PATCH 056/777] Add TapPacketReader#startAsyncForTest, poll Add a startAsyncForTest method to attempt to start the TapPacketReader on its handler thread. The method will not report failures to start (especially failures to create the socket), so it is only added in TapPacketReader for test code, and not FdEventsReader which would be in production code. Rename popPacket to poll, keeping the old version as deprecated for compatibility. "pop" normally refers to removing a packet from the top of a LIFO stack, so it is not appropriate naming here. Test: m Bug: 168868607 Change-Id: I19184aaca018165856d1d5e5d24b976ae75d1664 --- .../android/testutils/TapPacketReader.java | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/staticlibs/devicetests/com/android/testutils/TapPacketReader.java b/staticlibs/devicetests/com/android/testutils/TapPacketReader.java index c36f144584..001b709903 100644 --- a/staticlibs/devicetests/com/android/testutils/TapPacketReader.java +++ b/staticlibs/devicetests/com/android/testutils/TapPacketReader.java @@ -50,6 +50,17 @@ public class TapPacketReader extends PacketReader { mTapFd = tapFd; } + + /** + * Attempt to start the FdEventsReader on its handler thread. + * + * As opposed to {@link android.net.util.FdEventsReader#start()}, this method will not report + * failure to start, so it is only appropriate in tests that will fail later if that happens. + */ + public void startAsyncForTest() { + getHandler().post(this::start); + } + @Override protected FileDescriptor createFd() { return mTapFd; @@ -63,11 +74,31 @@ public class TapPacketReader extends PacketReader { } } + /** + * @deprecated This method does not actually "pop" (which generally means the last packet). + * Use {@link #poll(long)}, which has the same behavior, instead. + */ + @Nullable + @Deprecated + public byte[] popPacket(long timeoutMs) { + return poll(timeoutMs); + } + + /** + * @deprecated This method does not actually "pop" (which generally means the last packet). + * Use {@link #poll(long, Predicate)}, which has the same behavior, instead. + */ + @Nullable + @Deprecated + public byte[] popPacket(long timeoutMs, @NonNull Predicate filter) { + return poll(timeoutMs, filter); + } + /** * Get the next packet that was received on the interface. */ @Nullable - public byte[] popPacket(long timeoutMs) { + public byte[] poll(long timeoutMs) { return mReadHead.getValue().poll(timeoutMs, packet -> true); } @@ -75,7 +106,7 @@ public class TapPacketReader extends PacketReader { * Get the next packet that was received on the interface and matches the specified filter. */ @Nullable - public byte[] popPacket(long timeoutMs, @NonNull Predicate filter) { + public byte[] poll(long timeoutMs, @NonNull Predicate filter) { return mReadHead.getValue().poll(timeoutMs, filter::test); } From ba792733824e4927943bede2b2380d37ce283ff0 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 26 Jun 2020 18:34:52 +0900 Subject: [PATCH 057/777] Move util classes to their destination package Test: builds Change-Id: I93e9cfd968e08f983e3fd9f7196c455c79a0f32d (cherry picked from commit 7c9c12694aec7d688496a634f165661e0681773e) --- staticlibs/Android.bp | 11 ++++++++--- .../android/net/module}/util/FdEventsReader.java | 9 ++++----- .../android/net/module}/util/PacketReader.java | 3 +-- .../com/android/testutils/TapPacketReader.java | 2 +- .../android/net/module/util}/DnsSdTxtRecord.java | 2 +- .../net => com/android/net/module}/util/IpRange.java | 2 +- .../android/net/module}/util/LinkPropertiesUtils.java | 2 +- .../android/net/module}/util/MacAddressUtils.java | 2 +- .../net => com/android/net/module}/util/NetUtils.java | 2 +- staticlibs/jarjar-rules-shared.txt | 6 ------ staticlibs/tests/unit/Android.bp | 1 - staticlibs/tests/unit/AndroidManifest.xml | 2 ++ staticlibs/tests/unit/jarjar-rules.txt | 6 ------ .../tests/unit/src/android/net/util/IpRangeTest.java | 2 ++ .../src/android/net/util/LinkPropertiesUtilsTest.java | 6 ++++-- .../src/android/net/util/MacAddressUtilsTest.java | 2 ++ .../tests/unit/src/android/net/util/NetUtilsTest.java | 2 ++ .../com/android/net/module/util/PacketReaderTest.java | 7 ++----- 18 files changed, 33 insertions(+), 36 deletions(-) rename staticlibs/device/{android/net => com/android/net/module}/util/FdEventsReader.java (98%) rename staticlibs/device/{android/net => com/android/net/module}/util/PacketReader.java (94%) rename staticlibs/framework/{android/net/util/nsd => com/android/net/module/util}/DnsSdTxtRecord.java (99%) rename staticlibs/framework/{android/net => com/android/net/module}/util/IpRange.java (99%) rename staticlibs/framework/{android/net => com/android/net/module}/util/LinkPropertiesUtils.java (99%) rename staticlibs/framework/{android/net => com/android/net/module}/util/MacAddressUtils.java (99%) rename staticlibs/framework/{android/net => com/android/net/module}/util/NetUtils.java (98%) delete mode 100644 staticlibs/tests/unit/jarjar-rules.txt diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index f4799f0c50..08f4c0e0a1 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -86,6 +86,13 @@ java_defaults { ], } +// Rules for moving classes part of the lib that haven't been +// renamed yet for lack of time +java_defaults { + name: "net-utils-jarjar-shared", + jarjar_rules: "jarjar-rules-shared.txt", +} + java_library { name: "net-tests-utils", srcs: [ @@ -164,8 +171,6 @@ filegroup { filegroup { name: "net-utils-framework-wifi-common-srcs", srcs: [ - "framework/android/net/util/nsd/DnsSdTxtRecord.java", - "framework/android/net/util/MacAddressUtils.java", "framework/com/android/net/module/util/**/*.java", ], path: "framework", @@ -181,7 +186,7 @@ filegroup { name: "net-utils-wifi-service-common-srcs", srcs: [ "device/android/net/NetworkFactory.java", - "framework/android/net/util/NetUtils.java", + "framework/com/android/net/module/util/NetUtils.java", ], visibility: [ "//frameworks/opt/net/wifi/service", diff --git a/staticlibs/device/android/net/util/FdEventsReader.java b/staticlibs/device/com/android/net/module/util/FdEventsReader.java similarity index 98% rename from staticlibs/device/android/net/util/FdEventsReader.java rename to staticlibs/device/com/android/net/module/util/FdEventsReader.java index a5714aa5db..71ae13d80d 100644 --- a/staticlibs/device/android/net/util/FdEventsReader.java +++ b/staticlibs/device/com/android/net/module/util/FdEventsReader.java @@ -14,12 +14,14 @@ * limitations under the License. */ -// TODO : move this and PacketReader to com.android.net.module.util. -package android.net.util; +package com.android.net.module.util; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.util.SocketUtils; import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; @@ -27,9 +29,6 @@ import android.system.ErrnoException; import android.system.OsConstants; import android.util.Log; -import android.annotation.NonNull; -import android.annotation.Nullable; - import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; diff --git a/staticlibs/device/android/net/util/PacketReader.java b/staticlibs/device/com/android/net/module/util/PacketReader.java similarity index 94% rename from staticlibs/device/android/net/util/PacketReader.java rename to staticlibs/device/com/android/net/module/util/PacketReader.java index 61b3d6e294..66c47888c3 100644 --- a/staticlibs/device/android/net/util/PacketReader.java +++ b/staticlibs/device/com/android/net/module/util/PacketReader.java @@ -14,8 +14,7 @@ * limitations under the License. */ -// TODO : move this and FdEventsReader to com.android.net.module.util. -package android.net.util; +package com.android.net.module.util; import static java.lang.Math.max; diff --git a/staticlibs/devicetests/com/android/testutils/TapPacketReader.java b/staticlibs/devicetests/com/android/testutils/TapPacketReader.java index c36f144584..52c4cc9344 100644 --- a/staticlibs/devicetests/com/android/testutils/TapPacketReader.java +++ b/staticlibs/devicetests/com/android/testutils/TapPacketReader.java @@ -16,13 +16,13 @@ package com.android.testutils; -import android.net.util.PacketReader; import android.os.Handler; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.net.module.util.ArrayTrackRecord; +import com.android.net.module.util.PacketReader; import java.io.FileDescriptor; import java.io.FileOutputStream; diff --git a/staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java b/staticlibs/framework/com/android/net/module/util/DnsSdTxtRecord.java similarity index 99% rename from staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java rename to staticlibs/framework/com/android/net/module/util/DnsSdTxtRecord.java index 81768f7ed1..760891b9fc 100644 --- a/staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java +++ b/staticlibs/framework/com/android/net/module/util/DnsSdTxtRecord.java @@ -19,7 +19,7 @@ - fix set() to replace existing values */ -package android.net.util.nsd; +package com.android.net.module.util; import android.os.Parcelable; import android.os.Parcel; diff --git a/staticlibs/framework/android/net/util/IpRange.java b/staticlibs/framework/com/android/net/module/util/IpRange.java similarity index 99% rename from staticlibs/framework/android/net/util/IpRange.java rename to staticlibs/framework/com/android/net/module/util/IpRange.java index 099770bca4..40b57b10f0 100644 --- a/staticlibs/framework/android/net/util/IpRange.java +++ b/staticlibs/framework/com/android/net/module/util/IpRange.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import static com.android.internal.annotations.VisibleForTesting.Visibility; diff --git a/staticlibs/framework/android/net/util/LinkPropertiesUtils.java b/staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java similarity index 99% rename from staticlibs/framework/android/net/util/LinkPropertiesUtils.java rename to staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java index 282fa10d2b..1565f2bc2f 100644 --- a/staticlibs/framework/android/net/util/LinkPropertiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/staticlibs/framework/android/net/util/MacAddressUtils.java b/staticlibs/framework/com/android/net/module/util/MacAddressUtils.java similarity index 99% rename from staticlibs/framework/android/net/util/MacAddressUtils.java rename to staticlibs/framework/com/android/net/module/util/MacAddressUtils.java index 969d1270be..bc11fa2a7c 100644 --- a/staticlibs/framework/android/net/util/MacAddressUtils.java +++ b/staticlibs/framework/com/android/net/module/util/MacAddressUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/staticlibs/framework/android/net/util/NetUtils.java b/staticlibs/framework/com/android/net/module/util/NetUtils.java similarity index 98% rename from staticlibs/framework/android/net/util/NetUtils.java rename to staticlibs/framework/com/android/net/module/util/NetUtils.java index 302119ea11..4331b65de0 100644 --- a/staticlibs/framework/android/net/util/NetUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/staticlibs/jarjar-rules-shared.txt b/staticlibs/jarjar-rules-shared.txt index 9e618db19b..a7fda7c0ac 100644 --- a/staticlibs/jarjar-rules-shared.txt +++ b/staticlibs/jarjar-rules-shared.txt @@ -1,8 +1,2 @@ -# TODO: move the classes to the target package in java -rule android.net.util.IpRange* com.android.net.module.util.IpRange@1 -rule android.net.util.MacAddressUtils* com.android.net.module.util.MacAddressUtils@1 -rule android.net.util.LinkPropertiesUtils* com.android.net.module.util.LinkPropertiesUtils@1 -rule android.net.util.NetUtils* com.android.net.module.util.NetUtils@1 -rule android.net.util.nsd.** com.android.net.module.util.nsd.@1 rule android.annotation.** com.android.net.module.annotation.@1 rule com.android.internal.annotations.** com.android.net.module.annotation.@1 diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index f18ffcfdd5..cb2c7d8255 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -6,7 +6,6 @@ android_library { name: "NetworkStaticLibTestsLib", srcs: ["src/**/*.java","src/**/*.kt"], min_sdk_version: "29", - jarjar_rules: "jarjar-rules.txt", static_libs: [ "net-utils-framework-common", "androidx.test.rules", diff --git a/staticlibs/tests/unit/AndroidManifest.xml b/staticlibs/tests/unit/AndroidManifest.xml index cc9e09ea76..c747c8a585 100644 --- a/staticlibs/tests/unit/AndroidManifest.xml +++ b/staticlibs/tests/unit/AndroidManifest.xml @@ -17,6 +17,8 @@ + + diff --git a/staticlibs/tests/unit/jarjar-rules.txt b/staticlibs/tests/unit/jarjar-rules.txt deleted file mode 100644 index fceccfb755..0000000000 --- a/staticlibs/tests/unit/jarjar-rules.txt +++ /dev/null @@ -1,6 +0,0 @@ -# TODO: move the classes to the target package in java -rule android.net.util.IpRange* com.android.net.module.util.IpRange@1 -rule android.net.util.MacAddressUtils* com.android.net.module.util.MacAddressUtils@1 -rule android.net.util.LinkPropertiesUtils* com.android.net.module.util.LinkPropertiesUtils@1 -rule android.net.util.NetUtils* com.android.net.module.util.NetUtils@1 -rule android.net.util.nsd.** com.android.net.module.util.nsd.@1 diff --git a/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java b/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java index f4d07e9b3e..677db6956f 100644 --- a/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java +++ b/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java @@ -28,6 +28,8 @@ import android.net.IpPrefix; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.IpRange; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java index 6ffcc1d0a9..342e9d7b49 100644 --- a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java @@ -26,11 +26,13 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.ProxyInfo; import android.net.RouteInfo; -import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult; -import android.net.util.LinkPropertiesUtils.CompareResult; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.LinkPropertiesUtils; +import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult; +import com.android.net.module.util.LinkPropertiesUtils.CompareResult; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java index ad63b3c9eb..66d89ffd1d 100644 --- a/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java @@ -24,6 +24,8 @@ import android.net.MacAddress; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.MacAddressUtils; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java index 903e80d369..338d1c80fe 100644 --- a/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java @@ -27,6 +27,8 @@ import android.net.RouteInfo; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.NetUtils; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java index 046a1d9d15..459801c272 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java @@ -16,7 +16,6 @@ package com.android.net.module.util; -import static android.net.util.PacketReader.DEFAULT_RECV_BUF_SIZE; import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; @@ -24,14 +23,13 @@ import static android.system.OsConstants.SOCK_NONBLOCK; import static android.system.OsConstants.SOL_SOCKET; import static android.system.OsConstants.SO_SNDTIMEO; +import static com.android.net.module.util.PacketReader.DEFAULT_RECV_BUF_SIZE; import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import android.net.util.PacketReader; import android.os.Handler; import android.os.HandlerThread; import android.system.ErrnoException; @@ -93,8 +91,7 @@ public class PacketReaderTest { Os.setsockoptTimeval(s, SOL_SOCKET, SO_SNDTIMEO, TIMEO); } catch (ErrnoException | SocketException e) { closeFd(s); - fail(); - return null; + throw new RuntimeException("Failed to create FD", e); } mLocalSocket = s; From b904113030a710683aff37a22b756b39c493e870 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 24 Sep 2020 10:02:16 +0900 Subject: [PATCH 058/777] Add TapPacketReaderRule This test rule allows tests to easily create a tap interface, a TapPacketReader on it, and tear them down after the test. Bug: 168868607 Test: atest NetworkStackIntegrationTests Change-Id: Ibc167f5c9a8a1b295e8f6c8384a55a1e3410fcdc --- .../android/testutils/TapPacketReaderRule.kt | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 staticlibs/devicetests/com/android/testutils/TapPacketReaderRule.kt diff --git a/staticlibs/devicetests/com/android/testutils/TapPacketReaderRule.kt b/staticlibs/devicetests/com/android/testutils/TapPacketReaderRule.kt new file mode 100644 index 0000000000..3319fbe197 --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/TapPacketReaderRule.kt @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2020 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 com.android.testutils + +import android.Manifest.permission.MANAGE_TEST_NETWORKS +import android.net.TestNetworkInterface +import android.net.TestNetworkManager +import android.os.HandlerThread +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runners.model.Statement +import kotlin.test.assertFalse +import kotlin.test.fail + +private const val HANDLER_TIMEOUT_MS = 10_000L + +/** + * A [TestRule] that sets up a [TapPacketReader] on a [TestNetworkInterface] for use in the test. + */ +class TapPacketReaderRule @JvmOverloads constructor( + private val maxPacketSize: Int = 1500 +) : TestRule { + // Use lateinit as the below members can't be initialized in the rule constructor (the + // InstrumentationRegistry may not be ready), but from the point of view of test cases using + // this rule, the members are always initialized (in setup/test/teardown): tests cases should be + // able use them directly. + // lateinit also allows getting good exceptions detailing what went wrong in the unlikely event + // that the members are referenced before they could be initialized. + lateinit var iface: TestNetworkInterface + lateinit var reader: TapPacketReader + + // The reader runs on its own handlerThread created locally, but this is not an actual + // requirement: any handler could be used for this rule. If using a specific handler is needed, + // a method could be added to start the TapPacketReader manually on a given handler. + private val handlerThread = HandlerThread(TapPacketReaderRule::class.java.simpleName) + + override fun apply(base: Statement, description: Description): Statement { + return TapReaderStatement(base) + } + + private inner class TapReaderStatement(private val base: Statement) : Statement() { + override fun evaluate() { + val ctx: android.content.Context = InstrumentationRegistry.getInstrumentation().context + iface = runAsShell(MANAGE_TEST_NETWORKS) { + val tnm = ctx.getSystemService(TestNetworkManager::class.java) + ?: fail("Could not obtain the TestNetworkManager") + tnm.createTapInterface() + } + + handlerThread.start() + reader = TapPacketReader(handlerThread.threadHandler, + iface.fileDescriptor.fileDescriptor, maxPacketSize) + reader.startAsyncForTest() + + try { + base.evaluate() + } finally { + handlerThread.threadHandler.post(reader::stop) + handlerThread.quitSafely() + handlerThread.join(HANDLER_TIMEOUT_MS) + assertFalse(handlerThread.isAlive, + "HandlerThread did not exit within $HANDLER_TIMEOUT_MS ms") + iface.fileDescriptor.close() + } + } + } +} \ No newline at end of file From 197891988582ae2f000939b0c70ae530628ba09f Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 1 Oct 2020 12:45:31 +0900 Subject: [PATCH 059/777] Add visibility of this lib to wifi tests Test: this builds, and subsequent patches using this work Change-Id: I8d59b39e6554eccd22695dda47c41b1f2f661495 --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index f4799f0c50..e5cc8b1f7c 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -126,6 +126,7 @@ java_library { "//frameworks/base/packages/Tethering", "//frameworks/opt/net/ike", "//frameworks/opt/telephony", + "//frameworks/base/wifi:__subpackages__", "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", From 2344486963ee523d03bdb1390997c22d05f8249e Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Thu, 1 Oct 2020 20:12:46 +0000 Subject: [PATCH 060/777] Revert "Move util classes to their destination package" Revert "Move PacketReader and FdEventReader" Revert "Move static utils to a module package" Revert "Move static utils to a module package" Revert submission 12698912-move_packetreader Reason for revert: Broke presubmit on git_master, b/169861635 Reverted Changes: If5d1e4a58:Move module utils to the module package. I44ffaad3d:Move PacketReader and FdEventReader I93e9cfd96:Move util classes to their destination package Ia84d64130:Move static utils to a module package Iaac2810c7:Move static utils to a module package Change-Id: I6104ea5392b26069da9a54f3073fd408a0bc37a0 --- staticlibs/Android.bp | 11 +++-------- .../module => android/net}/util/FdEventsReader.java | 9 +++++---- .../net/module => android/net}/util/PacketReader.java | 3 ++- .../com/android/testutils/TapPacketReader.java | 2 +- .../net/module => android/net}/util/IpRange.java | 2 +- .../net}/util/LinkPropertiesUtils.java | 2 +- .../module => android/net}/util/MacAddressUtils.java | 2 +- .../net/module => android/net}/util/NetUtils.java | 2 +- .../util => android/net/util/nsd}/DnsSdTxtRecord.java | 2 +- staticlibs/jarjar-rules-shared.txt | 6 ++++++ staticlibs/tests/unit/Android.bp | 1 + staticlibs/tests/unit/AndroidManifest.xml | 2 -- staticlibs/tests/unit/jarjar-rules.txt | 6 ++++++ .../tests/unit/src/android/net/util/IpRangeTest.java | 2 -- .../src/android/net/util/LinkPropertiesUtilsTest.java | 6 ++---- .../src/android/net/util/MacAddressUtilsTest.java | 2 -- .../tests/unit/src/android/net/util/NetUtilsTest.java | 2 -- .../com/android/net/module/util/PacketReaderTest.java | 7 +++++-- 18 files changed, 36 insertions(+), 33 deletions(-) rename staticlibs/device/{com/android/net/module => android/net}/util/FdEventsReader.java (98%) rename staticlibs/device/{com/android/net/module => android/net}/util/PacketReader.java (94%) rename staticlibs/framework/{com/android/net/module => android/net}/util/IpRange.java (99%) rename staticlibs/framework/{com/android/net/module => android/net}/util/LinkPropertiesUtils.java (99%) rename staticlibs/framework/{com/android/net/module => android/net}/util/MacAddressUtils.java (99%) rename staticlibs/framework/{com/android/net/module => android/net}/util/NetUtils.java (98%) rename staticlibs/framework/{com/android/net/module/util => android/net/util/nsd}/DnsSdTxtRecord.java (99%) create mode 100644 staticlibs/tests/unit/jarjar-rules.txt diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 08f4c0e0a1..f4799f0c50 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -86,13 +86,6 @@ java_defaults { ], } -// Rules for moving classes part of the lib that haven't been -// renamed yet for lack of time -java_defaults { - name: "net-utils-jarjar-shared", - jarjar_rules: "jarjar-rules-shared.txt", -} - java_library { name: "net-tests-utils", srcs: [ @@ -171,6 +164,8 @@ filegroup { filegroup { name: "net-utils-framework-wifi-common-srcs", srcs: [ + "framework/android/net/util/nsd/DnsSdTxtRecord.java", + "framework/android/net/util/MacAddressUtils.java", "framework/com/android/net/module/util/**/*.java", ], path: "framework", @@ -186,7 +181,7 @@ filegroup { name: "net-utils-wifi-service-common-srcs", srcs: [ "device/android/net/NetworkFactory.java", - "framework/com/android/net/module/util/NetUtils.java", + "framework/android/net/util/NetUtils.java", ], visibility: [ "//frameworks/opt/net/wifi/service", diff --git a/staticlibs/device/com/android/net/module/util/FdEventsReader.java b/staticlibs/device/android/net/util/FdEventsReader.java similarity index 98% rename from staticlibs/device/com/android/net/module/util/FdEventsReader.java rename to staticlibs/device/android/net/util/FdEventsReader.java index 71ae13d80d..a5714aa5db 100644 --- a/staticlibs/device/com/android/net/module/util/FdEventsReader.java +++ b/staticlibs/device/android/net/util/FdEventsReader.java @@ -14,14 +14,12 @@ * limitations under the License. */ -package com.android.net.module.util; +// TODO : move this and PacketReader to com.android.net.module.util. +package android.net.util; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.util.SocketUtils; import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; @@ -29,6 +27,9 @@ import android.system.ErrnoException; import android.system.OsConstants; import android.util.Log; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; diff --git a/staticlibs/device/com/android/net/module/util/PacketReader.java b/staticlibs/device/android/net/util/PacketReader.java similarity index 94% rename from staticlibs/device/com/android/net/module/util/PacketReader.java rename to staticlibs/device/android/net/util/PacketReader.java index 66c47888c3..61b3d6e294 100644 --- a/staticlibs/device/com/android/net/module/util/PacketReader.java +++ b/staticlibs/device/android/net/util/PacketReader.java @@ -14,7 +14,8 @@ * limitations under the License. */ -package com.android.net.module.util; +// TODO : move this and FdEventsReader to com.android.net.module.util. +package android.net.util; import static java.lang.Math.max; diff --git a/staticlibs/devicetests/com/android/testutils/TapPacketReader.java b/staticlibs/devicetests/com/android/testutils/TapPacketReader.java index 52c4cc9344..c36f144584 100644 --- a/staticlibs/devicetests/com/android/testutils/TapPacketReader.java +++ b/staticlibs/devicetests/com/android/testutils/TapPacketReader.java @@ -16,13 +16,13 @@ package com.android.testutils; +import android.net.util.PacketReader; import android.os.Handler; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.net.module.util.ArrayTrackRecord; -import com.android.net.module.util.PacketReader; import java.io.FileDescriptor; import java.io.FileOutputStream; diff --git a/staticlibs/framework/com/android/net/module/util/IpRange.java b/staticlibs/framework/android/net/util/IpRange.java similarity index 99% rename from staticlibs/framework/com/android/net/module/util/IpRange.java rename to staticlibs/framework/android/net/util/IpRange.java index 40b57b10f0..099770bca4 100644 --- a/staticlibs/framework/com/android/net/module/util/IpRange.java +++ b/staticlibs/framework/android/net/util/IpRange.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.net.module.util; +package android.net.util; import static com.android.internal.annotations.VisibleForTesting.Visibility; diff --git a/staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java b/staticlibs/framework/android/net/util/LinkPropertiesUtils.java similarity index 99% rename from staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java rename to staticlibs/framework/android/net/util/LinkPropertiesUtils.java index 1565f2bc2f..282fa10d2b 100644 --- a/staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java +++ b/staticlibs/framework/android/net/util/LinkPropertiesUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.net.module.util; +package android.net.util; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/staticlibs/framework/com/android/net/module/util/MacAddressUtils.java b/staticlibs/framework/android/net/util/MacAddressUtils.java similarity index 99% rename from staticlibs/framework/com/android/net/module/util/MacAddressUtils.java rename to staticlibs/framework/android/net/util/MacAddressUtils.java index bc11fa2a7c..969d1270be 100644 --- a/staticlibs/framework/com/android/net/module/util/MacAddressUtils.java +++ b/staticlibs/framework/android/net/util/MacAddressUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.net.module.util; +package android.net.util; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/staticlibs/framework/com/android/net/module/util/NetUtils.java b/staticlibs/framework/android/net/util/NetUtils.java similarity index 98% rename from staticlibs/framework/com/android/net/module/util/NetUtils.java rename to staticlibs/framework/android/net/util/NetUtils.java index 4331b65de0..302119ea11 100644 --- a/staticlibs/framework/com/android/net/module/util/NetUtils.java +++ b/staticlibs/framework/android/net/util/NetUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.net.module.util; +package android.net.util; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/staticlibs/framework/com/android/net/module/util/DnsSdTxtRecord.java b/staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java similarity index 99% rename from staticlibs/framework/com/android/net/module/util/DnsSdTxtRecord.java rename to staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java index 760891b9fc..81768f7ed1 100644 --- a/staticlibs/framework/com/android/net/module/util/DnsSdTxtRecord.java +++ b/staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java @@ -19,7 +19,7 @@ - fix set() to replace existing values */ -package com.android.net.module.util; +package android.net.util.nsd; import android.os.Parcelable; import android.os.Parcel; diff --git a/staticlibs/jarjar-rules-shared.txt b/staticlibs/jarjar-rules-shared.txt index a7fda7c0ac..9e618db19b 100644 --- a/staticlibs/jarjar-rules-shared.txt +++ b/staticlibs/jarjar-rules-shared.txt @@ -1,2 +1,8 @@ +# TODO: move the classes to the target package in java +rule android.net.util.IpRange* com.android.net.module.util.IpRange@1 +rule android.net.util.MacAddressUtils* com.android.net.module.util.MacAddressUtils@1 +rule android.net.util.LinkPropertiesUtils* com.android.net.module.util.LinkPropertiesUtils@1 +rule android.net.util.NetUtils* com.android.net.module.util.NetUtils@1 +rule android.net.util.nsd.** com.android.net.module.util.nsd.@1 rule android.annotation.** com.android.net.module.annotation.@1 rule com.android.internal.annotations.** com.android.net.module.annotation.@1 diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index cb2c7d8255..f18ffcfdd5 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -6,6 +6,7 @@ android_library { name: "NetworkStaticLibTestsLib", srcs: ["src/**/*.java","src/**/*.kt"], min_sdk_version: "29", + jarjar_rules: "jarjar-rules.txt", static_libs: [ "net-utils-framework-common", "androidx.test.rules", diff --git a/staticlibs/tests/unit/AndroidManifest.xml b/staticlibs/tests/unit/AndroidManifest.xml index c747c8a585..cc9e09ea76 100644 --- a/staticlibs/tests/unit/AndroidManifest.xml +++ b/staticlibs/tests/unit/AndroidManifest.xml @@ -17,8 +17,6 @@ - - diff --git a/staticlibs/tests/unit/jarjar-rules.txt b/staticlibs/tests/unit/jarjar-rules.txt new file mode 100644 index 0000000000..fceccfb755 --- /dev/null +++ b/staticlibs/tests/unit/jarjar-rules.txt @@ -0,0 +1,6 @@ +# TODO: move the classes to the target package in java +rule android.net.util.IpRange* com.android.net.module.util.IpRange@1 +rule android.net.util.MacAddressUtils* com.android.net.module.util.MacAddressUtils@1 +rule android.net.util.LinkPropertiesUtils* com.android.net.module.util.LinkPropertiesUtils@1 +rule android.net.util.NetUtils* com.android.net.module.util.NetUtils@1 +rule android.net.util.nsd.** com.android.net.module.util.nsd.@1 diff --git a/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java b/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java index 677db6956f..f4d07e9b3e 100644 --- a/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java +++ b/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java @@ -28,8 +28,6 @@ import android.net.IpPrefix; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.net.module.util.IpRange; - import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java index 342e9d7b49..6ffcc1d0a9 100644 --- a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java @@ -26,13 +26,11 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.ProxyInfo; import android.net.RouteInfo; +import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult; +import android.net.util.LinkPropertiesUtils.CompareResult; import androidx.test.runner.AndroidJUnit4; -import com.android.net.module.util.LinkPropertiesUtils; -import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult; -import com.android.net.module.util.LinkPropertiesUtils.CompareResult; - import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java index 66d89ffd1d..ad63b3c9eb 100644 --- a/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java @@ -24,8 +24,6 @@ import android.net.MacAddress; import androidx.test.runner.AndroidJUnit4; -import com.android.net.module.util.MacAddressUtils; - import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java index 338d1c80fe..903e80d369 100644 --- a/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java @@ -27,8 +27,6 @@ import android.net.RouteInfo; import androidx.test.runner.AndroidJUnit4; -import com.android.net.module.util.NetUtils; - import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java index 459801c272..046a1d9d15 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java @@ -16,6 +16,7 @@ package com.android.net.module.util; +import static android.net.util.PacketReader.DEFAULT_RECV_BUF_SIZE; import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; @@ -23,13 +24,14 @@ import static android.system.OsConstants.SOCK_NONBLOCK; import static android.system.OsConstants.SOL_SOCKET; import static android.system.OsConstants.SO_SNDTIMEO; -import static com.android.net.module.util.PacketReader.DEFAULT_RECV_BUF_SIZE; import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import android.net.util.PacketReader; import android.os.Handler; import android.os.HandlerThread; import android.system.ErrnoException; @@ -91,7 +93,8 @@ public class PacketReaderTest { Os.setsockoptTimeval(s, SOL_SOCKET, SO_SNDTIMEO, TIMEO); } catch (ErrnoException | SocketException e) { closeFd(s); - throw new RuntimeException("Failed to create FD", e); + fail(); + return null; } mLocalSocket = s; From 539aece60fd252de3739b7ee870ab8763b0f20aa Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 25 Sep 2020 13:03:42 +0900 Subject: [PATCH 061/777] Add autoStart parameter to TapPacketReader rule Setting autoStart to false allows tests to manually start the TapPacketReader rule, either via method call (allowing callers to specify their own Handler) or an annotation. Bug: 168868607 Test: atest NetworkStackIntegrationTests using autoStart = false Change-Id: Ic295d659250795c45181dc3c0ac0aaacba854f0b --- .../android/testutils/TapPacketReaderRule.kt | 130 ++++++++++++++---- 1 file changed, 101 insertions(+), 29 deletions(-) diff --git a/staticlibs/devicetests/com/android/testutils/TapPacketReaderRule.kt b/staticlibs/devicetests/com/android/testutils/TapPacketReaderRule.kt index 3319fbe197..701666ca3f 100644 --- a/staticlibs/devicetests/com/android/testutils/TapPacketReaderRule.kt +++ b/staticlibs/devicetests/com/android/testutils/TapPacketReaderRule.kt @@ -19,6 +19,7 @@ package com.android.testutils import android.Manifest.permission.MANAGE_TEST_NETWORKS import android.net.TestNetworkInterface import android.net.TestNetworkManager +import android.os.Handler import android.os.HandlerThread import androidx.test.platform.app.InstrumentationRegistry import org.junit.rules.TestRule @@ -31,52 +32,123 @@ private const val HANDLER_TIMEOUT_MS = 10_000L /** * A [TestRule] that sets up a [TapPacketReader] on a [TestNetworkInterface] for use in the test. + * + * @param maxPacketSize Maximum size of packets read in the [TapPacketReader] buffer. + * @param autoStart Whether to initialize the interface and start the reader automatically for every + * test. If false, each test must either call start() and stop(), or be annotated + * with TapPacketReaderTest before using the reader or interface. */ class TapPacketReaderRule @JvmOverloads constructor( - private val maxPacketSize: Int = 1500 + private val maxPacketSize: Int = 1500, + private val autoStart: Boolean = true ) : TestRule { // Use lateinit as the below members can't be initialized in the rule constructor (the // InstrumentationRegistry may not be ready), but from the point of view of test cases using - // this rule, the members are always initialized (in setup/test/teardown): tests cases should be - // able use them directly. - // lateinit also allows getting good exceptions detailing what went wrong in the unlikely event - // that the members are referenced before they could be initialized. + // this rule with autoStart = true, the members are always initialized (in setup/test/teardown): + // tests cases should be able use them directly. + // lateinit also allows getting good exceptions detailing what went wrong if the members are + // referenced before they could be initialized (typically if autoStart is false and the test + // does not call start or use @TapPacketReaderTest). lateinit var iface: TestNetworkInterface lateinit var reader: TapPacketReader - // The reader runs on its own handlerThread created locally, but this is not an actual - // requirement: any handler could be used for this rule. If using a specific handler is needed, - // a method could be added to start the TapPacketReader manually on a given handler. - private val handlerThread = HandlerThread(TapPacketReaderRule::class.java.simpleName) + @Volatile + private var readerRunning = false - override fun apply(base: Statement, description: Description): Statement { - return TapReaderStatement(base) + /** + * Indicates that the [TapPacketReaderRule] should initialize its [TestNetworkInterface] and + * start the [TapPacketReader] before the test, and tear them down afterwards. + * + * For use when [TapPacketReaderRule] is created with autoStart = false. + */ + annotation class TapPacketReaderTest + + /** + * Initialize the tap interface and start the [TapPacketReader]. + * + * Tests using this method must also call [stop] before exiting. + * @param handler Handler to run the reader on. Callers are responsible for safely terminating + * the handler when the test ends. If null, a handler thread managed by the + * rule will be used. + */ + @JvmOverloads + fun start(handler: Handler? = null) { + if (this::iface.isInitialized) { + fail("${TapPacketReaderRule::class.java.simpleName} was already started") + } + + val ctx = InstrumentationRegistry.getInstrumentation().context + iface = runAsShell(MANAGE_TEST_NETWORKS) { + val tnm = ctx.getSystemService(TestNetworkManager::class.java) + ?: fail("Could not obtain the TestNetworkManager") + tnm.createTapInterface() + } + val usedHandler = handler ?: HandlerThread( + TapPacketReaderRule::class.java.simpleName).apply { start() }.threadHandler + reader = TapPacketReader(usedHandler, iface.fileDescriptor.fileDescriptor, maxPacketSize) + reader.startAsyncForTest() + readerRunning = true } - private inner class TapReaderStatement(private val base: Statement) : Statement() { - override fun evaluate() { - val ctx: android.content.Context = InstrumentationRegistry.getInstrumentation().context - iface = runAsShell(MANAGE_TEST_NETWORKS) { - val tnm = ctx.getSystemService(TestNetworkManager::class.java) - ?: fail("Could not obtain the TestNetworkManager") - tnm.createTapInterface() - } + /** + * Stop the [TapPacketReader]. + * + * Tests calling [start] must call this method before exiting. If a handler was specified in + * [start], all messages on that handler must also be processed after calling this method and + * before exiting. + * + * If [start] was not called, calling this method is a no-op. + */ + fun stop() { + // The reader may not be initialized if the test case did not use the rule, even though + // other test cases in the same class may be using it (so test classes may call stop in + // tearDown even if start is not called for all test cases). + if (!this::reader.isInitialized) return + reader.handler.post { + reader.stop() + readerRunning = false + } + } - handlerThread.start() - reader = TapPacketReader(handlerThread.threadHandler, - iface.fileDescriptor.fileDescriptor, maxPacketSize) - reader.startAsyncForTest() + override fun apply(base: Statement, description: Description): Statement { + return TapReaderStatement(base, description) + } + + private inner class TapReaderStatement( + private val base: Statement, + private val description: Description + ) : Statement() { + override fun evaluate() { + val shouldStart = autoStart || + description.getAnnotation(TapPacketReaderTest::class.java) != null + if (shouldStart) { + start() + } try { base.evaluate() } finally { - handlerThread.threadHandler.post(reader::stop) - handlerThread.quitSafely() - handlerThread.join(HANDLER_TIMEOUT_MS) - assertFalse(handlerThread.isAlive, - "HandlerThread did not exit within $HANDLER_TIMEOUT_MS ms") - iface.fileDescriptor.close() + if (shouldStart) { + stop() + reader.handler.looper.apply { + quitSafely() + thread.join(HANDLER_TIMEOUT_MS) + assertFalse(thread.isAlive, + "HandlerThread did not exit within $HANDLER_TIMEOUT_MS ms") + } + } + + if (this@TapPacketReaderRule::iface.isInitialized) { + iface.fileDescriptor.close() + } } + + assertFalse(readerRunning, + "stop() was not called, or the provided handler did not process the stop " + + "message before the test ended. If not using autostart, make sure to call " + + "stop() after the test. If a handler is specified in start(), make sure all " + + "messages are processed after calling stop(), before quitting (for example " + + "by using HandlerThread#quitSafely and HandlerThread#join).") } } } \ No newline at end of file From ff57cec7d16419415850bbdfcdcc2aa9869cbaad Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 25 Sep 2020 16:14:03 +0900 Subject: [PATCH 062/777] Move IpUtils to frameworks/libs/net The utility classes are useful for mainline modules and their tests, for example IpClientIntegrationTest. Bug: 168868607 Test: m && atest NetworkStackCoverageTests Change-Id: Ie3eea7731fa45cd58cd4acf8249da68ff3eb6a70 --- .../com/android/net/module/util/IpUtils.java | 151 ++++++++++++++++ .../android/net/module/util/IpUtilsTest.java | 166 ++++++++++++++++++ 2 files changed, 317 insertions(+) create mode 100644 staticlibs/framework/com/android/net/module/util/IpUtils.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/IpUtilsTest.java diff --git a/staticlibs/framework/com/android/net/module/util/IpUtils.java b/staticlibs/framework/com/android/net/module/util/IpUtils.java new file mode 100644 index 0000000000..54b4cdfd94 --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/IpUtils.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2015 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 com.android.net.module.util; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.nio.BufferOverflowException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.nio.ShortBuffer; + +import static android.system.OsConstants.IPPROTO_TCP; +import static android.system.OsConstants.IPPROTO_UDP; + +/** + * @hide + */ +public class IpUtils { + /** + * Converts a signed short value to an unsigned int value. Needed + * because Java does not have unsigned types. + */ + private static int intAbs(short v) { + return v & 0xFFFF; + } + + /** + * Performs an IP checksum (used in IP header and across UDP + * payload) on the specified portion of a ByteBuffer. The seed + * allows the checksum to commence with a specified value. + */ + private static int checksum(ByteBuffer buf, int seed, int start, int end) { + int sum = seed; + final int bufPosition = buf.position(); + + // set position of original ByteBuffer, so that the ShortBuffer + // will be correctly initialized + buf.position(start); + ShortBuffer shortBuf = buf.asShortBuffer(); + + // re-set ByteBuffer position + buf.position(bufPosition); + + final int numShorts = (end - start) / 2; + for (int i = 0; i < numShorts; i++) { + sum += intAbs(shortBuf.get(i)); + } + start += numShorts * 2; + + // see if a singleton byte remains + if (end != start) { + short b = buf.get(start); + + // make it unsigned + if (b < 0) { + b += 256; + } + + sum += b * 256; + } + + sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF); + sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF); + int negated = ~sum; + return intAbs((short) negated); + } + + private static int pseudoChecksumIPv4( + ByteBuffer buf, int headerOffset, int protocol, int transportLen) { + int partial = protocol + transportLen; + partial += intAbs(buf.getShort(headerOffset + 12)); + partial += intAbs(buf.getShort(headerOffset + 14)); + partial += intAbs(buf.getShort(headerOffset + 16)); + partial += intAbs(buf.getShort(headerOffset + 18)); + return partial; + } + + private static int pseudoChecksumIPv6( + ByteBuffer buf, int headerOffset, int protocol, int transportLen) { + int partial = protocol + transportLen; + for (int offset = 8; offset < 40; offset += 2) { + partial += intAbs(buf.getShort(headerOffset + offset)); + } + return partial; + } + + private static byte ipversion(ByteBuffer buf, int headerOffset) { + return (byte) ((buf.get(headerOffset) & (byte) 0xf0) >> 4); + } + + public static short ipChecksum(ByteBuffer buf, int headerOffset) { + byte ihl = (byte) (buf.get(headerOffset) & 0x0f); + return (short) checksum(buf, 0, headerOffset, headerOffset + ihl * 4); + } + + private static short transportChecksum(ByteBuffer buf, int protocol, + int ipOffset, int transportOffset, int transportLen) { + if (transportLen < 0) { + throw new IllegalArgumentException("Transport length < 0: " + transportLen); + } + int sum; + byte ver = ipversion(buf, ipOffset); + if (ver == 4) { + sum = pseudoChecksumIPv4(buf, ipOffset, protocol, transportLen); + } else if (ver == 6) { + sum = pseudoChecksumIPv6(buf, ipOffset, protocol, transportLen); + } else { + throw new UnsupportedOperationException("Checksum must be IPv4 or IPv6"); + } + + sum = checksum(buf, sum, transportOffset, transportOffset + transportLen); + if (protocol == IPPROTO_UDP && sum == 0) { + sum = (short) 0xffff; + } + return (short) sum; + } + + public static short udpChecksum(ByteBuffer buf, int ipOffset, int transportOffset) { + int transportLen = intAbs(buf.getShort(transportOffset + 4)); + return transportChecksum(buf, IPPROTO_UDP, ipOffset, transportOffset, transportLen); + } + + public static short tcpChecksum(ByteBuffer buf, int ipOffset, int transportOffset, + int transportLen) { + return transportChecksum(buf, IPPROTO_TCP, ipOffset, transportOffset, transportLen); + } + + public static String addressAndPortToString(InetAddress address, int port) { + return String.format( + (address instanceof Inet6Address) ? "[%s]:%d" : "%s:%d", + address.getHostAddress(), port); + } + + public static boolean isValidUdpOrTcpPort(int port) { + return port > 0 && port < 65536; + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/IpUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/IpUtilsTest.java new file mode 100644 index 0000000000..34683090ad --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/IpUtilsTest.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import static org.junit.Assert.assertEquals; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.nio.ByteBuffer; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class IpUtilsTest { + + private static final int IPV4_HEADER_LENGTH = 20; + private static final int IPV6_HEADER_LENGTH = 40; + private static final int TCP_HEADER_LENGTH = 20; + private static final int UDP_HEADER_LENGTH = 8; + private static final int IP_CHECKSUM_OFFSET = 10; + private static final int TCP_CHECKSUM_OFFSET = 16; + private static final int UDP_CHECKSUM_OFFSET = 6; + + private int getUnsignedByte(ByteBuffer buf, int offset) { + return buf.get(offset) & 0xff; + } + + private int getChecksum(ByteBuffer buf, int offset) { + return getUnsignedByte(buf, offset) * 256 + getUnsignedByte(buf, offset + 1); + } + + private void assertChecksumEquals(int expected, short actual) { + assertEquals(Integer.toHexString(expected), Integer.toHexString(actual & 0xffff)); + } + + // Generate test packets using Python code like this:: + // + // from scapy import all as scapy + // + // def JavaPacketDefinition(bytes): + // out = " ByteBuffer packet = ByteBuffer.wrap(new byte[] {\n " + // for i in xrange(len(bytes)): + // out += "(byte) 0x%02x" % ord(bytes[i]) + // if i < len(bytes) - 1: + // if i % 4 == 3: + // out += ",\n " + // else: + // out += ", " + // out += "\n });" + // return out + // + // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2") / + // scapy.UDP(sport=12345, dport=7) / + // "hello") + // print JavaPacketDefinition(str(packet)) + + @Test + public void testIpv6TcpChecksum() throws Exception { + // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80) / + // scapy.TCP(sport=12345, dport=7, + // seq=1692871236, ack=128376451, flags=16, + // window=32768) / + // "hello, world") + ByteBuffer packet = ByteBuffer.wrap(new byte[] { + (byte) 0x68, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x20, (byte) 0x06, (byte) 0x40, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, + (byte) 0x30, (byte) 0x39, (byte) 0x00, (byte) 0x07, + (byte) 0x64, (byte) 0xe7, (byte) 0x2a, (byte) 0x44, + (byte) 0x07, (byte) 0xa6, (byte) 0xde, (byte) 0x83, + (byte) 0x50, (byte) 0x10, (byte) 0x80, (byte) 0x00, + (byte) 0xee, (byte) 0x71, (byte) 0x00, (byte) 0x00, + (byte) 0x68, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, + (byte) 0x6f, (byte) 0x2c, (byte) 0x20, (byte) 0x77, + (byte) 0x6f, (byte) 0x72, (byte) 0x6c, (byte) 0x64 + }); + + // Check that a valid packet has checksum 0. + int transportLen = packet.limit() - IPV6_HEADER_LENGTH; + assertEquals(0, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen)); + + // Check that we can calculate the checksum from scratch. + int sumOffset = IPV6_HEADER_LENGTH + TCP_CHECKSUM_OFFSET; + int sum = getUnsignedByte(packet, sumOffset) * 256 + getUnsignedByte(packet, sumOffset + 1); + assertEquals(0xee71, sum); + + packet.put(sumOffset, (byte) 0); + packet.put(sumOffset + 1, (byte) 0); + assertChecksumEquals(sum, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen)); + + // Check that writing the checksum back into the packet results in a valid packet. + packet.putShort( + sumOffset, + IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen)); + assertEquals(0, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen)); + } + + @Test + public void testIpv4UdpChecksum() { + // packet = (scapy.IP(src="192.0.2.1", dst="192.0.2.2", tos=0x40) / + // scapy.UDP(sport=32012, dport=4500) / + // "\xff") + ByteBuffer packet = ByteBuffer.wrap(new byte[] { + (byte) 0x45, (byte) 0x40, (byte) 0x00, (byte) 0x1d, + (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, + (byte) 0x40, (byte) 0x11, (byte) 0xf6, (byte) 0x8b, + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x02, + (byte) 0x7d, (byte) 0x0c, (byte) 0x11, (byte) 0x94, + (byte) 0x00, (byte) 0x09, (byte) 0xee, (byte) 0x36, + (byte) 0xff + }); + + // Check that a valid packet has IP checksum 0 and UDP checksum 0xffff (0 is not a valid + // UDP checksum, so the udpChecksum rewrites 0 to 0xffff). + assertEquals(0, IpUtils.ipChecksum(packet, 0)); + assertEquals((short) 0xffff, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH)); + + // Check that we can calculate the checksums from scratch. + final int ipSumOffset = IP_CHECKSUM_OFFSET; + final int ipSum = getChecksum(packet, ipSumOffset); + assertEquals(0xf68b, ipSum); + + packet.put(ipSumOffset, (byte) 0); + packet.put(ipSumOffset + 1, (byte) 0); + assertChecksumEquals(ipSum, IpUtils.ipChecksum(packet, 0)); + + final int udpSumOffset = IPV4_HEADER_LENGTH + UDP_CHECKSUM_OFFSET; + final int udpSum = getChecksum(packet, udpSumOffset); + assertEquals(0xee36, udpSum); + + packet.put(udpSumOffset, (byte) 0); + packet.put(udpSumOffset + 1, (byte) 0); + assertChecksumEquals(udpSum, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH)); + + // Check that writing the checksums back into the packet results in a valid packet. + packet.putShort(ipSumOffset, IpUtils.ipChecksum(packet, 0)); + packet.putShort(udpSumOffset, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH)); + assertEquals(0, IpUtils.ipChecksum(packet, 0)); + assertEquals((short) 0xffff, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH)); + } +} From 8f415d0066ece3256bda07e741190875b22b9996 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 28 Sep 2020 19:12:54 +0900 Subject: [PATCH 063/777] Move NetworkStackConstants to frameworks/libs/net The class only contains constants that should be shareable between different modules and tests. Bug: 168868607 Test: m Change-Id: Ic382d24e73697d85d29fa226692bd0d64ffa0f1f --- staticlibs/Android.bp | 3 + .../module/util/NetworkStackConstants.java | 163 ++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/NetworkStackConstants.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index e5cc8b1f7c..252efb4e91 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -52,6 +52,9 @@ java_library { "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", ], + static_libs: [ + "net-utils-framework-common", + ], libs: [ "androidx.annotation_annotation", ], diff --git a/staticlibs/device/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/device/com/android/net/module/util/NetworkStackConstants.java new file mode 100644 index 0000000000..68da7c9e6a --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/NetworkStackConstants.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; + +import java.net.Inet4Address; + +/** + * Network constants used by the network stack. + */ +public final class NetworkStackConstants { + + /** + * Ethernet constants. + * + * See also: + * - https://tools.ietf.org/html/rfc894 + * - https://tools.ietf.org/html/rfc2464 + * - https://tools.ietf.org/html/rfc7042 + * - http://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml + * - http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml + */ + public static final int ETHER_DST_ADDR_OFFSET = 0; + public static final int ETHER_SRC_ADDR_OFFSET = 6; + public static final int ETHER_ADDR_LEN = 6; + public static final int ETHER_TYPE_OFFSET = 12; + public static final int ETHER_TYPE_LENGTH = 2; + public static final int ETHER_TYPE_ARP = 0x0806; + public static final int ETHER_TYPE_IPV4 = 0x0800; + public static final int ETHER_TYPE_IPV6 = 0x86dd; + public static final int ETHER_HEADER_LEN = 14; + public static final int ETHER_MTU = 1500; + + /** + * ARP constants. + * + * See also: + * - https://tools.ietf.org/html/rfc826 + * - http://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml + */ + public static final int ARP_PAYLOAD_LEN = 28; // For Ethernet+IPv4. + public static final int ARP_ETHER_IPV4_LEN = ARP_PAYLOAD_LEN + ETHER_HEADER_LEN; + public static final int ARP_REQUEST = 1; + public static final int ARP_REPLY = 2; + public static final int ARP_HWTYPE_RESERVED_LO = 0; + public static final int ARP_HWTYPE_ETHER = 1; + public static final int ARP_HWTYPE_RESERVED_HI = 0xffff; + + /** + * IPv4 Address Conflict Detection constants. + * + * See also: + * - https://tools.ietf.org/html/rfc5227 + */ + public static final int IPV4_CONFLICT_PROBE_NUM = 3; + public static final int IPV4_CONFLICT_ANNOUNCE_NUM = 2; + + /** + * IPv4 constants. + * + * See also: + * - https://tools.ietf.org/html/rfc791 + */ + public static final int IPV4_ADDR_BITS = 32; + public static final int IPV4_MIN_MTU = 68; + public static final int IPV4_MAX_MTU = 65_535; + public static final int IPV4_HEADER_MIN_LEN = 20; + public static final int IPV4_IHL_MASK = 0xf; + public static final int IPV4_FLAGS_OFFSET = 6; + public static final int IPV4_FRAGMENT_MASK = 0x1fff; + public static final int IPV4_PROTOCOL_OFFSET = 9; + public static final int IPV4_SRC_ADDR_OFFSET = 12; + public static final int IPV4_DST_ADDR_OFFSET = 16; + public static final int IPV4_ADDR_LEN = 4; + public static final Inet4Address IPV4_ADDR_ALL = intToInet4AddressHTH(0xffffffff); + public static final Inet4Address IPV4_ADDR_ANY = intToInet4AddressHTH(0x0); + + /** + * IPv6 constants. + * + * See also: + * - https://tools.ietf.org/html/rfc2460 + */ + public static final int IPV6_ADDR_LEN = 16; + public static final int IPV6_HEADER_LEN = 40; + public static final int IPV6_LEN_OFFSET = 4; + public static final int IPV6_PROTOCOL_OFFSET = 6; + public static final int IPV6_SRC_ADDR_OFFSET = 8; + public static final int IPV6_DST_ADDR_OFFSET = 24; + public static final int IPV6_MIN_MTU = 1280; + + /** + * ICMPv6 constants. + * + * See also: + * - https://tools.ietf.org/html/rfc4443 + * - https://tools.ietf.org/html/rfc4861 + */ + public static final int ICMPV6_HEADER_MIN_LEN = 4; + public static final int ICMPV6_CHECKSUM_OFFSET = 2; + public static final int ICMPV6_ECHO_REPLY_TYPE = 129; + public static final int ICMPV6_ECHO_REQUEST_TYPE = 128; + public static final int ICMPV6_ROUTER_SOLICITATION = 133; + public static final int ICMPV6_ROUTER_ADVERTISEMENT = 134; + public static final int ICMPV6_NEIGHBOR_SOLICITATION = 135; + public static final int ICMPV6_NEIGHBOR_ADVERTISEMENT = 136; + public static final int ICMPV6_ND_OPTION_MIN_LENGTH = 8; + public static final int ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR = 8; + public static final int ICMPV6_ND_OPTION_SLLA = 1; + public static final int ICMPV6_ND_OPTION_TLLA = 2; + public static final int ICMPV6_ND_OPTION_PIO = 3; + public static final int ICMPV6_ND_OPTION_MTU = 5; + public static final int ICMPV6_ND_OPTION_RDNSS = 25; + public static final int ICMPV6_ND_OPTION_PREF64 = 38; + + + public static final int ICMPV6_RA_HEADER_LEN = 16; + + /** + * UDP constants. + * + * See also: + * - https://tools.ietf.org/html/rfc768 + */ + public static final int UDP_HEADER_LEN = 8; + + + /** + * DHCP constants. + * + * See also: + * - https://tools.ietf.org/html/rfc2131 + */ + public static final int INFINITE_LEASE = 0xffffffff; + public static final int DHCP4_CLIENT_PORT = 68; + + /** + * IEEE802.11 standard constants. + * + * See also: + * - https://ieeexplore.ieee.org/document/7786995 + */ + public static final int VENDOR_SPECIFIC_IE_ID = 0xdd; + + private NetworkStackConstants() { + throw new UnsupportedOperationException("This class is not to be instantiated"); + } +} From b60e8e2836646aefaa18e3392572f1ed06f4029f Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 5 Oct 2020 11:15:26 +0900 Subject: [PATCH 064/777] Add an icmpv6Checksum utility to IpUtils The utility is similar to the existing udpChecksum and tcpChecksum methods, but for ICMPv6 messages. Bug: 168868607 Test: m, followup tests using this utility Change-Id: I41f478af89260a0225f597e672bd798932f1b5eb --- .../com/android/net/module/util/IpUtils.java | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/IpUtils.java b/staticlibs/framework/com/android/net/module/util/IpUtils.java index 54b4cdfd94..dbc22854ac 100644 --- a/staticlibs/framework/com/android/net/module/util/IpUtils.java +++ b/staticlibs/framework/com/android/net/module/util/IpUtils.java @@ -16,16 +16,15 @@ package com.android.net.module.util; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.nio.BufferOverflowException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.nio.ShortBuffer; - +import static android.system.OsConstants.IPPROTO_ICMPV6; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ShortBuffer; + /** * @hide */ @@ -129,16 +128,30 @@ public class IpUtils { return (short) sum; } + /** + * Calculate the UDP checksum for an UDP packet. + */ public static short udpChecksum(ByteBuffer buf, int ipOffset, int transportOffset) { int transportLen = intAbs(buf.getShort(transportOffset + 4)); return transportChecksum(buf, IPPROTO_UDP, ipOffset, transportOffset, transportLen); } + /** + * Calculate the TCP checksum for a TCP packet. + */ public static short tcpChecksum(ByteBuffer buf, int ipOffset, int transportOffset, int transportLen) { return transportChecksum(buf, IPPROTO_TCP, ipOffset, transportOffset, transportLen); } + /** + * Calculate the ICMPv6 checksum for an ICMPv6 packet. + */ + public static short icmpv6Checksum(ByteBuffer buf, int ipOffset, int transportOffset, + int transportLen) { + return transportChecksum(buf, IPPROTO_ICMPV6, ipOffset, transportOffset, transportLen); + } + public static String addressAndPortToString(InetAddress address, int port) { return String.format( (address instanceof Inet6Address) ? "[%s]:%d" : "%s:%d", From b2cce59454ee7cc93c6f5551698904983122f1f3 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 9 Oct 2020 01:38:44 +0000 Subject: [PATCH 065/777] Revert "Move NetworkStackConstants to frameworks/libs/net" Revert "Use new test utilities from frameworks/libs/net" Revert submission 1440811-iputils_constants_move Reason for revert: Likely broke build in b/170438226 Reverted Changes: Ic382d24e7:Move NetworkStackConstants to frameworks/libs/net I0d938e296:Use new test utilities from frameworks/libs/net Change-Id: I5e41daa85af39cfab4261ddf790c2008b2630c15 --- staticlibs/Android.bp | 3 - .../module/util/NetworkStackConstants.java | 163 ------------------ 2 files changed, 166 deletions(-) delete mode 100644 staticlibs/device/com/android/net/module/util/NetworkStackConstants.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 252efb4e91..e5cc8b1f7c 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -52,9 +52,6 @@ java_library { "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", ], - static_libs: [ - "net-utils-framework-common", - ], libs: [ "androidx.annotation_annotation", ], diff --git a/staticlibs/device/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/device/com/android/net/module/util/NetworkStackConstants.java deleted file mode 100644 index 68da7c9e6a..0000000000 --- a/staticlibs/device/com/android/net/module/util/NetworkStackConstants.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.net.module.util; - -import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; - -import java.net.Inet4Address; - -/** - * Network constants used by the network stack. - */ -public final class NetworkStackConstants { - - /** - * Ethernet constants. - * - * See also: - * - https://tools.ietf.org/html/rfc894 - * - https://tools.ietf.org/html/rfc2464 - * - https://tools.ietf.org/html/rfc7042 - * - http://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml - * - http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml - */ - public static final int ETHER_DST_ADDR_OFFSET = 0; - public static final int ETHER_SRC_ADDR_OFFSET = 6; - public static final int ETHER_ADDR_LEN = 6; - public static final int ETHER_TYPE_OFFSET = 12; - public static final int ETHER_TYPE_LENGTH = 2; - public static final int ETHER_TYPE_ARP = 0x0806; - public static final int ETHER_TYPE_IPV4 = 0x0800; - public static final int ETHER_TYPE_IPV6 = 0x86dd; - public static final int ETHER_HEADER_LEN = 14; - public static final int ETHER_MTU = 1500; - - /** - * ARP constants. - * - * See also: - * - https://tools.ietf.org/html/rfc826 - * - http://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml - */ - public static final int ARP_PAYLOAD_LEN = 28; // For Ethernet+IPv4. - public static final int ARP_ETHER_IPV4_LEN = ARP_PAYLOAD_LEN + ETHER_HEADER_LEN; - public static final int ARP_REQUEST = 1; - public static final int ARP_REPLY = 2; - public static final int ARP_HWTYPE_RESERVED_LO = 0; - public static final int ARP_HWTYPE_ETHER = 1; - public static final int ARP_HWTYPE_RESERVED_HI = 0xffff; - - /** - * IPv4 Address Conflict Detection constants. - * - * See also: - * - https://tools.ietf.org/html/rfc5227 - */ - public static final int IPV4_CONFLICT_PROBE_NUM = 3; - public static final int IPV4_CONFLICT_ANNOUNCE_NUM = 2; - - /** - * IPv4 constants. - * - * See also: - * - https://tools.ietf.org/html/rfc791 - */ - public static final int IPV4_ADDR_BITS = 32; - public static final int IPV4_MIN_MTU = 68; - public static final int IPV4_MAX_MTU = 65_535; - public static final int IPV4_HEADER_MIN_LEN = 20; - public static final int IPV4_IHL_MASK = 0xf; - public static final int IPV4_FLAGS_OFFSET = 6; - public static final int IPV4_FRAGMENT_MASK = 0x1fff; - public static final int IPV4_PROTOCOL_OFFSET = 9; - public static final int IPV4_SRC_ADDR_OFFSET = 12; - public static final int IPV4_DST_ADDR_OFFSET = 16; - public static final int IPV4_ADDR_LEN = 4; - public static final Inet4Address IPV4_ADDR_ALL = intToInet4AddressHTH(0xffffffff); - public static final Inet4Address IPV4_ADDR_ANY = intToInet4AddressHTH(0x0); - - /** - * IPv6 constants. - * - * See also: - * - https://tools.ietf.org/html/rfc2460 - */ - public static final int IPV6_ADDR_LEN = 16; - public static final int IPV6_HEADER_LEN = 40; - public static final int IPV6_LEN_OFFSET = 4; - public static final int IPV6_PROTOCOL_OFFSET = 6; - public static final int IPV6_SRC_ADDR_OFFSET = 8; - public static final int IPV6_DST_ADDR_OFFSET = 24; - public static final int IPV6_MIN_MTU = 1280; - - /** - * ICMPv6 constants. - * - * See also: - * - https://tools.ietf.org/html/rfc4443 - * - https://tools.ietf.org/html/rfc4861 - */ - public static final int ICMPV6_HEADER_MIN_LEN = 4; - public static final int ICMPV6_CHECKSUM_OFFSET = 2; - public static final int ICMPV6_ECHO_REPLY_TYPE = 129; - public static final int ICMPV6_ECHO_REQUEST_TYPE = 128; - public static final int ICMPV6_ROUTER_SOLICITATION = 133; - public static final int ICMPV6_ROUTER_ADVERTISEMENT = 134; - public static final int ICMPV6_NEIGHBOR_SOLICITATION = 135; - public static final int ICMPV6_NEIGHBOR_ADVERTISEMENT = 136; - public static final int ICMPV6_ND_OPTION_MIN_LENGTH = 8; - public static final int ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR = 8; - public static final int ICMPV6_ND_OPTION_SLLA = 1; - public static final int ICMPV6_ND_OPTION_TLLA = 2; - public static final int ICMPV6_ND_OPTION_PIO = 3; - public static final int ICMPV6_ND_OPTION_MTU = 5; - public static final int ICMPV6_ND_OPTION_RDNSS = 25; - public static final int ICMPV6_ND_OPTION_PREF64 = 38; - - - public static final int ICMPV6_RA_HEADER_LEN = 16; - - /** - * UDP constants. - * - * See also: - * - https://tools.ietf.org/html/rfc768 - */ - public static final int UDP_HEADER_LEN = 8; - - - /** - * DHCP constants. - * - * See also: - * - https://tools.ietf.org/html/rfc2131 - */ - public static final int INFINITE_LEASE = 0xffffffff; - public static final int DHCP4_CLIENT_PORT = 68; - - /** - * IEEE802.11 standard constants. - * - * See also: - * - https://ieeexplore.ieee.org/document/7786995 - */ - public static final int VENDOR_SPECIFIC_IE_ID = 0xdd; - - private NetworkStackConstants() { - throw new UnsupportedOperationException("This class is not to be instantiated"); - } -} From e1979e7624757ab4c50cc145c15aa9e372632fdf Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 9 Oct 2020 02:17:40 +0000 Subject: [PATCH 066/777] Move NetworkStackConstants to frameworks/libs/net The class only contains constants that should be shareable between different modules and tests. This rolls forward the previous change that broke FrameworksTelephonyTests, because adding net-utils-framework-common to net-utils-device-common caused the tests to contain a jarjared version of net-utils-framework-common inherited from telephony code, and a non-jarjared version inherited from net-utils-device-common. This resulted in duplicate classes after applying jarjar to the test, which is not supported (the build system can deduplicate if two libs include the same class, but jarjar fails if a class after rename conflicts with an existing class). This new change removes the dependency on net-utils-framework-common from net-utils-device-common. Bug: 168868607 Test: m Change-Id: I34bad7ec79ef0fd03e5e40b643f0d85d686c53ec --- .../module/util/NetworkStackConstants.java | 181 ++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/NetworkStackConstants.java diff --git a/staticlibs/device/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/device/com/android/net/module/util/NetworkStackConstants.java new file mode 100644 index 0000000000..1088477cb2 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/NetworkStackConstants.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * Network constants used by the network stack. + */ +public final class NetworkStackConstants { + + /** + * Ethernet constants. + * + * See also: + * - https://tools.ietf.org/html/rfc894 + * - https://tools.ietf.org/html/rfc2464 + * - https://tools.ietf.org/html/rfc7042 + * - http://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml + * - http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml + */ + public static final int ETHER_DST_ADDR_OFFSET = 0; + public static final int ETHER_SRC_ADDR_OFFSET = 6; + public static final int ETHER_ADDR_LEN = 6; + public static final int ETHER_TYPE_OFFSET = 12; + public static final int ETHER_TYPE_LENGTH = 2; + public static final int ETHER_TYPE_ARP = 0x0806; + public static final int ETHER_TYPE_IPV4 = 0x0800; + public static final int ETHER_TYPE_IPV6 = 0x86dd; + public static final int ETHER_HEADER_LEN = 14; + public static final int ETHER_MTU = 1500; + + /** + * ARP constants. + * + * See also: + * - https://tools.ietf.org/html/rfc826 + * - http://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml + */ + public static final int ARP_PAYLOAD_LEN = 28; // For Ethernet+IPv4. + public static final int ARP_ETHER_IPV4_LEN = ARP_PAYLOAD_LEN + ETHER_HEADER_LEN; + public static final int ARP_REQUEST = 1; + public static final int ARP_REPLY = 2; + public static final int ARP_HWTYPE_RESERVED_LO = 0; + public static final int ARP_HWTYPE_ETHER = 1; + public static final int ARP_HWTYPE_RESERVED_HI = 0xffff; + + /** + * IPv4 Address Conflict Detection constants. + * + * See also: + * - https://tools.ietf.org/html/rfc5227 + */ + public static final int IPV4_CONFLICT_PROBE_NUM = 3; + public static final int IPV4_CONFLICT_ANNOUNCE_NUM = 2; + + /** + * IPv4 constants. + * + * See also: + * - https://tools.ietf.org/html/rfc791 + */ + public static final int IPV4_ADDR_BITS = 32; + public static final int IPV4_MIN_MTU = 68; + public static final int IPV4_MAX_MTU = 65_535; + public static final int IPV4_HEADER_MIN_LEN = 20; + public static final int IPV4_IHL_MASK = 0xf; + public static final int IPV4_FLAGS_OFFSET = 6; + public static final int IPV4_FRAGMENT_MASK = 0x1fff; + public static final int IPV4_PROTOCOL_OFFSET = 9; + public static final int IPV4_SRC_ADDR_OFFSET = 12; + public static final int IPV4_DST_ADDR_OFFSET = 16; + public static final int IPV4_ADDR_LEN = 4; + public static final Inet4Address IPV4_ADDR_ALL = makeInet4Address( + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff); + public static final Inet4Address IPV4_ADDR_ANY = makeInet4Address( + (byte) 0, (byte) 0, (byte) 0, (byte) 0); + + /** + * IPv6 constants. + * + * See also: + * - https://tools.ietf.org/html/rfc2460 + */ + public static final int IPV6_ADDR_LEN = 16; + public static final int IPV6_HEADER_LEN = 40; + public static final int IPV6_LEN_OFFSET = 4; + public static final int IPV6_PROTOCOL_OFFSET = 6; + public static final int IPV6_SRC_ADDR_OFFSET = 8; + public static final int IPV6_DST_ADDR_OFFSET = 24; + public static final int IPV6_MIN_MTU = 1280; + + /** + * ICMPv6 constants. + * + * See also: + * - https://tools.ietf.org/html/rfc4443 + * - https://tools.ietf.org/html/rfc4861 + */ + public static final int ICMPV6_HEADER_MIN_LEN = 4; + public static final int ICMPV6_CHECKSUM_OFFSET = 2; + public static final int ICMPV6_ECHO_REPLY_TYPE = 129; + public static final int ICMPV6_ECHO_REQUEST_TYPE = 128; + public static final int ICMPV6_ROUTER_SOLICITATION = 133; + public static final int ICMPV6_ROUTER_ADVERTISEMENT = 134; + public static final int ICMPV6_NEIGHBOR_SOLICITATION = 135; + public static final int ICMPV6_NEIGHBOR_ADVERTISEMENT = 136; + public static final int ICMPV6_ND_OPTION_MIN_LENGTH = 8; + public static final int ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR = 8; + public static final int ICMPV6_ND_OPTION_SLLA = 1; + public static final int ICMPV6_ND_OPTION_TLLA = 2; + public static final int ICMPV6_ND_OPTION_PIO = 3; + public static final int ICMPV6_ND_OPTION_MTU = 5; + public static final int ICMPV6_ND_OPTION_RDNSS = 25; + public static final int ICMPV6_ND_OPTION_PREF64 = 38; + + + public static final int ICMPV6_RA_HEADER_LEN = 16; + + /** + * UDP constants. + * + * See also: + * - https://tools.ietf.org/html/rfc768 + */ + public static final int UDP_HEADER_LEN = 8; + + + /** + * DHCP constants. + * + * See also: + * - https://tools.ietf.org/html/rfc2131 + */ + public static final int INFINITE_LEASE = 0xffffffff; + public static final int DHCP4_CLIENT_PORT = 68; + + /** + * IEEE802.11 standard constants. + * + * See also: + * - https://ieeexplore.ieee.org/document/7786995 + */ + public static final int VENDOR_SPECIFIC_IE_ID = 0xdd; + + // TODO: Move to Inet4AddressUtils + // See aosp/1455936: NetworkStackConstants can't depend on it as it causes jarjar-related issues + // for users of both the net-utils-device-common and net-utils-framework-common libraries. + // Jarjar rule management needs to be simplified for that: b/170445871 + + /** + * Make an Inet4Address from 4 bytes in network byte order. + */ + private static Inet4Address makeInet4Address(byte b1, byte b2, byte b3, byte b4) { + try { + return (Inet4Address) InetAddress.getByAddress(new byte[] { b1, b2, b3, b4 }); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("addr must be 4 bytes: this should never happen"); + } + } + + private NetworkStackConstants() { + throw new UnsupportedOperationException("This class is not to be instantiated"); + } +} From 6f95cefd38494756307ee83ce5dc6d4a5cbc1cd8 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Tue, 8 Sep 2020 19:16:15 +0900 Subject: [PATCH 067/777] Define a generic class to parse structured message. Bug: 163492391 Test: atest android.net.util.StructTest --rerun-until-failure Change-Id: I1848984d80998d87acccc52287a351d27708dedc --- staticlibs/Android.bp | 2 +- .../device/android/net/util/Struct.java | 377 ++++++++++++++ staticlibs/tests/unit/jarjar-rules.txt | 11 +- .../unit/src/android/net/util/StructTest.java | 492 ++++++++++++++++++ 4 files changed, 876 insertions(+), 6 deletions(-) create mode 100644 staticlibs/device/android/net/util/Struct.java create mode 100644 staticlibs/tests/unit/src/android/net/util/StructTest.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index f4799f0c50..17372dc937 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -48,7 +48,7 @@ java_library { "//frameworks/opt/net/ike", "//frameworks/opt/net/wifi/service", "//frameworks/opt/net/telephony", - "//packages/modules/NetworkStack", + "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", ], diff --git a/staticlibs/device/android/net/util/Struct.java b/staticlibs/device/android/net/util/Struct.java new file mode 100644 index 0000000000..d0c763e483 --- /dev/null +++ b/staticlibs/device/android/net/util/Struct.java @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2020 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.util; + +import android.annotation.NonNull; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.math.BigInteger; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * Define a generic class that helps to parse the structured message. + * + * Example usage: + * + * // C-style NduserOption message header definition in the kernel: + * struct nduseroptmsg { + * unsigned char nduseropt_family; + * unsigned char nduseropt_pad1; + * unsigned short nduseropt_opts_len; + * int nduseropt_ifindex; + * __u8 nduseropt_icmp_type; + * __u8 nduseropt_icmp_code; + * unsigned short nduseropt_pad2; + * unsigned int nduseropt_pad3; + * } + * + * - Declare a subclass with explicit constructor or not which extends from this class to parse + * NduserOption header from raw bytes array. + * + * - Option w/ explicit constructor: + * static class NduserOptHeaderMessage extends Struct { + * @Field(order = 0, type = Type.U8, padding = 1) + * final short family; + * @Field(order = 1, type = Type.U16) + * final int len; + * @Field(order = 2, type = Type.S32) + * final int ifindex; + * @Field(order = 3, type = Type.U8) + * final short type; + * @Field(order = 4, type = Type.U8, padding = 6) + * final short code; + * + * NduserOptHeaderMessage(final short family, final int len, final int ifindex, + * final short type, final short code) { + * this.family = family; + * this.len = len; + * this.ifindex = ifindex; + * this.type = type; + * this.code = code; + * } + * } + * + * - Option w/o explicit constructor: + * static class NduserOptHeaderMessage extends Struct { + * @Field(order = 0, type = Type.U8, padding = 1) + * short family; + * @Field(order = 1, type = Type.U16) + * int len; + * @Field(order = 2, type = Type.S32) + * int ifindex; + * @Field(order = 3, type = Type.U8) + * short type; + * @Field(order = 4, type = Type.U8, padding = 6) + * short code; + * } + * + * - Parse the target message and refer the members. + * final ByteBuffer buf = ByteBuffer.wrap(RAW_BYTES_ARRAY); + * buf.order(ByteOrder.nativeOrder()); + * final NduserOptHeaderMessage nduserHdrMsg = Struct.parse(NduserOptHeaderMessage.class, buf); + * assertEquals(10, nduserHdrMsg.family); + */ +public class Struct { + public enum Type { + U8, // unsigned byte, size = 1 byte + U16, // unsigned short, size = 2 bytes + U32, // unsigned int, size = 4 bytes + U64, // unsigned long, size = 8 bytes + S8, // signed byte, size = 1 byte + S16, // signed short, size = 2 bytes + S32, // signed int, size = 4 bytes + S64, // signed long, size = 8 bytes + BE16, // unsigned short in network order, size = 2 bytes + BE32, // unsigned int in network order, size = 4 bytes + BE64, // unsigned long in network order, size = 8 bytes + ByteArray, // byte array with predefined length + } + + /** + * Indicate that the field marked with this annotation will automatically be managed by this + * class (e.g., will be parsed by #parse). + * + * order: The placeholder associated with each field, consecutive order starting from zero. + * type: The primitive data type listed in above Type enumeration. + * padding: Padding bytes appear after the field for alignment. + * arraysize: The length of byte array. + * + * Annotation associated with field MUST have order and type properties at least, padding + * and arraysize properties depend on the specific usage, if these properties are absence, + * then default value 0 will be applied. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface Field { + int order(); + Type type(); + int padding() default 0; + int arraysize() default 0; + } + + private static class FieldInfo { + @NonNull + public final Field annotation; + @NonNull + public final java.lang.reflect.Field field; + + FieldInfo(final Field annotation, final java.lang.reflect.Field field) { + this.annotation = annotation; + this.field = field; + } + } + + private static void checkAnnotationType(final Type type, final Class fieldType) { + switch (type) { + case U8: + case S16: + if (fieldType == Short.TYPE) return; + break; + case U16: + case S32: + case BE16: + if (fieldType == Integer.TYPE) return; + break; + case U32: + case S64: + case BE32: + if (fieldType == Long.TYPE) return; + break; + case U64: + case BE64: + if (fieldType == BigInteger.class || fieldType == Long.TYPE) return; + break; + case S8: + if (fieldType == Byte.TYPE) return; + break; + case ByteArray: + if (fieldType == byte[].class) return; + break; + default: + throw new IllegalArgumentException("Unknown type" + type); + } + throw new IllegalArgumentException("Invalid primitive data type: " + fieldType + + "for annotation type: " + type); + } + + private static boolean isStructSubclass(final Class clazz) { + return clazz != null && Struct.class.isAssignableFrom(clazz) && Struct.class != clazz; + } + + private static int getAnnotationFieldCount(final Class clazz) { + int count = 0; + for (java.lang.reflect.Field field : clazz.getDeclaredFields()) { + if (field.isAnnotationPresent(Field.class)) count++; + } + return count; + } + + private static boolean matchModifier(final FieldInfo[] fields, boolean immutable) { + for (FieldInfo fi : fields) { + if (Modifier.isFinal(fi.field.getModifiers()) != immutable) return false; + } + return true; + } + + private static boolean hasBothMutableAndImmutableFields(final FieldInfo[] fields) { + return !matchModifier(fields, true /* immutable */) + && !matchModifier(fields, false /* mutable */); + } + + private static boolean matchConstructor(final Constructor cons, final FieldInfo[] fields) { + final Class[] paramTypes = cons.getParameterTypes(); + if (paramTypes.length != fields.length) return false; + for (int i = 0; i < cons.getParameterTypes().length; i++) { + if (!paramTypes[i].equals(fields[i].field.getType())) return false; + } + return true; + } + + private static BigInteger readBigInteger(final ByteBuffer buf) { + // The magnitude argument of BigInteger constructor is a byte array in big-endian order. + // If ByteBuffer is read in little-endian, reverse the order of the bytes is required; + // if ByteBuffer is read in big-endian, then just keep it as-is. + final byte[] input = new byte[8]; + for (int i = 0; i < 8; i++) { + input[(buf.order() == ByteOrder.LITTLE_ENDIAN ? input.length - 1 - i : i)] = buf.get(); + } + return new BigInteger(1, input); + } + + private static Object getFieldValue(final ByteBuffer buf, final FieldInfo fieldInfo) + throws BufferUnderflowException { + final Object value; + checkAnnotationType(fieldInfo.annotation.type(), fieldInfo.field.getType()); + switch (fieldInfo.annotation.type()) { + case U8: + value = (short) (buf.get() & 0xFF); + break; + case U16: + value = (int) (buf.getShort() & 0xFFFF); + break; + case U32: + value = (long) (buf.getInt() & 0xFFFFFFFFL); + break; + case U64: + if (fieldInfo.field.getType() == BigInteger.class) { + value = readBigInteger(buf); + } else { + value = buf.getLong(); + } + break; + case S8: + value = buf.get(); + break; + case S16: + value = buf.getShort(); + break; + case S32: + value = buf.getInt(); + break; + case S64: + value = buf.getLong(); + break; + case BE16: + if (buf.order() == ByteOrder.LITTLE_ENDIAN) { + value = (int) (Short.reverseBytes(buf.getShort()) & 0xFFFF); + } else { + value = (int) (buf.getShort() & 0xFFFF); + } + break; + case BE32: + if (buf.order() == ByteOrder.LITTLE_ENDIAN) { + value = (long) (Integer.reverseBytes(buf.getInt()) & 0xFFFFFFFFL); + } else { + value = (long) (buf.getInt() & 0xFFFFFFFFL); + } + break; + case BE64: + if (fieldInfo.field.getType() == BigInteger.class) { + value = readBigInteger(buf); + } else { + if (buf.order() == ByteOrder.LITTLE_ENDIAN) { + value = Long.reverseBytes(buf.getLong()); + } else { + value = buf.getLong(); + } + } + break; + case ByteArray: + final byte[] array = new byte[fieldInfo.annotation.arraysize()]; + buf.get(array); + value = array; + break; + default: + throw new IllegalArgumentException("Unknown type:" + fieldInfo.annotation.type()); + } + + // Skip the padding data for alignment if any. + if (fieldInfo.annotation.padding() > 0) { + buf.position(buf.position() + fieldInfo.annotation.padding()); + } + return value; + } + + private static FieldInfo[] getClassFieldInfo(final Class clazz) { + final FieldInfo[] annotationFields = new FieldInfo[getAnnotationFieldCount(clazz)]; + + // Since array returned from Class#getDeclaredFields doesn't guarantee the actual order + // of field appeared in the class, that is a problem when parsing raw data read from + // ByteBuffer. Store the fields appeared by the order() defined in the Field annotation. + for (java.lang.reflect.Field field : clazz.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers())) continue; + + final Field annotation = field.getAnnotation(Field.class); + if (annotation == null) { + throw new IllegalArgumentException("Field " + field.getName() + + " is missing the " + Field.class.getSimpleName() + + " annotation"); + } + if (annotation.order() < 0 || annotation.order() >= annotationFields.length) { + throw new IllegalArgumentException("Annotation order: " + annotation.order() + + " is negative or non-consecutive"); + } + if (annotationFields[annotation.order()] != null) { + throw new IllegalArgumentException("Duplicated annotation order: " + + annotation.order()); + } + annotationFields[annotation.order()] = new FieldInfo(annotation, field); + } + return annotationFields; + } + + /** + * Parse raw data from ByteBuffer according to the pre-defined annotation rule and return + * the type-variable object which is subclass of Struct class. + * + * TODO: + * 1. Support subclass inheritance. + * 2. Introduce annotation processor to enforce the subclass naming schema. + */ + public static T parse(final Class clazz, final ByteBuffer buf) { + try { + if (!isStructSubclass(clazz)) { + throw new IllegalArgumentException(clazz.getName() + " is not a subclass of " + + Struct.class.getName()); + } + + final FieldInfo[] foundFields = getClassFieldInfo(clazz); + if (hasBothMutableAndImmutableFields(foundFields)) { + throw new IllegalArgumentException("Class has both immutable and mutable fields"); + } + + Constructor constructor = null; + Constructor defaultConstructor = null; + final Constructor[] constructors = clazz.getDeclaredConstructors(); + for (Constructor cons : constructors) { + if (matchConstructor(cons, foundFields)) constructor = cons; + if (cons.getParameterTypes().length == 0) defaultConstructor = cons; + } + + if (constructor == null && defaultConstructor == null) { + throw new IllegalArgumentException("Fail to find available constructor"); + } + if (constructor != null) { + final Object[] args = new Object[constructor.getParameterTypes().length]; + for (int i = 0; i < args.length; i++) { + args[i] = getFieldValue(buf, foundFields[i]); + } + return (T) constructor.newInstance(args); + } + + final Object instance = defaultConstructor.newInstance(); + for (FieldInfo fi : foundFields) { + fi.field.set(instance, getFieldValue(buf, fi)); + } + return (T) instance; + } catch (IllegalAccessException + | InvocationTargetException + | InstantiationException e) { + throw new IllegalArgumentException("Fail to create a instance from constructor", e); + } catch (BufferUnderflowException e) { + throw new IllegalArgumentException("Fail to read raw data from ByteBuffer", e); + } + } +} diff --git a/staticlibs/tests/unit/jarjar-rules.txt b/staticlibs/tests/unit/jarjar-rules.txt index fceccfb755..0f131b20d4 100644 --- a/staticlibs/tests/unit/jarjar-rules.txt +++ b/staticlibs/tests/unit/jarjar-rules.txt @@ -1,6 +1,7 @@ # TODO: move the classes to the target package in java -rule android.net.util.IpRange* com.android.net.module.util.IpRange@1 -rule android.net.util.MacAddressUtils* com.android.net.module.util.MacAddressUtils@1 -rule android.net.util.LinkPropertiesUtils* com.android.net.module.util.LinkPropertiesUtils@1 -rule android.net.util.NetUtils* com.android.net.module.util.NetUtils@1 -rule android.net.util.nsd.** com.android.net.module.util.nsd.@1 +rule android.net.util.IpRange* com.android.net.moduletests.util.IpRange@1 +rule android.net.util.MacAddressUtils* com.android.net.moduletests.util.MacAddressUtils@1 +rule android.net.util.LinkPropertiesUtils* com.android.net.moduletests.util.LinkPropertiesUtils@1 +rule android.net.util.NetUtils* com.android.net.moduletests.util.NetUtils@1 +rule android.net.util.nsd.** com.android.net.moduletests.util.nsd.@1 +rule com.android.net.module.util.** com.android.net.moduletests.util.@1 diff --git a/staticlibs/tests/unit/src/android/net/util/StructTest.java b/staticlibs/tests/unit/src/android/net/util/StructTest.java new file mode 100644 index 0000000000..2d35891a59 --- /dev/null +++ b/staticlibs/tests/unit/src/android/net/util/StructTest.java @@ -0,0 +1,492 @@ +/* + * Copyright (C) 2020 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.util; + +import static com.android.testutils.MiscAsserts.assertThrows; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.net.IpPrefix; +import android.net.util.Struct.Field; +import android.net.util.Struct.Type; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.util.HexDump; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.math.BigInteger; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class StructTest { + + // IPv6, 0 bytes of options, ifindex 15715755: 0x00efcdab, type 134 (RA), code 0, padding. + private static final String HDR_EMPTY = "0a00" + "0000" + "abcdef00" + "8600000000000000"; + + // BE16: 0xfeff, BE32: 0xfeffffff, BE64: 0xfffffffffffffffe, 0x7effffffffffffff + private static final String NETWORK_ORDER_MSG = "feff" + "feffffff" + "fffffffffffffffe" + + "7effffffffffffff"; + + // S8: 0x7f, S16: 0x7fff, S32: 0x7fffffff, S64: 0x7fffffffffffffff + private static final String SIGNED_DATA = "7f" + "ff7f" + "ffffff7f" + "ffffffffffffff7f"; + + // nS8: 0x81, nS16: 0x8001, nS32: 0x80000001, nS64: 800000000000000001 + private static final String SIGNED_NEGATIVE_DATA = "81" + "0180" + "01000080" + + "0100000000000080"; + + // U8: 0xff, U16: 0xffff, U32: 0xffffffff, U64: 0xffffffffffffffff, U63: 0x7fffffffffffffff; + private static final String UNSIGNED_DATA = "ff" + "ffff" + "ffffffff" + "ffffffffffffffff" + + "ffffffffffffff7f"; + + // PREF64 option, 2001:db8:3:4:5:6::/96, lifetime: 10064 + private static final String OPT_PREF64 = "2750" + "20010db80003000400050006"; + + private T doParsingMessageTest(final String hexString, Class clazz) { + final ByteBuffer buf = toByteBuffer(hexString); + buf.order(ByteOrder.LITTLE_ENDIAN); + return Struct.parse(clazz, buf); + } + + static class HeaderMsgWithConstructor extends Struct { + static int sType; + static int sLength; + + @Field(order = 0, type = Type.U8, padding = 1) + final short mFamily; + @Field(order = 1, type = Type.U16) + final int mLen; + @Field(order = 2, type = Type.S32) + final int mIfindex; + @Field(order = 3, type = Type.U8) + final short mIcmpType; + @Field(order = 4, type = Type.U8, padding = 6) + final short mIcmpCode; + + HeaderMsgWithConstructor(final short family, final int len, final int ifindex, + final short type, final short code) { + mFamily = family; + mLen = len; + mIfindex = ifindex; + mIcmpType = type; + mIcmpCode = code; + } + } + + @Test + public void testClassWithExplicitConstructor() { + final HeaderMsgWithConstructor msg = doParsingMessageTest(HDR_EMPTY, + HeaderMsgWithConstructor.class); + assertEquals(10, msg.mFamily); + assertEquals(0, msg.mLen); + assertEquals(15715755, msg.mIfindex); + assertEquals(134, msg.mIcmpType); + assertEquals(0, msg.mIcmpCode); + } + + static class HeaderMsgWithoutConstructor extends Struct { + static int sType; + static int sLength; + + @Field(order = 0, type = Type.U8, padding = 1) + short mFamily; + @Field(order = 1, type = Type.U16) + int mLen; + @Field(order = 2, type = Type.S32) + int mIfindex; + @Field(order = 3, type = Type.U8) + short mIcmpType; + @Field(order = 4, type = Type.U8, padding = 6) + short mIcmpCode; + } + + @Test + public void testClassWithDefaultConstrcutor() { + final HeaderMsgWithoutConstructor msg = doParsingMessageTest(HDR_EMPTY, + HeaderMsgWithoutConstructor.class); + assertEquals(10, msg.mFamily); + assertEquals(0, msg.mLen); + assertEquals(15715755, msg.mIfindex); + assertEquals(134, msg.mIcmpType); + assertEquals(0, msg.mIcmpCode); + } + + static class HeaderMessage { + @Field(order = 0, type = Type.U8, padding = 1) + short mFamily; + @Field(order = 1, type = Type.U16) + int mLen; + @Field(order = 2, type = Type.S32) + int mIfindex; + @Field(order = 3, type = Type.U8) + short mIcmpType; + @Field(order = 4, type = Type.U8, padding = 6) + short mIcmpCode; + } + + @Test + public void testInvalidClass_NotSubClass() { + final ByteBuffer buf = toByteBuffer(HDR_EMPTY); + assertThrows(IllegalArgumentException.class, + () -> Struct.parse(HeaderMessage.class, buf)); + } + + static class HeaderMessageMissingAnnotation extends Struct { + @Field(order = 0, type = Type.U8, padding = 1) + short mFamily; + @Field(order = 1, type = Type.U16) + int mLen; + int mIfindex; + @Field(order = 2, type = Type.U8) + short mIcmpType; + @Field(order = 3, type = Type.U8, padding = 6) + short mIcmpCode; + } + + @Test + public void testInvalidClass_MissingAnnotationField() { + final ByteBuffer buf = toByteBuffer(HDR_EMPTY); + assertThrows(IllegalArgumentException.class, + () -> Struct.parse(HeaderMessageMissingAnnotation.class, buf)); + } + + static class NetworkOrderMessage extends Struct { + @Field(order = 0, type = Type.BE16) + final int mBE16; + @Field(order = 1, type = Type.BE32) + final long mBE32; + @Field(order = 2, type = Type.BE64) + final BigInteger mBE64; + @Field(order = 3, type = Type.BE64) + final long mBE63; + + NetworkOrderMessage(final int be16, final long be32, final BigInteger be64, + final long be63) { + mBE16 = be16; + mBE32 = be32; + mBE64 = be64; + mBE63 = be63; + } + } + + @Test + public void testNetworkOrder() { + final NetworkOrderMessage msg = doParsingMessageTest(NETWORK_ORDER_MSG, + NetworkOrderMessage.class); + assertEquals(65279, msg.mBE16); + assertEquals(4278190079L, msg.mBE32); + assertEquals(new BigInteger("18374686479671623679"), msg.mBE64); + assertEquals(9151314442816847871L, msg.mBE63); + } + + static class UnsignedDataMessage extends Struct { + @Field(order = 0, type = Type.U8) + final short mU8; + @Field(order = 1, type = Type.U16) + final int mU16; + @Field(order = 2, type = Type.U32) + final long mU32; + @Field(order = 3, type = Type.U64) + final BigInteger mU64; + @Field(order = 4, type = Type.U64) + final long mU63; + + UnsignedDataMessage(final short u8, final int u16, final long u32, final BigInteger u64, + final long u63) { + mU8 = u8; + mU16 = u16; + mU32 = u32; + mU64 = u64; + mU63 = u63; + } + } + + @Test + public void testUnsignedData() { + final UnsignedDataMessage msg = doParsingMessageTest(UNSIGNED_DATA, + UnsignedDataMessage.class); + assertEquals(255, msg.mU8); + assertEquals(65535, msg.mU16); + assertEquals(4294967295L, msg.mU32); + assertEquals(new BigInteger("18446744073709551615"), msg.mU64); + assertEquals(9223372036854775807L, msg.mU63); + } + + static class SignedDataMessage extends Struct { + @Field(order = 0, type = Type.S8) + final byte mS8; + @Field(order = 1, type = Type.S16) + final short mS16; + @Field(order = 2, type = Type.S32) + final int mS32; + @Field(order = 3, type = Type.S64) + final long mS64; + @Field(order = 4, type = Type.S8) + final byte mNS8; + @Field(order = 5, type = Type.S16) + final short mNS16; + @Field(order = 6, type = Type.S32) + final int mNS32; + @Field(order = 7, type = Type.S64) + final long mNS64; + + SignedDataMessage(final byte s8, final short s16, final int s32, final long s64, + final byte nS8, final short nS16, final int nS32, final long nS64) { + mS8 = s8; + mS16 = s16; + mS32 = s32; + mS64 = s64; + mNS8 = nS8; + mNS16 = nS16; + mNS32 = nS32; + mNS64 = nS64; + } + } + + @Test + public void testSignedData() { + final SignedDataMessage msg = doParsingMessageTest(SIGNED_DATA + SIGNED_NEGATIVE_DATA, + SignedDataMessage.class); + assertEquals(127, msg.mS8); + assertEquals(32767, msg.mS16); + assertEquals(2147483647, msg.mS32); + assertEquals(9223372036854775807L, msg.mS64); + + assertEquals(-127, msg.mNS8); + assertEquals(-32767, msg.mNS16); + assertEquals(-2147483647, msg.mNS32); + assertEquals(-9223372036854775807L, msg.mNS64); + } + + static class HeaderMessageWithDuplicateOrder extends Struct { + @Field(order = 0, type = Type.U8, padding = 1) + short mFamily; + @Field(order = 1, type = Type.U16) + int mLen; + @Field(order = 2, type = Type.S32) + int mIfindex; + @Field(order = 2, type = Type.U8) + short mIcmpType; + @Field(order = 3, type = Type.U8, padding = 6) + short mIcmpCode; + } + + @Test + public void testInvalidClass_DuplicateFieldOrder() { + final ByteBuffer buf = toByteBuffer(HDR_EMPTY); + assertThrows(IllegalArgumentException.class, + () -> Struct.parse(HeaderMessageWithDuplicateOrder.class, buf)); + } + + static class HeaderMessageWithNegativeOrder extends Struct { + @Field(order = 0, type = Type.U8, padding = 1) + short mFamily; + @Field(order = 1, type = Type.U16) + int mLen; + @Field(order = 2, type = Type.S32) + int mIfindex; + @Field(order = 3, type = Type.U8) + short mIcmpType; + @Field(order = -4, type = Type.U8, padding = 6) + short mIcmpCode; + } + + @Test + public void testInvalidClass_NegativeFieldOrder() { + final ByteBuffer buf = toByteBuffer(HDR_EMPTY); + assertThrows(IllegalArgumentException.class, + () -> Struct.parse(HeaderMessageWithNegativeOrder.class, buf)); + } + + static class HeaderMessageOutOfIndexBounds extends Struct { + @Field(order = 0, type = Type.U8, padding = 1) + short mFamily; + @Field(order = 1, type = Type.U16) + int mLen; + @Field(order = 2, type = Type.S32) + int mIfindex; + @Field(order = 3, type = Type.U8) + short mIcmpType; + @Field(order = 5, type = Type.U8, padding = 6) + short mIcmpCode; + } + + @Test + public void testInvalidClass_OutOfIndexBounds() { + final ByteBuffer buf = toByteBuffer(HDR_EMPTY); + assertThrows(IllegalArgumentException.class, + () -> Struct.parse(HeaderMessageOutOfIndexBounds.class, buf)); + } + + static class HeaderMessageMismatchedPrimitiveType extends Struct { + @Field(order = 0, type = Type.U8, padding = 1) + short mFamily; + @Field(order = 1, type = Type.U16) + short mLen; // should be integer + @Field(order = 2, type = Type.S32) + int mIfindex; + @Field(order = 3, type = Type.U8) + short mIcmpType; + @Field(order = 4, type = Type.U8, padding = 6) + short mIcmpCode; + } + + @Test + public void testInvalidClass_MismatchedPrimitiveDataType() { + final ByteBuffer buf = toByteBuffer(HDR_EMPTY); + assertThrows(IllegalArgumentException.class, + () -> Struct.parse(HeaderMessageMismatchedPrimitiveType.class, buf)); + } + + static class PrefixMessage extends Struct { + @Field(order = 0, type = Type.BE16) + final int mLifetime; + @Field(order = 1, type = Type.ByteArray, arraysize = 12) + final byte[] mPrefix; + + PrefixMessage(final int lifetime, final byte[] prefix) { + mLifetime = lifetime; + mPrefix = prefix; + } + } + + @Test + public void testPrefixArrayField() throws Exception { + final ByteBuffer buf = toByteBuffer(OPT_PREF64); + buf.order(ByteOrder.LITTLE_ENDIAN); + + // The original PREF64 option message has just 12 bytes for prefix byte array + // (Highest 96 bits of the Prefix), copyOf pads the 128-bits IPv6 address with + // prefix and 4-bytes zeros. + final PrefixMessage msg = Struct.parse(PrefixMessage.class, buf); + final InetAddress addr = InetAddress.getByAddress(Arrays.copyOf(msg.mPrefix, 16)); + final IpPrefix prefix = new IpPrefix(addr, 96); + assertEquals(10064, msg.mLifetime); + assertTrue(prefix.equals(new IpPrefix("2001:db8:3:4:5:6::/96"))); + } + + static class HeaderMessageWithMutableField extends Struct { + @Field(order = 0, type = Type.U8, padding = 1) + final short mFamily; + @Field(order = 1, type = Type.U16) + final int mLen; + @Field(order = 2, type = Type.S32) + int mIfindex; + @Field(order = 3, type = Type.U8) + short mIcmpType; + @Field(order = 4, type = Type.U8, padding = 6) + final short mIcmpCode; + + HeaderMessageWithMutableField(final short family, final int len, final short code) { + mFamily = family; + mLen = len; + mIcmpCode = code; + } + } + + @Test + public void testMixMutableAndImmutableFields() { + final ByteBuffer buf = toByteBuffer(HDR_EMPTY); + assertThrows(IllegalArgumentException.class, + () -> Struct.parse(HeaderMessageWithMutableField.class, buf)); + } + + static class HeaderMsgWithStaticConstant extends Struct { + private static final String TAG = "HeaderMessage"; + private static final int FIELD_COUNT = 5; + + @Field(order = 0, type = Type.U8, padding = 1) + final short mFamily; + @Field(order = 1, type = Type.U16) + final int mLen; + @Field(order = 2, type = Type.S32) + final int mIfindex; + @Field(order = 3, type = Type.U8) + final short mIcmpType; + @Field(order = 4, type = Type.U8, padding = 6) + final short mIcmpCode; + + HeaderMsgWithStaticConstant(final short family, final int len, final int ifindex, + final short type, final short code) { + mFamily = family; + mLen = len; + mIfindex = ifindex; + mIcmpType = type; + mIcmpCode = code; + } + } + + @Test + public void testStaticConstantField() { + final HeaderMsgWithStaticConstant msg = doParsingMessageTest(HDR_EMPTY, + HeaderMsgWithStaticConstant.class); + assertEquals(10, msg.mFamily); + assertEquals(0, msg.mLen); + assertEquals(15715755, msg.mIfindex); + assertEquals(134, msg.mIcmpType); + assertEquals(0, msg.mIcmpCode); + } + + static class MismatchedConstructor extends Struct { + @Field(order = 0, type = Type.U16) final int mInt1; + @Field(order = 1, type = Type.U16) final int mInt2; + MismatchedConstructor(String int1, String int2) { + mInt1 = Integer.valueOf(int1); + mInt2 = Integer.valueOf(int2); + } + } + + @Test + public void testMisMatchedConstructor() { + final ByteBuffer buf = toByteBuffer("1234" + "5678"); + assertThrows(IllegalArgumentException.class, + () -> Struct.parse(MismatchedConstructor.class, buf)); + } + + static class ClassWithTwoConstructors extends Struct { + @Field(order = 0, type = Type.U16) final int mInt1; + @Field(order = 1, type = Type.U16) final int mInt2; + ClassWithTwoConstructors(String int1, String int2) { + mInt1 = Integer.valueOf(int1); + mInt2 = Integer.valueOf(int2); + } + ClassWithTwoConstructors(int int1, int int2) { + mInt1 = int1; + mInt2 = int2; + } + } + + @Test + public void testClassWithTwoConstructors() { + final ClassWithTwoConstructors msg = doParsingMessageTest("1234" + "5678", + ClassWithTwoConstructors.class); + assertEquals(13330 /* 0x3412 */, msg.mInt1); + assertEquals(30806 /* 0x7856 */, msg.mInt2); + } + + private ByteBuffer toByteBuffer(final String hexString) { + return ByteBuffer.wrap(HexDump.hexStringToByteArray(hexString)); + } +} From ea53144db002183d5e66690141c84be6574db848 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Sat, 10 Oct 2020 23:23:42 +0900 Subject: [PATCH 068/777] Improve code style in Struct.java and add tests for Type.U64 represented by long primitive. Bug: 163492391 Test: atest android.net.util.StructTest --rerun-until-failure Change-Id: I0120d7ab063d9d170e8b6e6a6077f8f86db93d67 --- .../device/android/net/util/Struct.java | 14 ++--- .../unit/src/android/net/util/StructTest.java | 51 +++++++++---------- 2 files changed, 30 insertions(+), 35 deletions(-) diff --git a/staticlibs/device/android/net/util/Struct.java b/staticlibs/device/android/net/util/Struct.java index d0c763e483..92e05aa8b1 100644 --- a/staticlibs/device/android/net/util/Struct.java +++ b/staticlibs/device/android/net/util/Struct.java @@ -203,7 +203,7 @@ public class Struct { private static boolean matchConstructor(final Constructor cons, final FieldInfo[] fields) { final Class[] paramTypes = cons.getParameterTypes(); if (paramTypes.length != fields.length) return false; - for (int i = 0; i < cons.getParameterTypes().length; i++) { + for (int i = 0; i < paramTypes.length; i++) { if (!paramTypes[i].equals(fields[i].field.getType())) return false; } return true; @@ -295,6 +295,11 @@ public class Struct { } private static FieldInfo[] getClassFieldInfo(final Class clazz) { + if (!isStructSubclass(clazz)) { + throw new IllegalArgumentException(clazz.getName() + " is not a subclass of " + + Struct.class.getName()); + } + final FieldInfo[] annotationFields = new FieldInfo[getAnnotationFieldCount(clazz)]; // Since array returned from Class#getDeclaredFields doesn't guarantee the actual order @@ -332,11 +337,6 @@ public class Struct { */ public static T parse(final Class clazz, final ByteBuffer buf) { try { - if (!isStructSubclass(clazz)) { - throw new IllegalArgumentException(clazz.getName() + " is not a subclass of " - + Struct.class.getName()); - } - final FieldInfo[] foundFields = getClassFieldInfo(clazz); if (hasBothMutableAndImmutableFields(foundFields)) { throw new IllegalArgumentException("Class has both immutable and mutable fields"); @@ -354,7 +354,7 @@ public class Struct { throw new IllegalArgumentException("Fail to find available constructor"); } if (constructor != null) { - final Object[] args = new Object[constructor.getParameterTypes().length]; + final Object[] args = new Object[foundFields.length]; for (int i = 0; i < args.length; i++) { args[i] = getFieldValue(buf, foundFields[i]); } diff --git a/staticlibs/tests/unit/src/android/net/util/StructTest.java b/staticlibs/tests/unit/src/android/net/util/StructTest.java index 2d35891a59..34517393e9 100644 --- a/staticlibs/tests/unit/src/android/net/util/StructTest.java +++ b/staticlibs/tests/unit/src/android/net/util/StructTest.java @@ -57,9 +57,10 @@ public class StructTest { private static final String SIGNED_NEGATIVE_DATA = "81" + "0180" + "01000080" + "0100000000000080"; - // U8: 0xff, U16: 0xffff, U32: 0xffffffff, U64: 0xffffffffffffffff, U63: 0x7fffffffffffffff; + // U8: 0xff, U16: 0xffff, U32: 0xffffffff, U64: 0xffffffffffffffff, U63: 0x7fffffffffffffff, + // U63: 0xffffffffffffffff(-1L) private static final String UNSIGNED_DATA = "ff" + "ffff" + "ffffffff" + "ffffffffffffffff" - + "ffffffffffffff7f"; + + "ffffffffffffff7f" + "ffffffffffffffff"; // PREF64 option, 2001:db8:3:4:5:6::/96, lifetime: 10064 private static final String OPT_PREF64 = "2750" + "20010db80003000400050006"; @@ -149,8 +150,7 @@ public class StructTest { @Test public void testInvalidClass_NotSubClass() { final ByteBuffer buf = toByteBuffer(HDR_EMPTY); - assertThrows(IllegalArgumentException.class, - () -> Struct.parse(HeaderMessage.class, buf)); + assertThrows(IllegalArgumentException.class, () -> Struct.parse(HeaderMessage.class, buf)); } static class HeaderMessageMissingAnnotation extends Struct { @@ -209,17 +209,20 @@ public class StructTest { @Field(order = 2, type = Type.U32) final long mU32; @Field(order = 3, type = Type.U64) - final BigInteger mU64; + final BigInteger mU64; // represent U64 with BigInteger. @Field(order = 4, type = Type.U64) - final long mU63; + final long mU63; // represent U63 with long primitive. + @Field(order = 5, type = Type.U64) + final long mLU64; // represent U64 with long primitive. UnsignedDataMessage(final short u8, final int u16, final long u32, final BigInteger u64, - final long u63) { + final long u63, final long lu64) { mU8 = u8; mU16 = u16; mU32 = u32; mU64 = u64; mU63 = u63; + mLU64 = lu64; } } @@ -232,6 +235,7 @@ public class StructTest { assertEquals(4294967295L, msg.mU32); assertEquals(new BigInteger("18446744073709551615"), msg.mU64); assertEquals(9223372036854775807L, msg.mU63); + assertEquals(-1L, msg.mLU64); } static class SignedDataMessage extends Struct { @@ -243,41 +247,32 @@ public class StructTest { final int mS32; @Field(order = 3, type = Type.S64) final long mS64; - @Field(order = 4, type = Type.S8) - final byte mNS8; - @Field(order = 5, type = Type.S16) - final short mNS16; - @Field(order = 6, type = Type.S32) - final int mNS32; - @Field(order = 7, type = Type.S64) - final long mNS64; - SignedDataMessage(final byte s8, final short s16, final int s32, final long s64, - final byte nS8, final short nS16, final int nS32, final long nS64) { + SignedDataMessage(final byte s8, final short s16, final int s32, final long s64) { mS8 = s8; mS16 = s16; mS32 = s32; mS64 = s64; - mNS8 = nS8; - mNS16 = nS16; - mNS32 = nS32; - mNS64 = nS64; } } @Test - public void testSignedData() { - final SignedDataMessage msg = doParsingMessageTest(SIGNED_DATA + SIGNED_NEGATIVE_DATA, - SignedDataMessage.class); + public void testSignedPositiveData() { + final SignedDataMessage msg = doParsingMessageTest(SIGNED_DATA, SignedDataMessage.class); assertEquals(127, msg.mS8); assertEquals(32767, msg.mS16); assertEquals(2147483647, msg.mS32); assertEquals(9223372036854775807L, msg.mS64); + } - assertEquals(-127, msg.mNS8); - assertEquals(-32767, msg.mNS16); - assertEquals(-2147483647, msg.mNS32); - assertEquals(-9223372036854775807L, msg.mNS64); + @Test + public void testSignedNegativeData() { + final SignedDataMessage msg = doParsingMessageTest(SIGNED_NEGATIVE_DATA, + SignedDataMessage.class); + assertEquals(-127, msg.mS8); + assertEquals(-32767, msg.mS16); + assertEquals(-2147483647, msg.mS32); + assertEquals(-9223372036854775807L, msg.mS64); } static class HeaderMessageWithDuplicateOrder extends Struct { From a9f49910fe06be1ec7c265d531c2e4833362ec20 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 15 Oct 2020 18:06:30 +0900 Subject: [PATCH 069/777] Let frameworks/base/tests access the static lib Test: CtsNetTestCases FrameworksNetTests Change-Id: I51520b179fe2946f03311eccac97bf4bd4019aea --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index e5cc8b1f7c..2b5c2e85f4 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -124,6 +124,7 @@ java_library { visibility: [ "//cts/tests/tests/net", "//frameworks/base/packages/Tethering", + "//frameworks/base/tests:__subpackages__", "//frameworks/opt/net/ike", "//frameworks/opt/telephony", "//frameworks/base/wifi:__subpackages__", From c746481d10ec27bca96945f3dbd3a2ddd8645454 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 9 Oct 2020 11:13:02 +0900 Subject: [PATCH 070/777] Add basic tests for CompareResult ...as suggested in aosp/1448415 Test: this Change-Id: I8469ba6cbcbd9c1b414cfde6cda27505c210526c --- .../net/util/LinkPropertiesUtilsTest.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java index 6ffcc1d0a9..2142090bc6 100644 --- a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java @@ -28,6 +28,7 @@ import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult; import android.net.util.LinkPropertiesUtils.CompareResult; +import android.util.ArraySet; import androidx.test.runner.AndroidJUnit4; @@ -166,6 +167,58 @@ public final class LinkPropertiesUtilsTest { assertFalse(LinkPropertiesUtils.isIdenticalHttpProxy(target, source)); } + private void compareResult(List oldItems, List newItems, List expectRemoved, + List expectAdded) { + CompareResult result = new CompareResult<>(oldItems, newItems); + assertEquals(new ArraySet<>(expectAdded), new ArraySet<>(result.added)); + assertEquals(new ArraySet<>(expectRemoved), (new ArraySet<>(result.removed))); + } + + @Test + public void testCompareResult() { + // Either adding or removing items + compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(1), + Arrays.asList(2, 3, 4), new ArrayList<>()); + compareResult(Arrays.asList(1, 2), Arrays.asList(3, 2, 1, 4), + new ArrayList<>(), Arrays.asList(3, 4)); + + + // adding and removing items at the same time + compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(2, 3, 4, 5), + Arrays.asList(1), Arrays.asList(5)); + compareResult(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6), + Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6)); + + // null cases + compareResult(Arrays.asList(1, 2, 3), null, Arrays.asList(1, 2, 3), new ArrayList<>()); + compareResult(null, Arrays.asList(3, 2, 1), new ArrayList<>(), Arrays.asList(1, 2, 3)); + compareResult(null, null, new ArrayList<>(), new ArrayList<>()); + + // Some more tests with strings + final ArrayList list1 = new ArrayList<>(); + list1.add("string1"); + + final ArrayList list2 = new ArrayList<>(list1); + final CompareResult cr1 = new CompareResult<>(list1, list2); + assertTrue(cr1.added.isEmpty()); + assertTrue(cr1.removed.isEmpty()); + + list2.add("string2"); + final CompareResult cr2 = new CompareResult<>(list1, list2); + assertEquals(Arrays.asList("string2"), cr2.added); + assertTrue(cr2.removed.isEmpty()); + + list2.remove("string1"); + final CompareResult cr3 = new CompareResult<>(list1, list2); + assertEquals(Arrays.asList("string2"), cr3.added); + assertEquals(Arrays.asList("string1"), cr3.removed); + + list1.add("string2"); + final CompareResult cr4 = new CompareResult<>(list1, list2); + assertTrue(cr4.added.isEmpty()); + assertEquals(Arrays.asList("string1"), cr3.removed); + } + @Test public void testCompareAddresses() { final LinkProperties source = createTestObject(); From c064abd0dbc625fb5baf778dc93f545724533aac Mon Sep 17 00:00:00 2001 From: markchien Date: Mon, 26 Oct 2020 15:10:45 +0800 Subject: [PATCH 071/777] Move jarjar rules from NetworkStaticTestsLib to NetworkStaticTests jarjar should be applied on the final artifact (android_test, android_app, java_library that goes into an apex), not on any intermediate (android_library etc). Bug: 171670016 Test: atest NetworkStaticTests atest TetheringCoverageTests atest NetworkCoverageTests Change-Id: I86a15133112c555e08275efbde99e68315aa6bc2 --- staticlibs/tests/unit/Android.bp | 3 ++- staticlibs/tests/unit/jarjar-rules-sharedlib.txt | 6 ++++++ staticlibs/tests/unit/jarjar-rules.txt | 6 ------ 3 files changed, 8 insertions(+), 7 deletions(-) create mode 100644 staticlibs/tests/unit/jarjar-rules-sharedlib.txt diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index f18ffcfdd5..199b8cc279 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -6,7 +6,6 @@ android_library { name: "NetworkStaticLibTestsLib", srcs: ["src/**/*.java","src/**/*.kt"], min_sdk_version: "29", - jarjar_rules: "jarjar-rules.txt", static_libs: [ "net-utils-framework-common", "androidx.test.rules", @@ -17,6 +16,7 @@ android_library { "android.test.runner", "android.test.base", ], + jarjar_rules: "jarjar-rules-sharedlib.txt", visibility: [ "//frameworks/base/packages/Tethering/tests/integration", "//packages/modules/NetworkStack/tests/integration", @@ -29,6 +29,7 @@ android_test { static_libs: [ "NetworkStaticLibTestsLib", ], + jarjar_rules: "jarjar-rules.txt", test_suites: ["device-tests"], } diff --git a/staticlibs/tests/unit/jarjar-rules-sharedlib.txt b/staticlibs/tests/unit/jarjar-rules-sharedlib.txt new file mode 100644 index 0000000000..fceccfb755 --- /dev/null +++ b/staticlibs/tests/unit/jarjar-rules-sharedlib.txt @@ -0,0 +1,6 @@ +# TODO: move the classes to the target package in java +rule android.net.util.IpRange* com.android.net.module.util.IpRange@1 +rule android.net.util.MacAddressUtils* com.android.net.module.util.MacAddressUtils@1 +rule android.net.util.LinkPropertiesUtils* com.android.net.module.util.LinkPropertiesUtils@1 +rule android.net.util.NetUtils* com.android.net.module.util.NetUtils@1 +rule android.net.util.nsd.** com.android.net.module.util.nsd.@1 diff --git a/staticlibs/tests/unit/jarjar-rules.txt b/staticlibs/tests/unit/jarjar-rules.txt index 0f131b20d4..e032ae5030 100644 --- a/staticlibs/tests/unit/jarjar-rules.txt +++ b/staticlibs/tests/unit/jarjar-rules.txt @@ -1,7 +1 @@ -# TODO: move the classes to the target package in java -rule android.net.util.IpRange* com.android.net.moduletests.util.IpRange@1 -rule android.net.util.MacAddressUtils* com.android.net.moduletests.util.MacAddressUtils@1 -rule android.net.util.LinkPropertiesUtils* com.android.net.moduletests.util.LinkPropertiesUtils@1 -rule android.net.util.NetUtils* com.android.net.moduletests.util.NetUtils@1 -rule android.net.util.nsd.** com.android.net.moduletests.util.nsd.@1 rule com.android.net.module.util.** com.android.net.moduletests.util.@1 From ae4770df38d0d60d880ccf68855540a324097a40 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Thu, 29 Oct 2020 02:12:06 +0000 Subject: [PATCH 072/777] Add visibility rules for packages/modules/Connectivity/Tethering BUG: 167962976 Test: TH Change-Id: I4f9c63d27fe7f10534e89f3d132f26b2f45e7b07 --- staticlibs/Android.bp | 2 ++ staticlibs/tests/unit/Android.bp | 1 + 2 files changed, 3 insertions(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 08febfe2bd..c550e18b51 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -45,6 +45,7 @@ java_library { ], visibility: [ "//frameworks/base/packages/Tethering", + "//packages/modules/Connectivity/Tethering", "//frameworks/opt/net/ike", "//frameworks/opt/net/wifi/service", "//frameworks/opt/net/telephony", @@ -124,6 +125,7 @@ java_library { visibility: [ "//cts/tests/tests/net", "//frameworks/base/packages/Tethering", + "//packages/modules/Connectivity/Tethering", "//frameworks/base/tests:__subpackages__", "//frameworks/opt/net/ike", "//frameworks/opt/telephony", diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index 199b8cc279..c20b87db29 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -19,6 +19,7 @@ android_library { jarjar_rules: "jarjar-rules-sharedlib.txt", visibility: [ "//frameworks/base/packages/Tethering/tests/integration", + "//packages/modules/Connectivity/Tethering/tests/integration", "//packages/modules/NetworkStack/tests/integration", ] } From e685c813d5410f982160da82554a9e041c55b34c Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Sat, 31 Oct 2020 04:28:58 +0000 Subject: [PATCH 073/777] Adjust visibility to avoid build breaks. per b/167962976#comment10, following project directories are being moved under platform/packages/modules/Connectivity/... cts/test/net --> packages/modules/Connectivity/tests/cts/net cts/tests/tests/tethering -> packages/modules/Connectivity/tests/cts/tethering cts/hostsidetests/net -> packages/modules/Connectivity/tests/cts/hostside BUG: 167962976 Test: TH & Local Build Exempt-From-Owner-Approval: PS.1 +2d by Lorenzo. fixing tab (+2 not sticky) Change-Id: I4e13620ea16b74712a917737607bc3ed38c11cd9 --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index c550e18b51..020cc61e8b 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -124,6 +124,7 @@ java_library { jarjar_rules: "jarjar-rules-shared.txt", visibility: [ "//cts/tests/tests/net", + "//packages/modules/Connectivity/tests/cts/net", "//frameworks/base/packages/Tethering", "//packages/modules/Connectivity/Tethering", "//frameworks/base/tests:__subpackages__", From 92213091fce62174f324394a7479537a458b3eb4 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 26 Jun 2020 18:34:52 +0900 Subject: [PATCH 074/777] Move util classes to their destination package Test: FrameworksWifiTests FrameworksNetTests Change-Id: Id19c650246a8f3d55d7b6a874840a6eebcd9eb17 (cherry picked from commit e742f79a095f0930964d9517524de922ec103a4a) --- staticlibs/Android.bp | 5 ++--- .../android/net/module}/util/FdEventsReader.java | 9 ++++----- .../android/net/module}/util/PacketReader.java | 3 +-- .../com/android/testutils/TapPacketReader.java | 2 +- .../android/net/module/util}/DnsSdTxtRecord.java | 2 +- .../net => com/android/net/module}/util/IpRange.java | 2 +- .../android/net/module}/util/LinkPropertiesUtils.java | 2 +- .../android/net/module}/util/MacAddressUtils.java | 2 +- .../net => com/android/net/module}/util/NetUtils.java | 2 +- staticlibs/jarjar-rules-shared.txt | 6 ------ staticlibs/tests/unit/Android.bp | 1 - staticlibs/tests/unit/AndroidManifest.xml | 2 ++ staticlibs/tests/unit/jarjar-rules-sharedlib.txt | 6 ------ .../tests/unit/src/android/net/util/IpRangeTest.java | 2 ++ .../src/android/net/util/LinkPropertiesUtilsTest.java | 6 ++++-- .../unit/src/android/net/util/MacAddressUtilsTest.java | 2 ++ .../tests/unit/src/android/net/util/NetUtilsTest.java | 2 ++ .../com/android/net/module/util/PacketReaderTest.java | 7 ++----- 18 files changed, 27 insertions(+), 36 deletions(-) rename staticlibs/device/{android/net => com/android/net/module}/util/FdEventsReader.java (98%) rename staticlibs/device/{android/net => com/android/net/module}/util/PacketReader.java (94%) rename staticlibs/framework/{android/net/util/nsd => com/android/net/module/util}/DnsSdTxtRecord.java (99%) rename staticlibs/framework/{android/net => com/android/net/module}/util/IpRange.java (99%) rename staticlibs/framework/{android/net => com/android/net/module}/util/LinkPropertiesUtils.java (99%) rename staticlibs/framework/{android/net => com/android/net/module}/util/MacAddressUtils.java (99%) rename staticlibs/framework/{android/net => com/android/net/module}/util/NetUtils.java (98%) delete mode 100644 staticlibs/tests/unit/jarjar-rules-sharedlib.txt diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 020cc61e8b..0f3bc22784 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -124,6 +124,7 @@ java_library { jarjar_rules: "jarjar-rules-shared.txt", visibility: [ "//cts/tests/tests/net", + "//cts/tests/tests/wifi", "//packages/modules/Connectivity/tests/cts/net", "//frameworks/base/packages/Tethering", "//packages/modules/Connectivity/Tethering", @@ -169,8 +170,6 @@ filegroup { filegroup { name: "net-utils-framework-wifi-common-srcs", srcs: [ - "framework/android/net/util/nsd/DnsSdTxtRecord.java", - "framework/android/net/util/MacAddressUtils.java", "framework/com/android/net/module/util/**/*.java", ], path: "framework", @@ -186,7 +185,7 @@ filegroup { name: "net-utils-wifi-service-common-srcs", srcs: [ "device/android/net/NetworkFactory.java", - "framework/android/net/util/NetUtils.java", + "framework/com/android/net/module/util/NetUtils.java", ], visibility: [ "//frameworks/opt/net/wifi/service", diff --git a/staticlibs/device/android/net/util/FdEventsReader.java b/staticlibs/device/com/android/net/module/util/FdEventsReader.java similarity index 98% rename from staticlibs/device/android/net/util/FdEventsReader.java rename to staticlibs/device/com/android/net/module/util/FdEventsReader.java index a5714aa5db..71ae13d80d 100644 --- a/staticlibs/device/android/net/util/FdEventsReader.java +++ b/staticlibs/device/com/android/net/module/util/FdEventsReader.java @@ -14,12 +14,14 @@ * limitations under the License. */ -// TODO : move this and PacketReader to com.android.net.module.util. -package android.net.util; +package com.android.net.module.util; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.util.SocketUtils; import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; @@ -27,9 +29,6 @@ import android.system.ErrnoException; import android.system.OsConstants; import android.util.Log; -import android.annotation.NonNull; -import android.annotation.Nullable; - import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; diff --git a/staticlibs/device/android/net/util/PacketReader.java b/staticlibs/device/com/android/net/module/util/PacketReader.java similarity index 94% rename from staticlibs/device/android/net/util/PacketReader.java rename to staticlibs/device/com/android/net/module/util/PacketReader.java index 61b3d6e294..66c47888c3 100644 --- a/staticlibs/device/android/net/util/PacketReader.java +++ b/staticlibs/device/com/android/net/module/util/PacketReader.java @@ -14,8 +14,7 @@ * limitations under the License. */ -// TODO : move this and FdEventsReader to com.android.net.module.util. -package android.net.util; +package com.android.net.module.util; import static java.lang.Math.max; diff --git a/staticlibs/devicetests/com/android/testutils/TapPacketReader.java b/staticlibs/devicetests/com/android/testutils/TapPacketReader.java index 001b709903..b25b9f214b 100644 --- a/staticlibs/devicetests/com/android/testutils/TapPacketReader.java +++ b/staticlibs/devicetests/com/android/testutils/TapPacketReader.java @@ -16,13 +16,13 @@ package com.android.testutils; -import android.net.util.PacketReader; import android.os.Handler; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.net.module.util.ArrayTrackRecord; +import com.android.net.module.util.PacketReader; import java.io.FileDescriptor; import java.io.FileOutputStream; diff --git a/staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java b/staticlibs/framework/com/android/net/module/util/DnsSdTxtRecord.java similarity index 99% rename from staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java rename to staticlibs/framework/com/android/net/module/util/DnsSdTxtRecord.java index 81768f7ed1..760891b9fc 100644 --- a/staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java +++ b/staticlibs/framework/com/android/net/module/util/DnsSdTxtRecord.java @@ -19,7 +19,7 @@ - fix set() to replace existing values */ -package android.net.util.nsd; +package com.android.net.module.util; import android.os.Parcelable; import android.os.Parcel; diff --git a/staticlibs/framework/android/net/util/IpRange.java b/staticlibs/framework/com/android/net/module/util/IpRange.java similarity index 99% rename from staticlibs/framework/android/net/util/IpRange.java rename to staticlibs/framework/com/android/net/module/util/IpRange.java index 099770bca4..40b57b10f0 100644 --- a/staticlibs/framework/android/net/util/IpRange.java +++ b/staticlibs/framework/com/android/net/module/util/IpRange.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import static com.android.internal.annotations.VisibleForTesting.Visibility; diff --git a/staticlibs/framework/android/net/util/LinkPropertiesUtils.java b/staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java similarity index 99% rename from staticlibs/framework/android/net/util/LinkPropertiesUtils.java rename to staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java index 282fa10d2b..1565f2bc2f 100644 --- a/staticlibs/framework/android/net/util/LinkPropertiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/staticlibs/framework/android/net/util/MacAddressUtils.java b/staticlibs/framework/com/android/net/module/util/MacAddressUtils.java similarity index 99% rename from staticlibs/framework/android/net/util/MacAddressUtils.java rename to staticlibs/framework/com/android/net/module/util/MacAddressUtils.java index 969d1270be..bc11fa2a7c 100644 --- a/staticlibs/framework/android/net/util/MacAddressUtils.java +++ b/staticlibs/framework/com/android/net/module/util/MacAddressUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/staticlibs/framework/android/net/util/NetUtils.java b/staticlibs/framework/com/android/net/module/util/NetUtils.java similarity index 98% rename from staticlibs/framework/android/net/util/NetUtils.java rename to staticlibs/framework/com/android/net/module/util/NetUtils.java index 302119ea11..4331b65de0 100644 --- a/staticlibs/framework/android/net/util/NetUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/staticlibs/jarjar-rules-shared.txt b/staticlibs/jarjar-rules-shared.txt index 9e618db19b..a7fda7c0ac 100644 --- a/staticlibs/jarjar-rules-shared.txt +++ b/staticlibs/jarjar-rules-shared.txt @@ -1,8 +1,2 @@ -# TODO: move the classes to the target package in java -rule android.net.util.IpRange* com.android.net.module.util.IpRange@1 -rule android.net.util.MacAddressUtils* com.android.net.module.util.MacAddressUtils@1 -rule android.net.util.LinkPropertiesUtils* com.android.net.module.util.LinkPropertiesUtils@1 -rule android.net.util.NetUtils* com.android.net.module.util.NetUtils@1 -rule android.net.util.nsd.** com.android.net.module.util.nsd.@1 rule android.annotation.** com.android.net.module.annotation.@1 rule com.android.internal.annotations.** com.android.net.module.annotation.@1 diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index c20b87db29..537340ef78 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -16,7 +16,6 @@ android_library { "android.test.runner", "android.test.base", ], - jarjar_rules: "jarjar-rules-sharedlib.txt", visibility: [ "//frameworks/base/packages/Tethering/tests/integration", "//packages/modules/Connectivity/Tethering/tests/integration", diff --git a/staticlibs/tests/unit/AndroidManifest.xml b/staticlibs/tests/unit/AndroidManifest.xml index cc9e09ea76..c747c8a585 100644 --- a/staticlibs/tests/unit/AndroidManifest.xml +++ b/staticlibs/tests/unit/AndroidManifest.xml @@ -17,6 +17,8 @@ + + diff --git a/staticlibs/tests/unit/jarjar-rules-sharedlib.txt b/staticlibs/tests/unit/jarjar-rules-sharedlib.txt deleted file mode 100644 index fceccfb755..0000000000 --- a/staticlibs/tests/unit/jarjar-rules-sharedlib.txt +++ /dev/null @@ -1,6 +0,0 @@ -# TODO: move the classes to the target package in java -rule android.net.util.IpRange* com.android.net.module.util.IpRange@1 -rule android.net.util.MacAddressUtils* com.android.net.module.util.MacAddressUtils@1 -rule android.net.util.LinkPropertiesUtils* com.android.net.module.util.LinkPropertiesUtils@1 -rule android.net.util.NetUtils* com.android.net.module.util.NetUtils@1 -rule android.net.util.nsd.** com.android.net.module.util.nsd.@1 diff --git a/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java b/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java index f4d07e9b3e..677db6956f 100644 --- a/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java +++ b/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java @@ -28,6 +28,8 @@ import android.net.IpPrefix; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.IpRange; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java index 2142090bc6..e47c864350 100644 --- a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java @@ -26,12 +26,14 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.ProxyInfo; import android.net.RouteInfo; -import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult; -import android.net.util.LinkPropertiesUtils.CompareResult; import android.util.ArraySet; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.LinkPropertiesUtils; +import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult; +import com.android.net.module.util.LinkPropertiesUtils.CompareResult; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java index ad63b3c9eb..66d89ffd1d 100644 --- a/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java @@ -24,6 +24,8 @@ import android.net.MacAddress; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.MacAddressUtils; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java index 903e80d369..338d1c80fe 100644 --- a/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java @@ -27,6 +27,8 @@ import android.net.RouteInfo; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.NetUtils; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java index 046a1d9d15..459801c272 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java @@ -16,7 +16,6 @@ package com.android.net.module.util; -import static android.net.util.PacketReader.DEFAULT_RECV_BUF_SIZE; import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; @@ -24,14 +23,13 @@ import static android.system.OsConstants.SOCK_NONBLOCK; import static android.system.OsConstants.SOL_SOCKET; import static android.system.OsConstants.SO_SNDTIMEO; +import static com.android.net.module.util.PacketReader.DEFAULT_RECV_BUF_SIZE; import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import android.net.util.PacketReader; import android.os.Handler; import android.os.HandlerThread; import android.system.ErrnoException; @@ -93,8 +91,7 @@ public class PacketReaderTest { Os.setsockoptTimeval(s, SOL_SOCKET, SO_SNDTIMEO, TIMEO); } catch (ErrnoException | SocketException e) { closeFd(s); - fail(); - return null; + throw new RuntimeException("Failed to create FD", e); } mLocalSocket = s; From 2dbab6439b530c91612032cd2ca8757a4bb660cf Mon Sep 17 00:00:00 2001 From: David Su Date: Mon, 26 Oct 2020 14:51:01 -0700 Subject: [PATCH 075/777] Create net-utils-services-common-srcs ...in order to allow "services.net-module-wifi" to use it. Bug: 171330443 Test: compiles Change-Id: I67300429e1a95344c2287ec0358c94c651d2f9f9 --- staticlibs/Android.bp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 08febfe2bd..4d842efead 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -134,10 +134,20 @@ java_library { ] } +filegroup { + name: "net-utils-services-common-srcs", + srcs: [ + "device/android/net/NetworkFactory.java", + ], + visibility: [ + "//frameworks/base/services/net", + ], +} + java_library { name: "net-utils-services-common", srcs: [ - "device/android/net/NetworkFactory.java", + ":net-utils-services-common-srcs", ":framework-annotations", ], sdk_version: "system_current", From 94912a1b0acb48f72e7182be712cd3748735777b Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 26 Jun 2020 18:34:52 +0900 Subject: [PATCH 076/777] Move util classes to their destination package Test: FrameworksWifiTests FrameworksNetTests Change-Id: Id19c650246a8f3d55d7b6a874840a6eebcd9eb17 Merged-In: Id19c650246a8f3d55d7b6a874840a6eebcd9eb17 --- staticlibs/Android.bp | 5 ++--- .../android/net/module}/util/FdEventsReader.java | 9 ++++----- .../android/net/module}/util/PacketReader.java | 3 +-- .../com/android/testutils/TapPacketReader.java | 2 +- .../android/net/module/util}/DnsSdTxtRecord.java | 2 +- .../net => com/android/net/module}/util/IpRange.java | 2 +- .../android/net/module}/util/LinkPropertiesUtils.java | 2 +- .../android/net/module}/util/MacAddressUtils.java | 2 +- .../net => com/android/net/module}/util/NetUtils.java | 2 +- staticlibs/jarjar-rules-shared.txt | 6 ------ staticlibs/tests/unit/Android.bp | 1 - staticlibs/tests/unit/AndroidManifest.xml | 2 ++ staticlibs/tests/unit/jarjar-rules-sharedlib.txt | 6 ------ .../tests/unit/src/android/net/util/IpRangeTest.java | 2 ++ .../src/android/net/util/LinkPropertiesUtilsTest.java | 6 ++++-- .../unit/src/android/net/util/MacAddressUtilsTest.java | 2 ++ .../tests/unit/src/android/net/util/NetUtilsTest.java | 2 ++ .../com/android/net/module/util/PacketReaderTest.java | 7 ++----- 18 files changed, 27 insertions(+), 36 deletions(-) rename staticlibs/device/{android/net => com/android/net/module}/util/FdEventsReader.java (98%) rename staticlibs/device/{android/net => com/android/net/module}/util/PacketReader.java (94%) rename staticlibs/framework/{android/net/util/nsd => com/android/net/module/util}/DnsSdTxtRecord.java (99%) rename staticlibs/framework/{android/net => com/android/net/module}/util/IpRange.java (99%) rename staticlibs/framework/{android/net => com/android/net/module}/util/LinkPropertiesUtils.java (99%) rename staticlibs/framework/{android/net => com/android/net/module}/util/MacAddressUtils.java (99%) rename staticlibs/framework/{android/net => com/android/net/module}/util/NetUtils.java (98%) delete mode 100644 staticlibs/tests/unit/jarjar-rules-sharedlib.txt diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index a1a998eb60..76aceda81c 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -124,6 +124,7 @@ java_library { jarjar_rules: "jarjar-rules-shared.txt", visibility: [ "//cts/tests/tests/net", + "//cts/tests/tests/wifi", "//packages/modules/Connectivity/tests/cts/net", "//frameworks/base/packages/Tethering", "//packages/modules/Connectivity/Tethering", @@ -179,8 +180,6 @@ filegroup { filegroup { name: "net-utils-framework-wifi-common-srcs", srcs: [ - "framework/android/net/util/nsd/DnsSdTxtRecord.java", - "framework/android/net/util/MacAddressUtils.java", "framework/com/android/net/module/util/**/*.java", ], path: "framework", @@ -196,7 +195,7 @@ filegroup { name: "net-utils-wifi-service-common-srcs", srcs: [ "device/android/net/NetworkFactory.java", - "framework/android/net/util/NetUtils.java", + "framework/com/android/net/module/util/NetUtils.java", ], visibility: [ "//frameworks/opt/net/wifi/service", diff --git a/staticlibs/device/android/net/util/FdEventsReader.java b/staticlibs/device/com/android/net/module/util/FdEventsReader.java similarity index 98% rename from staticlibs/device/android/net/util/FdEventsReader.java rename to staticlibs/device/com/android/net/module/util/FdEventsReader.java index a5714aa5db..71ae13d80d 100644 --- a/staticlibs/device/android/net/util/FdEventsReader.java +++ b/staticlibs/device/com/android/net/module/util/FdEventsReader.java @@ -14,12 +14,14 @@ * limitations under the License. */ -// TODO : move this and PacketReader to com.android.net.module.util. -package android.net.util; +package com.android.net.module.util; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.util.SocketUtils; import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; @@ -27,9 +29,6 @@ import android.system.ErrnoException; import android.system.OsConstants; import android.util.Log; -import android.annotation.NonNull; -import android.annotation.Nullable; - import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; diff --git a/staticlibs/device/android/net/util/PacketReader.java b/staticlibs/device/com/android/net/module/util/PacketReader.java similarity index 94% rename from staticlibs/device/android/net/util/PacketReader.java rename to staticlibs/device/com/android/net/module/util/PacketReader.java index 61b3d6e294..66c47888c3 100644 --- a/staticlibs/device/android/net/util/PacketReader.java +++ b/staticlibs/device/com/android/net/module/util/PacketReader.java @@ -14,8 +14,7 @@ * limitations under the License. */ -// TODO : move this and FdEventsReader to com.android.net.module.util. -package android.net.util; +package com.android.net.module.util; import static java.lang.Math.max; diff --git a/staticlibs/devicetests/com/android/testutils/TapPacketReader.java b/staticlibs/devicetests/com/android/testutils/TapPacketReader.java index 001b709903..b25b9f214b 100644 --- a/staticlibs/devicetests/com/android/testutils/TapPacketReader.java +++ b/staticlibs/devicetests/com/android/testutils/TapPacketReader.java @@ -16,13 +16,13 @@ package com.android.testutils; -import android.net.util.PacketReader; import android.os.Handler; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.net.module.util.ArrayTrackRecord; +import com.android.net.module.util.PacketReader; import java.io.FileDescriptor; import java.io.FileOutputStream; diff --git a/staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java b/staticlibs/framework/com/android/net/module/util/DnsSdTxtRecord.java similarity index 99% rename from staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java rename to staticlibs/framework/com/android/net/module/util/DnsSdTxtRecord.java index 81768f7ed1..760891b9fc 100644 --- a/staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java +++ b/staticlibs/framework/com/android/net/module/util/DnsSdTxtRecord.java @@ -19,7 +19,7 @@ - fix set() to replace existing values */ -package android.net.util.nsd; +package com.android.net.module.util; import android.os.Parcelable; import android.os.Parcel; diff --git a/staticlibs/framework/android/net/util/IpRange.java b/staticlibs/framework/com/android/net/module/util/IpRange.java similarity index 99% rename from staticlibs/framework/android/net/util/IpRange.java rename to staticlibs/framework/com/android/net/module/util/IpRange.java index 099770bca4..40b57b10f0 100644 --- a/staticlibs/framework/android/net/util/IpRange.java +++ b/staticlibs/framework/com/android/net/module/util/IpRange.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import static com.android.internal.annotations.VisibleForTesting.Visibility; diff --git a/staticlibs/framework/android/net/util/LinkPropertiesUtils.java b/staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java similarity index 99% rename from staticlibs/framework/android/net/util/LinkPropertiesUtils.java rename to staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java index 282fa10d2b..1565f2bc2f 100644 --- a/staticlibs/framework/android/net/util/LinkPropertiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/staticlibs/framework/android/net/util/MacAddressUtils.java b/staticlibs/framework/com/android/net/module/util/MacAddressUtils.java similarity index 99% rename from staticlibs/framework/android/net/util/MacAddressUtils.java rename to staticlibs/framework/com/android/net/module/util/MacAddressUtils.java index 969d1270be..bc11fa2a7c 100644 --- a/staticlibs/framework/android/net/util/MacAddressUtils.java +++ b/staticlibs/framework/com/android/net/module/util/MacAddressUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/staticlibs/framework/android/net/util/NetUtils.java b/staticlibs/framework/com/android/net/module/util/NetUtils.java similarity index 98% rename from staticlibs/framework/android/net/util/NetUtils.java rename to staticlibs/framework/com/android/net/module/util/NetUtils.java index 302119ea11..4331b65de0 100644 --- a/staticlibs/framework/android/net/util/NetUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/staticlibs/jarjar-rules-shared.txt b/staticlibs/jarjar-rules-shared.txt index 9e618db19b..a7fda7c0ac 100644 --- a/staticlibs/jarjar-rules-shared.txt +++ b/staticlibs/jarjar-rules-shared.txt @@ -1,8 +1,2 @@ -# TODO: move the classes to the target package in java -rule android.net.util.IpRange* com.android.net.module.util.IpRange@1 -rule android.net.util.MacAddressUtils* com.android.net.module.util.MacAddressUtils@1 -rule android.net.util.LinkPropertiesUtils* com.android.net.module.util.LinkPropertiesUtils@1 -rule android.net.util.NetUtils* com.android.net.module.util.NetUtils@1 -rule android.net.util.nsd.** com.android.net.module.util.nsd.@1 rule android.annotation.** com.android.net.module.annotation.@1 rule com.android.internal.annotations.** com.android.net.module.annotation.@1 diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index c20b87db29..537340ef78 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -16,7 +16,6 @@ android_library { "android.test.runner", "android.test.base", ], - jarjar_rules: "jarjar-rules-sharedlib.txt", visibility: [ "//frameworks/base/packages/Tethering/tests/integration", "//packages/modules/Connectivity/Tethering/tests/integration", diff --git a/staticlibs/tests/unit/AndroidManifest.xml b/staticlibs/tests/unit/AndroidManifest.xml index cc9e09ea76..c747c8a585 100644 --- a/staticlibs/tests/unit/AndroidManifest.xml +++ b/staticlibs/tests/unit/AndroidManifest.xml @@ -17,6 +17,8 @@ + + diff --git a/staticlibs/tests/unit/jarjar-rules-sharedlib.txt b/staticlibs/tests/unit/jarjar-rules-sharedlib.txt deleted file mode 100644 index fceccfb755..0000000000 --- a/staticlibs/tests/unit/jarjar-rules-sharedlib.txt +++ /dev/null @@ -1,6 +0,0 @@ -# TODO: move the classes to the target package in java -rule android.net.util.IpRange* com.android.net.module.util.IpRange@1 -rule android.net.util.MacAddressUtils* com.android.net.module.util.MacAddressUtils@1 -rule android.net.util.LinkPropertiesUtils* com.android.net.module.util.LinkPropertiesUtils@1 -rule android.net.util.NetUtils* com.android.net.module.util.NetUtils@1 -rule android.net.util.nsd.** com.android.net.module.util.nsd.@1 diff --git a/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java b/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java index f4d07e9b3e..677db6956f 100644 --- a/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java +++ b/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java @@ -28,6 +28,8 @@ import android.net.IpPrefix; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.IpRange; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java index 2142090bc6..e47c864350 100644 --- a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java @@ -26,12 +26,14 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.ProxyInfo; import android.net.RouteInfo; -import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult; -import android.net.util.LinkPropertiesUtils.CompareResult; import android.util.ArraySet; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.LinkPropertiesUtils; +import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult; +import com.android.net.module.util.LinkPropertiesUtils.CompareResult; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java index ad63b3c9eb..66d89ffd1d 100644 --- a/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java @@ -24,6 +24,8 @@ import android.net.MacAddress; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.MacAddressUtils; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java index 903e80d369..338d1c80fe 100644 --- a/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java @@ -27,6 +27,8 @@ import android.net.RouteInfo; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.NetUtils; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java index 046a1d9d15..459801c272 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java @@ -16,7 +16,6 @@ package com.android.net.module.util; -import static android.net.util.PacketReader.DEFAULT_RECV_BUF_SIZE; import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; @@ -24,14 +23,13 @@ import static android.system.OsConstants.SOCK_NONBLOCK; import static android.system.OsConstants.SOL_SOCKET; import static android.system.OsConstants.SO_SNDTIMEO; +import static com.android.net.module.util.PacketReader.DEFAULT_RECV_BUF_SIZE; import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import android.net.util.PacketReader; import android.os.Handler; import android.os.HandlerThread; import android.system.ErrnoException; @@ -93,8 +91,7 @@ public class PacketReaderTest { Os.setsockoptTimeval(s, SOL_SOCKET, SO_SNDTIMEO, TIMEO); } catch (ErrnoException | SocketException e) { closeFd(s); - fail(); - return null; + throw new RuntimeException("Failed to create FD", e); } mLocalSocket = s; From a76690a3b7f0c4b8c1b1aa68f5479144c3e361b8 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 4 Nov 2020 10:41:04 +0900 Subject: [PATCH 077/777] Introduce cache schema for generic Struct class. Bug: 163492391 Test: atest android.net.util.StructTest --rerun-until-failure Change-Id: Idffad7d3b907d8853ed7d296808a2e0e2736cbbe --- .../device/android/net/util/Struct.java | 9 ++++- .../unit/src/android/net/util/StructTest.java | 37 ++++++++++++++----- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/staticlibs/device/android/net/util/Struct.java b/staticlibs/device/android/net/util/Struct.java index 92e05aa8b1..03f5f22b28 100644 --- a/staticlibs/device/android/net/util/Struct.java +++ b/staticlibs/device/android/net/util/Struct.java @@ -29,6 +29,7 @@ import java.math.BigInteger; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.concurrent.ConcurrentHashMap; /** * Define a generic class that helps to parse the structured message. @@ -142,6 +143,7 @@ public class Struct { this.field = field; } } + private static ConcurrentHashMap sFieldCache = new ConcurrentHashMap(); private static void checkAnnotationType(final Type type, final Class fieldType) { switch (type) { @@ -300,11 +302,15 @@ public class Struct { + Struct.class.getName()); } - final FieldInfo[] annotationFields = new FieldInfo[getAnnotationFieldCount(clazz)]; + final FieldInfo[] cachedAnnotationFields = sFieldCache.get(clazz); + if (cachedAnnotationFields != null) { + return cachedAnnotationFields; + } // Since array returned from Class#getDeclaredFields doesn't guarantee the actual order // of field appeared in the class, that is a problem when parsing raw data read from // ByteBuffer. Store the fields appeared by the order() defined in the Field annotation. + final FieldInfo[] annotationFields = new FieldInfo[getAnnotationFieldCount(clazz)]; for (java.lang.reflect.Field field : clazz.getDeclaredFields()) { if (Modifier.isStatic(field.getModifiers())) continue; @@ -324,6 +330,7 @@ public class Struct { } annotationFields[annotation.order()] = new FieldInfo(annotation, field); } + sFieldCache.putIfAbsent(clazz, annotationFields); return annotationFields; } diff --git a/staticlibs/tests/unit/src/android/net/util/StructTest.java b/staticlibs/tests/unit/src/android/net/util/StructTest.java index 34517393e9..5ca278ac2c 100644 --- a/staticlibs/tests/unit/src/android/net/util/StructTest.java +++ b/staticlibs/tests/unit/src/android/net/util/StructTest.java @@ -96,10 +96,7 @@ public class StructTest { } } - @Test - public void testClassWithExplicitConstructor() { - final HeaderMsgWithConstructor msg = doParsingMessageTest(HDR_EMPTY, - HeaderMsgWithConstructor.class); + private void verifyHeaderParsing(final HeaderMsgWithConstructor msg) { assertEquals(10, msg.mFamily); assertEquals(0, msg.mLen); assertEquals(15715755, msg.mIfindex); @@ -107,6 +104,13 @@ public class StructTest { assertEquals(0, msg.mIcmpCode); } + @Test + public void testClassWithExplicitConstructor() { + final HeaderMsgWithConstructor msg = doParsingMessageTest(HDR_EMPTY, + HeaderMsgWithConstructor.class); + verifyHeaderParsing(msg); + } + static class HeaderMsgWithoutConstructor extends Struct { static int sType; static int sLength; @@ -367,21 +371,22 @@ public class StructTest { } } - @Test - public void testPrefixArrayField() throws Exception { - final ByteBuffer buf = toByteBuffer(OPT_PREF64); - buf.order(ByteOrder.LITTLE_ENDIAN); - + private void verifyPrefixByteArrayParsing(final PrefixMessage msg) throws Exception { // The original PREF64 option message has just 12 bytes for prefix byte array // (Highest 96 bits of the Prefix), copyOf pads the 128-bits IPv6 address with // prefix and 4-bytes zeros. - final PrefixMessage msg = Struct.parse(PrefixMessage.class, buf); final InetAddress addr = InetAddress.getByAddress(Arrays.copyOf(msg.mPrefix, 16)); final IpPrefix prefix = new IpPrefix(addr, 96); assertEquals(10064, msg.mLifetime); assertTrue(prefix.equals(new IpPrefix("2001:db8:3:4:5:6::/96"))); } + @Test + public void testPrefixArrayField() throws Exception { + final PrefixMessage msg = doParsingMessageTest(OPT_PREF64, PrefixMessage.class); + verifyPrefixByteArrayParsing(msg); + } + static class HeaderMessageWithMutableField extends Struct { @Field(order = 0, type = Type.U8, padding = 1) final short mFamily; @@ -481,6 +486,18 @@ public class StructTest { assertEquals(30806 /* 0x7856 */, msg.mInt2); } + @Test + public void testClassesParsedFromCache() throws Exception { + for (int i = 0; i < 100; i++) { + final HeaderMsgWithConstructor msg1 = + doParsingMessageTest(HDR_EMPTY, HeaderMsgWithConstructor.class); + verifyHeaderParsing(msg1); + + final PrefixMessage msg2 = doParsingMessageTest(OPT_PREF64, PrefixMessage.class); + verifyPrefixByteArrayParsing(msg2); + } + } + private ByteBuffer toByteBuffer(final String hexString) { return ByteBuffer.wrap(HexDump.hexStringToByteArray(hexString)); } From 38afb0cd0713bb638f561670a6fb605b09b9e418 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 10 Nov 2020 18:04:27 +0900 Subject: [PATCH 078/777] Add visibility rules for Connectivity project The packages/modules/Connectivity project contains module code that can depend on net-utils-device-common or net-utils-framework-common. Bug: 171540887 Test: m Change-Id: Ie754e3f55d78aabff4cef2da3a2a94a1204bd5e5 --- staticlibs/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index a1a998eb60..4a51db84f6 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -49,6 +49,8 @@ java_library { "//frameworks/opt/net/ike", "//frameworks/opt/net/wifi/service", "//frameworks/opt/net/telephony", + "//frameworks/base/packages/Connectivity:__subpackages__", + "//packages/modules/Connectivity:__subpackages__", "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", @@ -131,6 +133,8 @@ java_library { "//frameworks/opt/net/ike", "//frameworks/opt/telephony", "//frameworks/base/wifi:__subpackages__", + "//frameworks/base/packages/Connectivity:__subpackages__", + "//packages/modules/Connectivity:__subpackages__", "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", From 1ba696dbf70ecf631e1be4f2d849530cd7a45236 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 30 Nov 2020 17:19:18 +0900 Subject: [PATCH 079/777] Add NetworkStackConstants to framework/ The constants are also useful for bootclasspath code, for example in Ikev2VpnProfile. Bug: 174436414 Test: atest FrameworksNetTests NetworkStackTests NetworkStaticLibTests Change-Id: I34458fe6568a73533f956f86ed7bb50d45aa7d7e --- .../com/android/net/module/util/NetworkStackConstants.java | 1 + 1 file changed, 1 insertion(+) rename staticlibs/{device => framework}/com/android/net/module/util/NetworkStackConstants.java (99%) diff --git a/staticlibs/device/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java similarity index 99% rename from staticlibs/device/com/android/net/module/util/NetworkStackConstants.java rename to staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 1088477cb2..1572fe0438 100644 --- a/staticlibs/device/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -22,6 +22,7 @@ import java.net.UnknownHostException; /** * Network constants used by the network stack. + * @hide */ public final class NetworkStackConstants { From f4cb6d6789e9568efe2de5edf43598e522a8dd14 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 23 Oct 2020 18:10:12 +0900 Subject: [PATCH 080/777] Add new APIs writeToByteBuffer/writeToBytes for generic Struct class. Split the original U64/UBE64 into two groups: U63/UBE63 which could be represented by long primitive directly and U64/UBE64 which should be represented by BigInteger class. Also fix the endianness-related issue to support both of big-endian or little-endian input ByteBuffer, and writeToBytes API outputs the bytes array in appropriate order then. Bug: 163492391 Test: atest android.net.util.StructTest --rerun-until-failure Change-Id: Ie9c07fac6dcfceb8efdf1d6b56ce6ff1e845f477 --- .../device/android/net/util/Struct.java | 288 +++++++++++++++--- .../unit/src/android/net/util/StructTest.java | 240 ++++++++++++--- 2 files changed, 447 insertions(+), 81 deletions(-) diff --git a/staticlibs/device/android/net/util/Struct.java b/staticlibs/device/android/net/util/Struct.java index 03f5f22b28..841829e502 100644 --- a/staticlibs/device/android/net/util/Struct.java +++ b/staticlibs/device/android/net/util/Struct.java @@ -99,14 +99,16 @@ public class Struct { U8, // unsigned byte, size = 1 byte U16, // unsigned short, size = 2 bytes U32, // unsigned int, size = 4 bytes + U63, // unsigned long(MSB: 0), size = 8 bytes U64, // unsigned long, size = 8 bytes S8, // signed byte, size = 1 byte S16, // signed short, size = 2 bytes S32, // signed int, size = 4 bytes S64, // signed long, size = 8 bytes - BE16, // unsigned short in network order, size = 2 bytes - BE32, // unsigned int in network order, size = 4 bytes - BE64, // unsigned long in network order, size = 8 bytes + UBE16, // unsigned short in network order, size = 2 bytes + UBE32, // unsigned int in network order, size = 4 bytes + UBE63, // unsigned long(MSB: 0) in network order, size = 8 bytes + UBE64, // unsigned long in network order, size = 8 bytes ByteArray, // byte array with predefined length } @@ -120,7 +122,7 @@ public class Struct { * arraysize: The length of byte array. * * Annotation associated with field MUST have order and type properties at least, padding - * and arraysize properties depend on the specific usage, if these properties are absence, + * and arraysize properties depend on the specific usage, if these properties are absent, * then default value 0 will be applied. */ @Retention(RetentionPolicy.RUNTIME) @@ -145,37 +147,76 @@ public class Struct { } private static ConcurrentHashMap sFieldCache = new ConcurrentHashMap(); - private static void checkAnnotationType(final Type type, final Class fieldType) { - switch (type) { + private static void checkAnnotationType(final Field annotation, final Class fieldType) { + switch (annotation.type()) { case U8: case S16: if (fieldType == Short.TYPE) return; break; case U16: case S32: - case BE16: + case UBE16: if (fieldType == Integer.TYPE) return; break; case U32: + case U63: case S64: - case BE32: + case UBE32: + case UBE63: if (fieldType == Long.TYPE) return; break; case U64: - case BE64: - if (fieldType == BigInteger.class || fieldType == Long.TYPE) return; + case UBE64: + if (fieldType == BigInteger.class) return; break; case S8: if (fieldType == Byte.TYPE) return; break; case ByteArray: - if (fieldType == byte[].class) return; - break; + if (fieldType != byte[].class) break; + if (annotation.arraysize() <= 0) { + throw new IllegalArgumentException("Invalid ByteArray size: " + + annotation.arraysize()); + } + return; default: - throw new IllegalArgumentException("Unknown type" + type); + throw new IllegalArgumentException("Unknown type" + annotation.type()); } throw new IllegalArgumentException("Invalid primitive data type: " + fieldType - + "for annotation type: " + type); + + " for annotation type: " + annotation.type()); + } + + private static int getFieldLength(final Field annotation) { + int length = 0; + switch (annotation.type()) { + case U8: + case S8: + length = 1; + break; + case U16: + case S16: + case UBE16: + length = 2; + break; + case U32: + case S32: + case UBE32: + length = 4; + break; + case U63: + case U64: + case S64: + case UBE63: + case UBE64: + length = 8; + break; + case ByteArray: + length = annotation.arraysize(); + break; + default: + throw new IllegalArgumentException("Unknown type" + annotation.type()); + } + return length + annotation.padding(); } private static boolean isStructSubclass(final Class clazz) { @@ -190,7 +231,7 @@ public class Struct { return count; } - private static boolean matchModifier(final FieldInfo[] fields, boolean immutable) { + private static boolean allFieldsFinal(final FieldInfo[] fields, boolean immutable) { for (FieldInfo fi : fields) { if (Modifier.isFinal(fi.field.getModifiers()) != immutable) return false; } @@ -198,8 +239,8 @@ public class Struct { } private static boolean hasBothMutableAndImmutableFields(final FieldInfo[] fields) { - return !matchModifier(fields, true /* immutable */) - && !matchModifier(fields, false /* mutable */); + return !allFieldsFinal(fields, true /* immutable */) + && !allFieldsFinal(fields, false /* mutable */); } private static boolean matchConstructor(final Constructor cons, final FieldInfo[] fields) { @@ -211,21 +252,72 @@ public class Struct { return true; } - private static BigInteger readBigInteger(final ByteBuffer buf) { - // The magnitude argument of BigInteger constructor is a byte array in big-endian order. - // If ByteBuffer is read in little-endian, reverse the order of the bytes is required; - // if ByteBuffer is read in big-endian, then just keep it as-is. + /** + * Read U64/UBE64 type data from ByteBuffer and output a BigInteger instance. + * + * @param buf The byte buffer to read. + * @param type The annotation type. + * + * The magnitude argument of BigInteger constructor is a byte array in big-endian order. + * If BigInteger data is read from the byte buffer in little-endian, reverse the order of + * the bytes is required; if BigInteger data is read from the byte buffer in big-endian, + * then just keep it as-is. + */ + private static BigInteger readBigInteger(final ByteBuffer buf, final Type type) { final byte[] input = new byte[8]; + boolean reverseBytes = (type == Type.U64 && buf.order() == ByteOrder.LITTLE_ENDIAN); for (int i = 0; i < 8; i++) { - input[(buf.order() == ByteOrder.LITTLE_ENDIAN ? input.length - 1 - i : i)] = buf.get(); + input[reverseBytes ? input.length - 1 - i : i] = buf.get(); } return new BigInteger(1, input); } + /** + * Get the last 8 bytes of a byte array. If there are less than 8 bytes, + * the first bytes are replaced with zeroes. + */ + private static byte[] getLast8Bytes(final byte[] input) { + final byte[] tmp = new byte[8]; + System.arraycopy( + input, + Math.max(0, input.length - 8), // srcPos: read at most last 8 bytes + tmp, + Math.max(0, 8 - input.length), // dstPos: pad output with that many zeroes + Math.min(8, input.length)); // length + return tmp; + } + + /** + * Convert U64/UBE64 type data interpreted by BigInteger class to bytes array, output are + * always 8 bytes. + * + * @param bigInteger The number to convert. + * @param order Indicate ByteBuffer is read as little-endian or big-endian. + * @param type The annotation type. + * + * BigInteger#toByteArray returns a byte array containing the 2's complement representation + * of this BigInteger, in big-endian. If annotation type is U64 and ByteBuffer is read as + * little-endian, then reversing the order of the bytes is required. + */ + private static byte[] bigIntegerToU64Bytes(final BigInteger bigInteger, final ByteOrder order, + final Type type) { + final byte[] bigIntegerBytes = bigInteger.toByteArray(); + final byte[] output = getLast8Bytes(bigIntegerBytes); + + if (type == Type.U64 && order == ByteOrder.LITTLE_ENDIAN) { + for (int i = 0; i < 4; i++) { + byte tmp = output[i]; + output[i] = output[7 - i]; + output[7 - i] = tmp; + } + } + return output; + } + private static Object getFieldValue(final ByteBuffer buf, final FieldInfo fieldInfo) throws BufferUnderflowException { final Object value; - checkAnnotationType(fieldInfo.annotation.type(), fieldInfo.field.getType()); + checkAnnotationType(fieldInfo.annotation, fieldInfo.field.getType()); switch (fieldInfo.annotation.type()) { case U8: value = (short) (buf.get() & 0xFF); @@ -237,11 +329,7 @@ public class Struct { value = (long) (buf.getInt() & 0xFFFFFFFFL); break; case U64: - if (fieldInfo.field.getType() == BigInteger.class) { - value = readBigInteger(buf); - } else { - value = buf.getLong(); - } + value = readBigInteger(buf, Type.U64); break; case S8: value = buf.get(); @@ -252,34 +340,34 @@ public class Struct { case S32: value = buf.getInt(); break; + case U63: case S64: value = buf.getLong(); break; - case BE16: + case UBE16: if (buf.order() == ByteOrder.LITTLE_ENDIAN) { value = (int) (Short.reverseBytes(buf.getShort()) & 0xFFFF); } else { value = (int) (buf.getShort() & 0xFFFF); } break; - case BE32: + case UBE32: if (buf.order() == ByteOrder.LITTLE_ENDIAN) { value = (long) (Integer.reverseBytes(buf.getInt()) & 0xFFFFFFFFL); } else { value = (long) (buf.getInt() & 0xFFFFFFFFL); } break; - case BE64: - if (fieldInfo.field.getType() == BigInteger.class) { - value = readBigInteger(buf); + case UBE63: + if (buf.order() == ByteOrder.LITTLE_ENDIAN) { + value = Long.reverseBytes(buf.getLong()); } else { - if (buf.order() == ByteOrder.LITTLE_ENDIAN) { - value = Long.reverseBytes(buf.getLong()); - } else { - value = buf.getLong(); - } + value = buf.getLong(); } break; + case UBE64: + value = readBigInteger(buf, Type.UBE64); + break; case ByteArray: final byte[] array = new byte[fieldInfo.annotation.arraysize()]; buf.get(array); @@ -296,6 +384,72 @@ public class Struct { return value; } + private static void putFieldValue(final ByteBuffer output, final FieldInfo fieldInfo, + final Object value) throws BufferUnderflowException { + switch (fieldInfo.annotation.type()) { + case U8: + output.put((byte) (((short) value) & 0xFF)); + break; + case U16: + output.putShort((short) (((int) value) & 0xFFFF)); + break; + case U32: + output.putInt((int) (((long) value) & 0xFFFFFFFFL)); + break; + case U63: + output.putLong((long) value); + break; + case U64: + output.put(bigIntegerToU64Bytes((BigInteger) value, output.order(), Type.U64)); + break; + case S8: + output.put((byte) value); + break; + case S16: + output.putShort((short) value); + break; + case S32: + output.putInt((int) value); + break; + case S64: + output.putLong((long) value); + break; + case UBE16: + if (output.order() == ByteOrder.LITTLE_ENDIAN) { + output.putShort(Short.reverseBytes((short) (((int) value) & 0xFFFF))); + } else { + output.putShort((short) (((int) value) & 0xFFFF)); + } + break; + case UBE32: + if (output.order() == ByteOrder.LITTLE_ENDIAN) { + output.putInt(Integer.reverseBytes( + (int) (((long) value) & 0xFFFFFFFFL))); + } else { + output.putInt((int) (((long) value) & 0xFFFFFFFFL)); + } + break; + case UBE63: + if (output.order() == ByteOrder.LITTLE_ENDIAN) { + output.putLong(Long.reverseBytes((long) value)); + } else { + output.putLong((long) value); + } + break; + case UBE64: + output.put(bigIntegerToU64Bytes((BigInteger) value, output.order(), Type.UBE64)); + break; + case ByteArray: + output.put((byte[]) value); + break; + default: + throw new IllegalArgumentException("Unknown type:" + fieldInfo.annotation.type()); + } + + // padding zero after field value for alignment. + for (int i = 0; i < fieldInfo.annotation.padding(); i++) output.put((byte) 0); + } + private static FieldInfo[] getClassFieldInfo(final Class clazz) { if (!isStructSubclass(clazz)) { throw new IllegalArgumentException(clazz.getName() + " is not a subclass of " @@ -346,7 +500,7 @@ public class Struct { try { final FieldInfo[] foundFields = getClassFieldInfo(clazz); if (hasBothMutableAndImmutableFields(foundFields)) { - throw new IllegalArgumentException("Class has both immutable and mutable fields"); + throw new IllegalArgumentException("Class has both final and non-final fields"); } Constructor constructor = null; @@ -373,12 +527,62 @@ public class Struct { fi.field.set(instance, getFieldValue(buf, fi)); } return (T) instance; - } catch (IllegalAccessException - | InvocationTargetException - | InstantiationException e) { + } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { throw new IllegalArgumentException("Fail to create a instance from constructor", e); } catch (BufferUnderflowException e) { throw new IllegalArgumentException("Fail to read raw data from ByteBuffer", e); } } + + private static int getSizeInternal(final FieldInfo[] fieldInfos) { + int size = 0; + for (FieldInfo fi : fieldInfos) { + size += getFieldLength(fi.annotation); + } + return size; + } + + private void writeToByteBufferInternal(final ByteBuffer output, final FieldInfo[] fieldInfos) { + for (FieldInfo fi : fieldInfos) { + try { + putFieldValue(output, fi, fi.field.get(this)); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException("Fail to get the field value from instance", e); + } catch (BufferUnderflowException e) { + throw new IllegalArgumentException("Fail to fill raw data to ByteBuffer", e); + } + } + } + + /** + * Get the size of Struct subclass object. + */ + public static int getSize(final Class clazz) { + final FieldInfo[] fieldInfos = getClassFieldInfo(clazz); + return getSizeInternal(fieldInfos); + } + + /** + * Convert the parsed Struct subclass object to ByteBuffer. + * + * @param output ByteBuffer passed-in from the caller. + */ + public final void writeToByteBuffer(final ByteBuffer output) { + final FieldInfo[] fieldInfos = getClassFieldInfo(this.getClass()); + writeToByteBufferInternal(output, fieldInfos); + } + + /** + * Convert the parsed Struct subclass object to byte array. + * + * @param order indicate ByteBuffer is outputted as little-endian or big-endian. + */ + public final byte[] writeToBytes(final ByteOrder order) { + final FieldInfo[] fieldInfos = getClassFieldInfo(this.getClass()); + final byte[] output = new byte[getSizeInternal(fieldInfos)]; + final ByteBuffer buffer = ByteBuffer.wrap(output); + buffer.order(order); + writeToByteBufferInternal(buffer, fieldInfos); + return output; + } } diff --git a/staticlibs/tests/unit/src/android/net/util/StructTest.java b/staticlibs/tests/unit/src/android/net/util/StructTest.java index 5ca278ac2c..59c94b2beb 100644 --- a/staticlibs/tests/unit/src/android/net/util/StructTest.java +++ b/staticlibs/tests/unit/src/android/net/util/StructTest.java @@ -18,6 +18,7 @@ package android.net.util; import static com.android.testutils.MiscAsserts.assertThrows; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -35,6 +36,7 @@ import org.junit.runner.RunWith; import java.math.BigInteger; import java.net.InetAddress; +import java.nio.BufferOverflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; @@ -46,8 +48,8 @@ public class StructTest { // IPv6, 0 bytes of options, ifindex 15715755: 0x00efcdab, type 134 (RA), code 0, padding. private static final String HDR_EMPTY = "0a00" + "0000" + "abcdef00" + "8600000000000000"; - // BE16: 0xfeff, BE32: 0xfeffffff, BE64: 0xfffffffffffffffe, 0x7effffffffffffff - private static final String NETWORK_ORDER_MSG = "feff" + "feffffff" + "fffffffffffffffe" + // UBE16: 0xfeff, UBE32: 0xfeffffff, UBE64: 0xfeffffffffffffff, UBE63: 0x7effffffffffffff + private static final String NETWORK_ORDER_MSG = "feff" + "feffffff" + "feffffffffffffff" + "7effffffffffffff"; // S8: 0x7f, S16: 0x7fff, S32: 0x7fffffff, S64: 0x7fffffffffffffff @@ -65,9 +67,10 @@ public class StructTest { // PREF64 option, 2001:db8:3:4:5:6::/96, lifetime: 10064 private static final String OPT_PREF64 = "2750" + "20010db80003000400050006"; - private T doParsingMessageTest(final String hexString, Class clazz) { + private T doParsingMessageTest(final String hexString, final Class clazz, + final ByteOrder order) { final ByteBuffer buf = toByteBuffer(hexString); - buf.order(ByteOrder.LITTLE_ENDIAN); + buf.order(order); return Struct.parse(clazz, buf); } @@ -102,12 +105,16 @@ public class StructTest { assertEquals(15715755, msg.mIfindex); assertEquals(134, msg.mIcmpType); assertEquals(0, msg.mIcmpCode); + + assertEquals(16, Struct.getSize(HeaderMsgWithConstructor.class)); + assertArrayEquals(toByteBuffer(HDR_EMPTY).array(), + msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); } @Test public void testClassWithExplicitConstructor() { final HeaderMsgWithConstructor msg = doParsingMessageTest(HDR_EMPTY, - HeaderMsgWithConstructor.class); + HeaderMsgWithConstructor.class, ByteOrder.LITTLE_ENDIAN); verifyHeaderParsing(msg); } @@ -128,14 +135,18 @@ public class StructTest { } @Test - public void testClassWithDefaultConstrcutor() { + public void testClassWithDefaultConstructor() { final HeaderMsgWithoutConstructor msg = doParsingMessageTest(HDR_EMPTY, - HeaderMsgWithoutConstructor.class); + HeaderMsgWithoutConstructor.class, ByteOrder.LITTLE_ENDIAN); assertEquals(10, msg.mFamily); assertEquals(0, msg.mLen); assertEquals(15715755, msg.mIfindex); assertEquals(134, msg.mIcmpType); assertEquals(0, msg.mIcmpCode); + + assertEquals(16, Struct.getSize(HeaderMsgWithoutConstructor.class)); + assertArrayEquals(toByteBuffer(HDR_EMPTY).array(), + msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); } static class HeaderMessage { @@ -177,32 +188,36 @@ public class StructTest { } static class NetworkOrderMessage extends Struct { - @Field(order = 0, type = Type.BE16) - final int mBE16; - @Field(order = 1, type = Type.BE32) - final long mBE32; - @Field(order = 2, type = Type.BE64) - final BigInteger mBE64; - @Field(order = 3, type = Type.BE64) - final long mBE63; + @Field(order = 0, type = Type.UBE16) + final int mUBE16; + @Field(order = 1, type = Type.UBE32) + final long mUBE32; + @Field(order = 2, type = Type.UBE64) + final BigInteger mUBE64; + @Field(order = 3, type = Type.UBE63) + final long mUBE63; NetworkOrderMessage(final int be16, final long be32, final BigInteger be64, final long be63) { - mBE16 = be16; - mBE32 = be32; - mBE64 = be64; - mBE63 = be63; + mUBE16 = be16; + mUBE32 = be32; + mUBE64 = be64; + mUBE63 = be63; } } @Test public void testNetworkOrder() { final NetworkOrderMessage msg = doParsingMessageTest(NETWORK_ORDER_MSG, - NetworkOrderMessage.class); - assertEquals(65279, msg.mBE16); - assertEquals(4278190079L, msg.mBE32); - assertEquals(new BigInteger("18374686479671623679"), msg.mBE64); - assertEquals(9151314442816847871L, msg.mBE63); + NetworkOrderMessage.class, ByteOrder.LITTLE_ENDIAN); + assertEquals(65279, msg.mUBE16); + assertEquals(4278190079L, msg.mUBE32); + assertEquals(new BigInteger("18374686479671623679"), msg.mUBE64); + assertEquals(9151314442816847871L, msg.mUBE63); + + assertEquals(22, Struct.getSize(NetworkOrderMessage.class)); + assertArrayEquals(toByteBuffer(NETWORK_ORDER_MSG).array(), + msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); } static class UnsignedDataMessage extends Struct { @@ -213,11 +228,11 @@ public class StructTest { @Field(order = 2, type = Type.U32) final long mU32; @Field(order = 3, type = Type.U64) - final BigInteger mU64; // represent U64 with BigInteger. - @Field(order = 4, type = Type.U64) - final long mU63; // represent U63 with long primitive. - @Field(order = 5, type = Type.U64) - final long mLU64; // represent U64 with long primitive. + final BigInteger mU64; + @Field(order = 4, type = Type.U63) + final long mU63; + @Field(order = 5, type = Type.U63) + final long mLU64; // represent U64 data with U63 type UnsignedDataMessage(final short u8, final int u16, final long u32, final BigInteger u64, final long u63, final long lu64) { @@ -233,13 +248,57 @@ public class StructTest { @Test public void testUnsignedData() { final UnsignedDataMessage msg = doParsingMessageTest(UNSIGNED_DATA, - UnsignedDataMessage.class); + UnsignedDataMessage.class, ByteOrder.LITTLE_ENDIAN); assertEquals(255, msg.mU8); assertEquals(65535, msg.mU16); assertEquals(4294967295L, msg.mU32); assertEquals(new BigInteger("18446744073709551615"), msg.mU64); assertEquals(9223372036854775807L, msg.mU63); assertEquals(-1L, msg.mLU64); + + assertEquals(31, Struct.getSize(UnsignedDataMessage.class)); + assertArrayEquals(toByteBuffer(UNSIGNED_DATA).array(), + msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); + } + + static class U64DataMessage extends Struct { + @Field(order = 0, type = Type.U64) long mU64; + } + + @Test + public void testInvalidType_U64WithLongPrimitive() { + assertThrows(IllegalArgumentException.class, + () -> Struct.parse(U64DataMessage.class, toByteBuffer("ffffffffffffffff"))); + } + + // BigInteger U64: 0x0000000000001234, BigInteger UBE64: 0x0000000000001234, BigInteger U64: 0 + private static final String SMALL_VALUE_BIGINTEGER = "3412000000000000" + "0000000000001234" + + "0000000000000000"; + + static class SmallValueBigInteger extends Struct { + @Field(order = 0, type = Type.U64) final BigInteger mSmallValue; + @Field(order = 1, type = Type.UBE64) final BigInteger mBSmallValue; + @Field(order = 2, type = Type.U64) final BigInteger mZero; + + SmallValueBigInteger(final BigInteger smallValue, final BigInteger bSmallValue, + final BigInteger zero) { + mSmallValue = smallValue; + mBSmallValue = bSmallValue; + mZero = zero; + } + } + + @Test + public void testBigIntegerSmallValueOrZero() { + final SmallValueBigInteger msg = doParsingMessageTest(SMALL_VALUE_BIGINTEGER, + SmallValueBigInteger.class, ByteOrder.LITTLE_ENDIAN); + assertEquals(new BigInteger("4660"), msg.mSmallValue); + assertEquals(new BigInteger("4660"), msg.mBSmallValue); + assertEquals(new BigInteger("0"), msg.mZero); + + assertEquals(24, Struct.getSize(SmallValueBigInteger.class)); + assertArrayEquals(toByteBuffer(SMALL_VALUE_BIGINTEGER).array(), + msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); } static class SignedDataMessage extends Struct { @@ -262,21 +321,30 @@ public class StructTest { @Test public void testSignedPositiveData() { - final SignedDataMessage msg = doParsingMessageTest(SIGNED_DATA, SignedDataMessage.class); + final SignedDataMessage msg = doParsingMessageTest(SIGNED_DATA, SignedDataMessage.class, + ByteOrder.LITTLE_ENDIAN); assertEquals(127, msg.mS8); assertEquals(32767, msg.mS16); assertEquals(2147483647, msg.mS32); assertEquals(9223372036854775807L, msg.mS64); + + assertEquals(15, Struct.getSize(SignedDataMessage.class)); + assertArrayEquals(toByteBuffer(SIGNED_DATA).array(), + msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); } @Test public void testSignedNegativeData() { final SignedDataMessage msg = doParsingMessageTest(SIGNED_NEGATIVE_DATA, - SignedDataMessage.class); + SignedDataMessage.class, ByteOrder.LITTLE_ENDIAN); assertEquals(-127, msg.mS8); assertEquals(-32767, msg.mS16); assertEquals(-2147483647, msg.mS32); assertEquals(-9223372036854775807L, msg.mS64); + + assertEquals(15, Struct.getSize(SignedDataMessage.class)); + assertArrayEquals(toByteBuffer(SIGNED_NEGATIVE_DATA).array(), + msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); } static class HeaderMessageWithDuplicateOrder extends Struct { @@ -360,7 +428,7 @@ public class StructTest { } static class PrefixMessage extends Struct { - @Field(order = 0, type = Type.BE16) + @Field(order = 0, type = Type.UBE16) final int mLifetime; @Field(order = 1, type = Type.ByteArray, arraysize = 12) final byte[] mPrefix; @@ -379,11 +447,35 @@ public class StructTest { final IpPrefix prefix = new IpPrefix(addr, 96); assertEquals(10064, msg.mLifetime); assertTrue(prefix.equals(new IpPrefix("2001:db8:3:4:5:6::/96"))); + + assertEquals(14, Struct.getSize(PrefixMessage.class)); + assertArrayEquals(toByteBuffer(OPT_PREF64).array(), + msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); + } + + static class PrefixMessageWithZeroLengthArray extends Struct { + @Field(order = 0, type = Type.UBE16) + final int mLifetime; + @Field(order = 1, type = Type.ByteArray, arraysize = 0) + final byte[] mPrefix; + + PrefixMessageWithZeroLengthArray(final int lifetime, final byte[] prefix) { + mLifetime = lifetime; + mPrefix = prefix; + } + } + + @Test + public void testInvalidClass_ZeroLengthByteArray() { + final ByteBuffer buf = toByteBuffer(OPT_PREF64); + assertThrows(IllegalArgumentException.class, + () -> Struct.parse(PrefixMessageWithZeroLengthArray.class, buf)); } @Test public void testPrefixArrayField() throws Exception { - final PrefixMessage msg = doParsingMessageTest(OPT_PREF64, PrefixMessage.class); + final PrefixMessage msg = doParsingMessageTest(OPT_PREF64, PrefixMessage.class, + ByteOrder.LITTLE_ENDIAN); verifyPrefixByteArrayParsing(msg); } @@ -441,12 +533,16 @@ public class StructTest { @Test public void testStaticConstantField() { final HeaderMsgWithStaticConstant msg = doParsingMessageTest(HDR_EMPTY, - HeaderMsgWithStaticConstant.class); + HeaderMsgWithStaticConstant.class, ByteOrder.LITTLE_ENDIAN); assertEquals(10, msg.mFamily); assertEquals(0, msg.mLen); assertEquals(15715755, msg.mIfindex); assertEquals(134, msg.mIcmpType); assertEquals(0, msg.mIcmpCode); + + assertEquals(16, Struct.getSize(HeaderMsgWithStaticConstant.class)); + assertArrayEquals(toByteBuffer(HDR_EMPTY).array(), + msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); } static class MismatchedConstructor extends Struct { @@ -481,23 +577,89 @@ public class StructTest { @Test public void testClassWithTwoConstructors() { final ClassWithTwoConstructors msg = doParsingMessageTest("1234" + "5678", - ClassWithTwoConstructors.class); + ClassWithTwoConstructors.class, ByteOrder.LITTLE_ENDIAN); assertEquals(13330 /* 0x3412 */, msg.mInt1); assertEquals(30806 /* 0x7856 */, msg.mInt2); + + assertEquals(4, Struct.getSize(ClassWithTwoConstructors.class)); + assertArrayEquals(toByteBuffer("1234" + "5678").array(), + msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); + } + + @Test + public void testInvalidOutputByteBuffer_ZeroCapacity() { + final ByteBuffer output = ByteBuffer.allocate(0); + output.order(ByteOrder.LITTLE_ENDIAN); + final HeaderMsgWithConstructor msg = doParsingMessageTest(HDR_EMPTY, + HeaderMsgWithConstructor.class, ByteOrder.LITTLE_ENDIAN); + assertThrows(BufferOverflowException.class, () -> msg.writeToByteBuffer(output)); + } + + @Test + public void testConsecutiveWrites() { + final HeaderMsgWithConstructor msg1 = doParsingMessageTest(HDR_EMPTY, + HeaderMsgWithConstructor.class, ByteOrder.LITTLE_ENDIAN); + final PrefixMessage msg2 = doParsingMessageTest(OPT_PREF64, PrefixMessage.class, + ByteOrder.LITTLE_ENDIAN); + + int size = Struct.getSize(HeaderMsgWithConstructor.class) + + Struct.getSize(PrefixMessage.class); + final ByteBuffer output = ByteBuffer.allocate(size); + output.order(ByteOrder.LITTLE_ENDIAN); + + msg1.writeToByteBuffer(output); + msg2.writeToByteBuffer(output); + output.flip(); + + final ByteBuffer concat = ByteBuffer.allocate(size).put(toByteBuffer(HDR_EMPTY)) + .put(toByteBuffer(OPT_PREF64)); + assertArrayEquals(output.array(), concat.array()); } @Test public void testClassesParsedFromCache() throws Exception { for (int i = 0; i < 100; i++) { - final HeaderMsgWithConstructor msg1 = - doParsingMessageTest(HDR_EMPTY, HeaderMsgWithConstructor.class); + final HeaderMsgWithConstructor msg1 = doParsingMessageTest(HDR_EMPTY, + HeaderMsgWithConstructor.class, ByteOrder.LITTLE_ENDIAN); verifyHeaderParsing(msg1); - final PrefixMessage msg2 = doParsingMessageTest(OPT_PREF64, PrefixMessage.class); + final PrefixMessage msg2 = doParsingMessageTest(OPT_PREF64, PrefixMessage.class, + ByteOrder.LITTLE_ENDIAN); verifyPrefixByteArrayParsing(msg2); } } + static class BigEndianDataMessage extends Struct { + @Field(order = 0, type = Type.S32) int mInt1; + @Field(order = 1, type = Type.S32) int mInt2; + @Field(order = 2, type = Type.UBE16) int mInt3; + @Field(order = 3, type = Type.U16) int mInt4; + @Field(order = 4, type = Type.U64) BigInteger mBigInteger1; + @Field(order = 5, type = Type.UBE64) BigInteger mBigInteger2; + @Field(order = 6, type = Type.S64) long mLong; + } + + private static final String BIG_ENDIAN_DATA = "00000001" + "fffffffe" + "fffe" + "fffe" + + "ff00004500002301" + "ff00004500002301" + "ff00004500002301"; + + @Test + public void testBigEndianByteBuffer() { + final BigEndianDataMessage msg = doParsingMessageTest(BIG_ENDIAN_DATA, + BigEndianDataMessage.class, ByteOrder.BIG_ENDIAN); + + assertEquals(1, msg.mInt1); + assertEquals(-2, msg.mInt2); + assertEquals(65534, msg.mInt3); + assertEquals(65534, msg.mInt4); + assertEquals(new BigInteger("18374686776024376065"), msg.mBigInteger1); + assertEquals(new BigInteger("18374686776024376065"), msg.mBigInteger2); + assertEquals(0xff00004500002301L, msg.mLong); + + assertEquals(36, Struct.getSize(BigEndianDataMessage.class)); + assertArrayEquals(toByteBuffer(BIG_ENDIAN_DATA).array(), + msg.writeToBytes(ByteOrder.BIG_ENDIAN)); + } + private ByteBuffer toByteBuffer(final String hexString) { return ByteBuffer.wrap(HexDump.hexStringToByteArray(hexString)); } From 4ec55ea0076b70f27e1d898b1d606f8d290f10e1 Mon Sep 17 00:00:00 2001 From: Orion Hodson Date: Tue, 8 Dec 2020 09:52:06 +0000 Subject: [PATCH 081/777] Share JNI file descriptor helper code Move JNI File descriptor code from NetworkStack into a common native static library. Bug: 158749603 Test: atest NetworkStaticLibTests / treehugger Change-Id: I3d14587ee8e8590b727736d7d2e29cba687e5514 --- staticlibs/native/netjniutils/Android.bp | 34 ++++++ .../include/netjniutils/netjniutils.h | 25 +++++ staticlibs/native/netjniutils/netjniutils.cpp | 104 ++++++++++++++++++ 3 files changed, 163 insertions(+) create mode 100644 staticlibs/native/netjniutils/Android.bp create mode 100644 staticlibs/native/netjniutils/include/netjniutils/netjniutils.h create mode 100644 staticlibs/native/netjniutils/netjniutils.cpp diff --git a/staticlibs/native/netjniutils/Android.bp b/staticlibs/native/netjniutils/Android.bp new file mode 100644 index 0000000000..8417c52327 --- /dev/null +++ b/staticlibs/native/netjniutils/Android.bp @@ -0,0 +1,34 @@ +// Copyright (C) 2020 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. + +cc_library_static { + name: "libnetjniutils", + srcs: ["netjniutils.cpp"], + header_libs: ["jni_headers"], + shared_libs: ["liblog"], + export_header_lib_headers: ["jni_headers"], + export_include_dirs: ["include"], + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + ], + sdk_version: "29", + min_sdk_version: "29", + apex_available: [ + "//apex_available:anyapex", + "//apex_available:platform", + ], + visibility: ["//visibility:public"], +} diff --git a/staticlibs/native/netjniutils/include/netjniutils/netjniutils.h b/staticlibs/native/netjniutils/include/netjniutils/netjniutils.h new file mode 100644 index 0000000000..1b2b035daa --- /dev/null +++ b/staticlibs/native/netjniutils/include/netjniutils/netjniutils.h @@ -0,0 +1,25 @@ +// Copyright (C) 2020 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. + +#pragma once + +#include + +namespace android { +namespace netjniutils { + +int GetNativeFileDescriptor(JNIEnv* env, jobject javaFd); + +} // namespace netjniutils +} // namepsace android diff --git a/staticlibs/native/netjniutils/netjniutils.cpp b/staticlibs/native/netjniutils/netjniutils.cpp new file mode 100644 index 0000000000..8ed72b087c --- /dev/null +++ b/staticlibs/native/netjniutils/netjniutils.cpp @@ -0,0 +1,104 @@ +// Copyright (C) 2020 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. + +#define LOG_TAG "netjniutils" + +#include "netjniutils/netjniutils.h" + +#include +#include +#include +#include + +#include +#include + +namespace android { +namespace netjniutils { + +namespace { + +bool IsAtLeastS() { + // TODO(b/158749603#comment19): move to android::modules::sdklevel::IsAtLeastS(). + int api_level = android_get_device_api_level(); + + // Guarded check for branches that do not have __ANDROID_API_S__. +#ifdef __ANDROID_API_S__ + if (api_level >= __ANDROID_API_S__) { + return true; + } +#endif + + if (api_level < __ANDROID_API_R__) { + return false; + } + + // Device looks like R or above, check codename as it could be (S or above). + static constexpr const char* kCodenameProperty = "ro.build.version.codename"; + char codename[PROP_VALUE_MAX] = { 0 }; + return (__system_property_get(kCodenameProperty, codename) > 0 && + codename[0] >= 'S' && codename[1] == '\0'); +} + +int GetNativeFileDescriptorWithoutNdk(JNIEnv* env, jobject javaFd) { + // Prior to Android S, we need to find the descriptor field in the FileDescriptor class. The + // symbol name has been stable in libcore, but is a private implementation detail. + // Older libnativehelper_compat_c++ versions had a jniGetFdFromFileDescriptor method, but this + // was removed in S to replace it with the NDK API in libnativehelper. + // The code is copied here instead. This code can be removed once R is not supported anymore. + static const jfieldID descriptorFieldID = [env]() -> jfieldID { + jclass cls = env->FindClass("java/io/FileDescriptor"); + jfieldID fieldID = env->GetFieldID(cls, "descriptor", "I"); + env->DeleteLocalRef(cls); + if (fieldID == nullptr) { + __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, "Failed to get descriptor field."); + } + return fieldID; + }(); + + return javaFd != nullptr ? env->GetIntField(javaFd, descriptorFieldID) : -1; +} + +int GetNativeFileDescriptorWithNdk(JNIEnv* env, jobject javaFd) { + // Since Android S, there is an NDK API to get a file descriptor present in libnativehelper.so. + // libnativehelper is loaded into all processes by the zygote since the zygote uses it + // to load the Android Runtime and is also a public library (because of the NDK API). + typedef int (*ndkGetFD_t)(JNIEnv*, jobject); + static const ndkGetFD_t ndkGetFD = []() -> ndkGetFD_t { + void* handle = dlopen("libnativehelper.so", RTLD_NOLOAD | RTLD_NODELETE); + auto ndkGetFD = reinterpret_cast(dlsym(handle, "AFileDescriptor_getFD")); + if (ndkGetFD == nullptr) { + __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, + "Failed to dlsym(AFileDescriptor_getFD): %s", dlerror()); + dlclose(handle); + } + return ndkGetFD; + }(); + + return javaFd != nullptr ? ndkGetFD(env, javaFd) : -1; +} + +} // namespace + +int GetNativeFileDescriptor(JNIEnv* env, jobject javaFd) { + static const bool preferNdkFileDescriptorApi = []() -> bool { return IsAtLeastS(); }(); + if (preferNdkFileDescriptorApi) { + return GetNativeFileDescriptorWithNdk(env, javaFd); + } else { + return GetNativeFileDescriptorWithoutNdk(env, javaFd); + } +} + +} // namespace netjniutils +} // namespace android From a726723ffb133c8124beed843ddb88013af50d8c Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 18 Nov 2020 01:36:17 +0900 Subject: [PATCH 082/777] Add logging to TestableNetworkCallback. This is not super useful because it cannot identify different NetworkCallback objects from each other, but I've found it to be better than nothing. Test: manual Change-Id: Ib402161f361c0f9fb68701bf171cbc99f598dafd --- .../com/android/testutils/TestableNetworkCallback.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt index 7cd5419b73..043654f4bd 100644 --- a/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -21,6 +21,7 @@ import android.net.LinkProperties import android.net.Network import android.net.NetworkCapabilities import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED +import android.util.Log import com.android.net.module.util.ArrayTrackRecord import com.android.testutils.RecorderCallback.CallbackEntry.Available import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatus @@ -48,6 +49,8 @@ open class RecorderCallback private constructor( public constructor() : this(ArrayTrackRecord()) protected constructor(src: RecorderCallback?): this(src?.backingRecord ?: ArrayTrackRecord()) + private val TAG = this::class.simpleName + sealed class CallbackEntry { // To get equals(), hashcode(), componentN() etc for free, the child classes of // this class are data classes. But while data classes can inherit from other classes, @@ -114,34 +117,42 @@ open class RecorderCallback private constructor( // expect the callbacks not to record this, do not listen to PreCheck here. override fun onCapabilitiesChanged(network: Network, caps: NetworkCapabilities) { + Log.d(TAG, "onCapabilitiesChanged $network $caps") history.add(CapabilitiesChanged(network, caps)) } override fun onLinkPropertiesChanged(network: Network, lp: LinkProperties) { + Log.d(TAG, "onLinkPropertiesChanged $network $lp") history.add(LinkPropertiesChanged(network, lp)) } override fun onBlockedStatusChanged(network: Network, blocked: Boolean) { + Log.d(TAG, "onBlockedStatusChanged $network $blocked") history.add(BlockedStatus(network, blocked)) } override fun onNetworkSuspended(network: Network) { + Log.d(TAG, "onNetworkSuspended $network $network") history.add(Suspended(network)) } override fun onNetworkResumed(network: Network) { + Log.d(TAG, "$network onNetworkResumed $network") history.add(Resumed(network)) } override fun onLosing(network: Network, maxMsToLive: Int) { + Log.d(TAG, "onLosing $network $maxMsToLive") history.add(Losing(network, maxMsToLive)) } override fun onLost(network: Network) { + Log.d(TAG, "onLost $network") history.add(Lost(network)) } override fun onUnavailable() { + Log.d(TAG, "onUnavailable") history.add(Unavailable()) } } From ceaf7d0edc61f324f0237314bcfdd127ad056834 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 26 Jun 2020 18:34:52 +0900 Subject: [PATCH 083/777] Move util classes to their destination package Test: FrameworksWifiTests FrameworksNetTests Change-Id: I93e9cfd968e08f983e3fd9f7196c455c79a0f32d Merged-In: Id19c650246a8f3d55d7b6a874840a6eebcd9eb17 --- staticlibs/Android.bp | 5 ++--- .../android/net/module}/util/FdEventsReader.java | 9 ++++----- .../android/net/module}/util/PacketReader.java | 3 +-- .../com/android/testutils/TapPacketReader.java | 2 +- .../android/net/module/util}/DnsSdTxtRecord.java | 2 +- .../net => com/android/net/module}/util/IpRange.java | 2 +- .../android/net/module}/util/LinkPropertiesUtils.java | 2 +- .../android/net/module}/util/MacAddressUtils.java | 2 +- .../net => com/android/net/module}/util/NetUtils.java | 2 +- staticlibs/jarjar-rules-shared.txt | 6 ------ staticlibs/tests/unit/Android.bp | 1 - staticlibs/tests/unit/AndroidManifest.xml | 2 ++ staticlibs/tests/unit/jarjar-rules-sharedlib.txt | 6 ------ .../tests/unit/src/android/net/util/IpRangeTest.java | 2 ++ .../src/android/net/util/LinkPropertiesUtilsTest.java | 6 ++++-- .../unit/src/android/net/util/MacAddressUtilsTest.java | 2 ++ .../tests/unit/src/android/net/util/NetUtilsTest.java | 2 ++ .../com/android/net/module/util/PacketReaderTest.java | 7 ++----- 18 files changed, 27 insertions(+), 36 deletions(-) rename staticlibs/device/{android/net => com/android/net/module}/util/FdEventsReader.java (98%) rename staticlibs/device/{android/net => com/android/net/module}/util/PacketReader.java (94%) rename staticlibs/framework/{android/net/util/nsd => com/android/net/module/util}/DnsSdTxtRecord.java (99%) rename staticlibs/framework/{android/net => com/android/net/module}/util/IpRange.java (99%) rename staticlibs/framework/{android/net => com/android/net/module}/util/LinkPropertiesUtils.java (99%) rename staticlibs/framework/{android/net => com/android/net/module}/util/MacAddressUtils.java (99%) rename staticlibs/framework/{android/net => com/android/net/module}/util/NetUtils.java (98%) delete mode 100644 staticlibs/tests/unit/jarjar-rules-sharedlib.txt diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index a1a998eb60..76aceda81c 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -124,6 +124,7 @@ java_library { jarjar_rules: "jarjar-rules-shared.txt", visibility: [ "//cts/tests/tests/net", + "//cts/tests/tests/wifi", "//packages/modules/Connectivity/tests/cts/net", "//frameworks/base/packages/Tethering", "//packages/modules/Connectivity/Tethering", @@ -179,8 +180,6 @@ filegroup { filegroup { name: "net-utils-framework-wifi-common-srcs", srcs: [ - "framework/android/net/util/nsd/DnsSdTxtRecord.java", - "framework/android/net/util/MacAddressUtils.java", "framework/com/android/net/module/util/**/*.java", ], path: "framework", @@ -196,7 +195,7 @@ filegroup { name: "net-utils-wifi-service-common-srcs", srcs: [ "device/android/net/NetworkFactory.java", - "framework/android/net/util/NetUtils.java", + "framework/com/android/net/module/util/NetUtils.java", ], visibility: [ "//frameworks/opt/net/wifi/service", diff --git a/staticlibs/device/android/net/util/FdEventsReader.java b/staticlibs/device/com/android/net/module/util/FdEventsReader.java similarity index 98% rename from staticlibs/device/android/net/util/FdEventsReader.java rename to staticlibs/device/com/android/net/module/util/FdEventsReader.java index a5714aa5db..71ae13d80d 100644 --- a/staticlibs/device/android/net/util/FdEventsReader.java +++ b/staticlibs/device/com/android/net/module/util/FdEventsReader.java @@ -14,12 +14,14 @@ * limitations under the License. */ -// TODO : move this and PacketReader to com.android.net.module.util. -package android.net.util; +package com.android.net.module.util; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.util.SocketUtils; import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; @@ -27,9 +29,6 @@ import android.system.ErrnoException; import android.system.OsConstants; import android.util.Log; -import android.annotation.NonNull; -import android.annotation.Nullable; - import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; diff --git a/staticlibs/device/android/net/util/PacketReader.java b/staticlibs/device/com/android/net/module/util/PacketReader.java similarity index 94% rename from staticlibs/device/android/net/util/PacketReader.java rename to staticlibs/device/com/android/net/module/util/PacketReader.java index 61b3d6e294..66c47888c3 100644 --- a/staticlibs/device/android/net/util/PacketReader.java +++ b/staticlibs/device/com/android/net/module/util/PacketReader.java @@ -14,8 +14,7 @@ * limitations under the License. */ -// TODO : move this and FdEventsReader to com.android.net.module.util. -package android.net.util; +package com.android.net.module.util; import static java.lang.Math.max; diff --git a/staticlibs/devicetests/com/android/testutils/TapPacketReader.java b/staticlibs/devicetests/com/android/testutils/TapPacketReader.java index 001b709903..b25b9f214b 100644 --- a/staticlibs/devicetests/com/android/testutils/TapPacketReader.java +++ b/staticlibs/devicetests/com/android/testutils/TapPacketReader.java @@ -16,13 +16,13 @@ package com.android.testutils; -import android.net.util.PacketReader; import android.os.Handler; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.net.module.util.ArrayTrackRecord; +import com.android.net.module.util.PacketReader; import java.io.FileDescriptor; import java.io.FileOutputStream; diff --git a/staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java b/staticlibs/framework/com/android/net/module/util/DnsSdTxtRecord.java similarity index 99% rename from staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java rename to staticlibs/framework/com/android/net/module/util/DnsSdTxtRecord.java index 81768f7ed1..760891b9fc 100644 --- a/staticlibs/framework/android/net/util/nsd/DnsSdTxtRecord.java +++ b/staticlibs/framework/com/android/net/module/util/DnsSdTxtRecord.java @@ -19,7 +19,7 @@ - fix set() to replace existing values */ -package android.net.util.nsd; +package com.android.net.module.util; import android.os.Parcelable; import android.os.Parcel; diff --git a/staticlibs/framework/android/net/util/IpRange.java b/staticlibs/framework/com/android/net/module/util/IpRange.java similarity index 99% rename from staticlibs/framework/android/net/util/IpRange.java rename to staticlibs/framework/com/android/net/module/util/IpRange.java index 099770bca4..40b57b10f0 100644 --- a/staticlibs/framework/android/net/util/IpRange.java +++ b/staticlibs/framework/com/android/net/module/util/IpRange.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import static com.android.internal.annotations.VisibleForTesting.Visibility; diff --git a/staticlibs/framework/android/net/util/LinkPropertiesUtils.java b/staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java similarity index 99% rename from staticlibs/framework/android/net/util/LinkPropertiesUtils.java rename to staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java index 282fa10d2b..1565f2bc2f 100644 --- a/staticlibs/framework/android/net/util/LinkPropertiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/staticlibs/framework/android/net/util/MacAddressUtils.java b/staticlibs/framework/com/android/net/module/util/MacAddressUtils.java similarity index 99% rename from staticlibs/framework/android/net/util/MacAddressUtils.java rename to staticlibs/framework/com/android/net/module/util/MacAddressUtils.java index 969d1270be..bc11fa2a7c 100644 --- a/staticlibs/framework/android/net/util/MacAddressUtils.java +++ b/staticlibs/framework/com/android/net/module/util/MacAddressUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/staticlibs/framework/android/net/util/NetUtils.java b/staticlibs/framework/com/android/net/module/util/NetUtils.java similarity index 98% rename from staticlibs/framework/android/net/util/NetUtils.java rename to staticlibs/framework/com/android/net/module/util/NetUtils.java index 302119ea11..4331b65de0 100644 --- a/staticlibs/framework/android/net/util/NetUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/staticlibs/jarjar-rules-shared.txt b/staticlibs/jarjar-rules-shared.txt index 9e618db19b..a7fda7c0ac 100644 --- a/staticlibs/jarjar-rules-shared.txt +++ b/staticlibs/jarjar-rules-shared.txt @@ -1,8 +1,2 @@ -# TODO: move the classes to the target package in java -rule android.net.util.IpRange* com.android.net.module.util.IpRange@1 -rule android.net.util.MacAddressUtils* com.android.net.module.util.MacAddressUtils@1 -rule android.net.util.LinkPropertiesUtils* com.android.net.module.util.LinkPropertiesUtils@1 -rule android.net.util.NetUtils* com.android.net.module.util.NetUtils@1 -rule android.net.util.nsd.** com.android.net.module.util.nsd.@1 rule android.annotation.** com.android.net.module.annotation.@1 rule com.android.internal.annotations.** com.android.net.module.annotation.@1 diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index c20b87db29..537340ef78 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -16,7 +16,6 @@ android_library { "android.test.runner", "android.test.base", ], - jarjar_rules: "jarjar-rules-sharedlib.txt", visibility: [ "//frameworks/base/packages/Tethering/tests/integration", "//packages/modules/Connectivity/Tethering/tests/integration", diff --git a/staticlibs/tests/unit/AndroidManifest.xml b/staticlibs/tests/unit/AndroidManifest.xml index cc9e09ea76..c747c8a585 100644 --- a/staticlibs/tests/unit/AndroidManifest.xml +++ b/staticlibs/tests/unit/AndroidManifest.xml @@ -17,6 +17,8 @@ + + diff --git a/staticlibs/tests/unit/jarjar-rules-sharedlib.txt b/staticlibs/tests/unit/jarjar-rules-sharedlib.txt deleted file mode 100644 index fceccfb755..0000000000 --- a/staticlibs/tests/unit/jarjar-rules-sharedlib.txt +++ /dev/null @@ -1,6 +0,0 @@ -# TODO: move the classes to the target package in java -rule android.net.util.IpRange* com.android.net.module.util.IpRange@1 -rule android.net.util.MacAddressUtils* com.android.net.module.util.MacAddressUtils@1 -rule android.net.util.LinkPropertiesUtils* com.android.net.module.util.LinkPropertiesUtils@1 -rule android.net.util.NetUtils* com.android.net.module.util.NetUtils@1 -rule android.net.util.nsd.** com.android.net.module.util.nsd.@1 diff --git a/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java b/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java index f4d07e9b3e..677db6956f 100644 --- a/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java +++ b/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java @@ -28,6 +28,8 @@ import android.net.IpPrefix; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.IpRange; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java index 2142090bc6..e47c864350 100644 --- a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java @@ -26,12 +26,14 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.ProxyInfo; import android.net.RouteInfo; -import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult; -import android.net.util.LinkPropertiesUtils.CompareResult; import android.util.ArraySet; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.LinkPropertiesUtils; +import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult; +import com.android.net.module.util.LinkPropertiesUtils.CompareResult; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java index ad63b3c9eb..66d89ffd1d 100644 --- a/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java @@ -24,6 +24,8 @@ import android.net.MacAddress; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.MacAddressUtils; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java index 903e80d369..338d1c80fe 100644 --- a/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java @@ -27,6 +27,8 @@ import android.net.RouteInfo; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.NetUtils; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java index 046a1d9d15..459801c272 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PacketReaderTest.java @@ -16,7 +16,6 @@ package com.android.net.module.util; -import static android.net.util.PacketReader.DEFAULT_RECV_BUF_SIZE; import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; @@ -24,14 +23,13 @@ import static android.system.OsConstants.SOCK_NONBLOCK; import static android.system.OsConstants.SOL_SOCKET; import static android.system.OsConstants.SO_SNDTIMEO; +import static com.android.net.module.util.PacketReader.DEFAULT_RECV_BUF_SIZE; import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import android.net.util.PacketReader; import android.os.Handler; import android.os.HandlerThread; import android.system.ErrnoException; @@ -93,8 +91,7 @@ public class PacketReaderTest { Os.setsockoptTimeval(s, SOL_SOCKET, SO_SNDTIMEO, TIMEO); } catch (ErrnoException | SocketException e) { closeFd(s); - fail(); - return null; + throw new RuntimeException("Failed to create FD", e); } mLocalSocket = s; From ce033d48246d0928d886c8df34c36666505a7d16 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 17 Dec 2020 15:31:21 +0000 Subject: [PATCH 084/777] Move Struct.java to com.android.net.module.util package. Bug: 163492391 Test: atest NetworkStaticLibTests Change-Id: If7d54f0356ce4d6426011914df0a2e85784daebd --- .../net => com/android/net/module}/util/Struct.java | 4 ++-- .../net => com/android/net/module}/util/StructTest.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename staticlibs/device/{android/net => com/android/net/module}/util/Struct.java (99%) rename staticlibs/tests/unit/src/{android/net => com/android/net/module}/util/StructTest.java (99%) diff --git a/staticlibs/device/android/net/util/Struct.java b/staticlibs/device/com/android/net/module/util/Struct.java similarity index 99% rename from staticlibs/device/android/net/util/Struct.java rename to staticlibs/device/com/android/net/module/util/Struct.java index 841829e502..bc8761a004 100644 --- a/staticlibs/device/android/net/util/Struct.java +++ b/staticlibs/device/com/android/net/module/util/Struct.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import android.annotation.NonNull; @@ -293,7 +293,7 @@ public class Struct { * * @param bigInteger The number to convert. * @param order Indicate ByteBuffer is read as little-endian or big-endian. - * @param type The annotation type. + * @param type The annotation U64 type. * * BigInteger#toByteArray returns a byte array containing the 2's complement representation * of this BigInteger, in big-endian. If annotation type is U64 and ByteBuffer is read as diff --git a/staticlibs/tests/unit/src/android/net/util/StructTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java similarity index 99% rename from staticlibs/tests/unit/src/android/net/util/StructTest.java rename to staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java index 59c94b2beb..1b03e75016 100644 --- a/staticlibs/tests/unit/src/android/net/util/StructTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import static com.android.testutils.MiscAsserts.assertThrows; @@ -23,13 +23,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.net.IpPrefix; -import android.net.util.Struct.Field; -import android.net.util.Struct.Type; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.HexDump; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; import org.junit.Test; import org.junit.runner.RunWith; From 460e78931af08eb4f8cab0153329e52ad5cf89a6 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Sun, 13 Dec 2020 22:47:55 +0900 Subject: [PATCH 085/777] Make Readhead more usable in multithread. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There doesn't seem to be a way to get any code at all to run in a generic way on the thread that will execute a test in android JUnit. JUnit can do it, but the android harness imposes a thread hop. This is inconvenent with ReadHead, because ReadHead can't be used in multithread for semantic reasons : it would make no sense at all. ReadHead enforces this today in a relatively strong fashion. But technically, the only guarantee that is needed is that poll() is executed only on one thread in slabs of time defined between a read barrier and a write barrier, where the write barrier of the previous slab happen-before the read barrier of the next slab. This in generally speaking a bit difficult to achieve, but the tests run satisfy this condition by starting the thread after executing the @Before methods and joining it before executing the @After methods. So in fact, it's safe to use ReadHead during the befores and afters, if a bit uncomfortable, as long as only one thread uses it during the before, one thread during the test, and one thread during the afters. This patch relaxes the enforcement on ReadHead to accept the usage above. If any slab of time contains usage of poll() on multiple threads, this will instead crash with ConcurrentModificationException in almost all cases. It's no longer possible to detect every possible misuse of poll() under these conditions, but with this code it's going to be very unlikely at each test run that the code is incorrect and still doesn't crash, so incorrect use should still cause at least very severe flakiness. The main drawback, aside from the very slight performance penalty, is that some use can be accidentally correct and this code will now accept it. So it's possible that code that is only accidentally correct is accepted, and a seemingly unrelated change later breaks that correctness, causing seemingly unrelated tests to fail. Still, this is going to be an improvement in usability of ReadHead. We'll no longer need to have lazy creation of it, and it will be possible to check remaining events after a tests runs. Test: FrameworksNetTests NetworkStackTests Change-Id: If87eef1686b235e53cb444a32f9985b4c2a0a901 --- .../android/net/module/util/TrackRecord.kt | 106 ++++++++++++------ 1 file changed, 73 insertions(+), 33 deletions(-) diff --git a/staticlibs/hostdevice/com/android/net/module/util/TrackRecord.kt b/staticlibs/hostdevice/com/android/net/module/util/TrackRecord.kt index b647d991fd..efd77d1b3b 100644 --- a/staticlibs/hostdevice/com/android/net/module/util/TrackRecord.kt +++ b/staticlibs/hostdevice/com/android/net/module/util/TrackRecord.kt @@ -19,6 +19,7 @@ package com.android.net.module.util import java.util.concurrent.TimeUnit import java.util.concurrent.locks.Condition import java.util.concurrent.locks.ReentrantLock +import java.util.concurrent.locks.StampedLock import kotlin.concurrent.withLock /** @@ -137,12 +138,6 @@ class ArrayTrackRecord : TrackRecord { * instance can also be used concurrently. ReadHead maintains the current index that is * the next to be read, and calls this the "mark". * - * A ReadHead delegates all TrackRecord methods to its associated ArrayTrackRecord, and - * inherits its thread-safe properties. However, the additional methods that ReadHead - * offers on top of TrackRecord do not share these properties and can only be used by - * the thread that created the ReadHead. This is because by construction it does not - * make sense to use a ReadHead on multiple threads concurrently (see below for details). - * * In a ReadHead, {@link poll(Long, (E) -> Boolean)} works similarly to a LinkedBlockingQueue. * It can be called repeatedly and will return the elements as they arrive. * @@ -162,21 +157,43 @@ class ArrayTrackRecord : TrackRecord { * The point is that the caller does not have to track the mark like it would have to if * it was using ArrayTrackRecord directly. * - * Note that if multiple threads were using poll() concurrently on the same ReadHead, what - * happens to the mark and the return values could be well defined, but it could not - * be useful because there is no way to provide either a guarantee not to skip objects nor - * a guarantee about the mark position at the exit of poll(). This is even more true in the - * presence of a predicate to filter returned elements, because one thread might be - * filtering out the events the other is interested in. - * Instead, this use case is supported by creating multiple ReadHeads on the same instance - * of ArrayTrackRecord. Each ReadHead is then guaranteed to see all events always and - * guarantees are made on the value of the mark upon return. {@see poll(Long, (E) -> Boolean)} - * for details. Be careful to create each ReadHead on the thread it is meant to be used on. + * Thread safety : + * A ReadHead delegates all TrackRecord methods to its associated ArrayTrackRecord, and + * inherits its thread-safe properties for all the TrackRecord methods. * - * Users of a ReadHead can ask for the current position of the mark at any time. This mark - * can be used later to replay the history of events either on this ReadHead, on the associated - * ArrayTrackRecord or on another ReadHead associated with the same ArrayTrackRecord. It - * might look like this in the reader thread : + * Poll() operates under its own set of rules that only allow execution on multiple threads + * within constrained boundaries, and never concurrently or pseudo-concurrently. This is + * because concurrent calls to poll() fundamentally do not make sense. poll() will move + * the mark according to what events remained to be read by this read head, and therefore + * if multiple threads were calling poll() concurrently on the same ReadHead, what + * happens to the mark and the return values could not be useful because there is no way to + * provide either a guarantee not to skip objects nor a guarantee about the mark position at + * the exit of poll(). This is even more true in the presence of a predicate to filter + * returned elements, because one thread might be filtering out the events the other is + * interested in. For this reason, this class will fail-fast if any concurrent access is + * detected with ConcurrentAccessException. + * It is possible to use poll() on different threads as long as the following can be + * guaranteed : one thread must call poll() for the last time, then execute a write barrier, + * then the other thread must execute a read barrier before calling poll() for the first time. + * This allows in particular to call poll in @Before and @After methods in JUnit unit tests, + * because JUnit will enforce those barriers by creating the testing thread after executing + * @Before and joining the thread after executing @After. + * + * peek() can be used by multiple threads concurrently, but only if no thread is calling + * poll() outside of the boundaries above. For simplicity, it can be considered that peek() + * is safe to call only when poll() is safe to call. + * + * Polling concurrently from the same ArrayTrackRecord is supported by creating multiple + * ReadHeads on the same instance of ArrayTrackRecord (or of course by using ArrayTrackRecord + * directly). Each ReadHead is then guaranteed to see all events always and + * guarantees are made on the value of the mark upon return. {@see poll(Long, (E) -> Boolean)} + * for details. Be careful to create each ReadHead on the thread it is meant to be used on, or + * to have a clear synchronization point between creation and use. + * + * Users of a ReadHead can ask for the current position of the mark at any time, on a thread + * where it's safe to call peek(). This mark can be used later to replay the history of events + * either on this ReadHead, on the associated ArrayTrackRecord or on another ReadHead + * associated with the same ArrayTrackRecord. It might look like this in the reader thread : * * val markAtStart = record.mark * // Start processing interesting events @@ -190,22 +207,39 @@ class ArrayTrackRecord : TrackRecord { * val specialElement = record.poll(timeout, markAtStart) { it.isSpecial() } */ inner class ReadHead : TrackRecord by this@ArrayTrackRecord { - private val owningThread = Thread.currentThread() + // This lock only controls access to the readHead member below. The ArrayTrackRecord + // object has its own synchronization following different (and more usual) semantics. + // See the comment on the ReadHead class for details. + private val slock = StampedLock() private var readHead = 0 /** * @return the current value of the mark. */ var mark - get() = readHead.also { checkThread() } + get() = checkThread { readHead } set(v: Int) = rewind(v) fun rewind(v: Int) { - checkThread() + val stamp = slock.tryWriteLock() + if (0L == stamp) concurrentAccessDetected() readHead = v + slock.unlockWrite(stamp) } - private fun checkThread() = check(Thread.currentThread() == owningThread) { - "Must be called by the thread that created this object" + private fun checkThread(r: (Long) -> T): T { + // tryOptimisticRead is a read barrier, guarantees writes from other threads are visible + // after it + val stamp = slock.tryOptimisticRead() + val result = r(stamp) + // validate also performs a read barrier, guaranteeing that if validate returns true, + // then any change either happens-before tryOptimisticRead, or happens-after validate. + if (!slock.validate(stamp)) concurrentAccessDetected() + return result + } + + private fun concurrentAccessDetected(): Nothing { + throw ConcurrentModificationException( + "ReadHeads can't be used concurrently. Check your threading model.") } /** @@ -225,21 +259,27 @@ class ArrayTrackRecord : TrackRecord { * @return an element matching the predicate, or null if timeout. */ fun poll(timeoutMs: Long, predicate: (E) -> Boolean = { true }): E? { - checkThread() - lock.withLock { - val index = pollForIndexReadLocked(timeoutMs, readHead, predicate) - readHead = if (index < 0) size else index + 1 - return getOrNull(index) + val stamp = slock.tryWriteLock() + if (0L == stamp) concurrentAccessDetected() + try { + lock.withLock { + val index = pollForIndexReadLocked(timeoutMs, readHead, predicate) + readHead = if (index < 0) size else index + 1 + return getOrNull(index) + } + } finally { + slock.unlockWrite(stamp) } } /** * Returns the first element after the mark or null. This never blocks. * - * This method can only be used by the thread that created this ManagedRecordingQueue. - * If used on another thread, this throws IllegalStateException. + * This method is subject to threading restrictions. It can be used concurrently on + * multiple threads but not if any other thread might be executing poll() at the same + * time. See the class comment for details. */ - fun peek(): E? = getOrNull(readHead).also { checkThread() } + fun peek(): E? = checkThread { getOrNull(readHead) } } } From 128c31f0b85974258245823eaf6ddffaf0eced4f Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 21 Dec 2020 07:16:47 +0000 Subject: [PATCH 086/777] Add kotlin-reflect to net-tests-utils This fixes failures in CtsNetTestCases, where TestableNetworkCallback.TAG cannot be used because it uses kotlin-reflect. Change-Id: I7e76fe224b1098c967665275eac24fcac08fca23 Fixes: 176047509 Test: atest CtsNetTestCasesLatestSdk --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 76aceda81c..80a358932a 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -99,6 +99,7 @@ java_library { ], static_libs: [ "androidx.test.ext.junit", + "kotlin-reflect", "libnanohttpd", "net-tests-utils-host-device-common", "net-utils-device-common", From acc47e60dac1b61af810384cb069574962f5a465 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 23 Dec 2020 07:55:44 +0000 Subject: [PATCH 087/777] Add ETHER_BROADCAST and DEFAULT_LINK_MTU constants. ETHER_BROADCAST is used to fill the destination mac address of ether header, it was defined in the DhcpPacket.java, move it to a common place for other usecases. Also have a link mtu constant(default value is 1500 bytes), irrelevant to specific link-layer type. Bug: 175830307 Test: m Change-Id: I422d284cd8fa943bd745ad29229a54515135a3c4 --- .../com/android/net/module/util/NetworkStackConstants.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 1572fe0438..a2275054c7 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -46,6 +46,12 @@ public final class NetworkStackConstants { public static final int ETHER_TYPE_IPV6 = 0x86dd; public static final int ETHER_HEADER_LEN = 14; public static final int ETHER_MTU = 1500; + public static final byte[] ETHER_BROADCAST = new byte[] { + (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, + }; + + public static final int DEFAULT_LINK_MTU = 1500; /** * ARP constants. From d24625247b4a9fb62db0029a10f3d9d41b36207f Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Wed, 23 Dec 2020 19:45:18 +0000 Subject: [PATCH 088/777] Add visibility rule for migration. Add paths to visibility needed for tests. Soong allows specifying paths w/o validation. Once the migration is complete, we can remove the old path in visibility rules. BUG: 137323948 Test: TH Change-Id: Ie9a36ef65b72aeb99c9580c4d5ed29bf9367bd25 Exempt-From-Owner-Approval: Cleanup CL --- staticlibs/Android.bp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 80a358932a..41bc1dae9d 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -126,16 +126,17 @@ java_library { visibility: [ "//cts/tests/tests/net", "//cts/tests/tests/wifi", - "//packages/modules/Connectivity/tests/cts/net", "//frameworks/base/packages/Tethering", - "//packages/modules/Connectivity/Tethering", "//frameworks/base/tests:__subpackages__", + "//frameworks/base/wifi:__subpackages__", + "//frameworks/libs/net/common/tests:__subpackages__", "//frameworks/opt/net/ike", "//frameworks/opt/telephony", - "//frameworks/base/wifi:__subpackages__", - "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", - "//frameworks/libs/net/common/tests:__subpackages__", + "//packages/modules/Connectivity/tests/cts/net", + "//packages/modules/Connectivity/Tethering", + "//packages/modules/NetworkStack:__subpackages__", + "//packages/modules/Wifi/framework/tests:__subpackages__", ] } From fe99df5a25e6c0d9ec9f5f5035d8b8f25094117e Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Thu, 24 Dec 2020 03:28:41 +0000 Subject: [PATCH 089/777] Add visibility rule for migration. Add paths to visibility needed for tests. Soong allows specifying paths w/o validation. Once the migration is complete, we can remove the old path in visibility rules. BUG: 137323948 Test: TH Merged-In: Id19c650246a8f3d55d7b6a874840a6eebcd9eb17 Change-Id: I68de6a67b978ed5a2e721adf41329af349076696 Exempt-From-Owner-Approval: Cleanup CL --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index e0378e2817..4e78d20649 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -140,6 +140,7 @@ java_library { "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", + "//packages/modules/Wifi/framework/tests:__subpackages__", ] } From 66a1a9032a2ee844646def6a73017c2bf3a58f71 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Thu, 24 Dec 2020 03:42:14 +0000 Subject: [PATCH 090/777] Add visibility rule for migration. Add paths to visibility needed for tests. Soong allows specifying paths w/o validation. Once the migration is complete, we can remove the old path in visibility rules. BUG: 137323948 Test: TH Merged-In: Ie9a36ef65b72aeb99c9580c4d5ed29bf9367bd25 Change-Id: I03dbededd107ed5304857f798180aa78a0a9e36c Exempt-From-Owner-Approval: Migration CL --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index e0378e2817..8c83aa7117 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -140,6 +140,7 @@ java_library { "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", + "//packages/modules/Wifi/framework/tests:__subpackages__", ] } From 81a17c3fc6661ebfdaafbcdeb7efd6de02909ade Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 24 Dec 2020 04:42:35 +0000 Subject: [PATCH 091/777] Support common MacAddress Type in Struct. MacAddress class is helpful to represent a 48-bits long MAC Address, we have to use 6-bytes array to interpret a MAC Address without a specific annotation type. To better parse the MAC Address appeared in the ether header, link-layer address option or Bpf class, it's worth supporting this specific type. Bug: 163492391 Test: atest NetworkStaticLibTests Change-Id: I1f716e5d4f38372fc5b7ee32e208d55a072c1e51 --- .../com/android/net/module/util/Struct.java | 17 ++++++++++ .../android/net/module/util/StructTest.java | 34 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/Struct.java b/staticlibs/device/com/android/net/module/util/Struct.java index bc8761a004..6d8d3011db 100644 --- a/staticlibs/device/com/android/net/module/util/Struct.java +++ b/staticlibs/device/com/android/net/module/util/Struct.java @@ -17,6 +17,7 @@ package com.android.net.module.util; import android.annotation.NonNull; +import android.net.MacAddress; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -110,6 +111,7 @@ public class Struct { UBE63, // unsigned long(MSB: 0) in network order, size = 8 bytes UBE64, // unsigned long in network order, size = 8 bytes ByteArray, // byte array with predefined length + EUI48, // a 48-bits long MAC address } /** @@ -179,6 +181,9 @@ public class Struct { + annotation.arraysize()); } return; + case EUI48: + if (fieldType == MacAddress.class) return; + break; default: throw new IllegalArgumentException("Unknown type" + annotation.type()); } @@ -213,6 +218,9 @@ public class Struct { case ByteArray: length = annotation.arraysize(); break; + case EUI48: + length = 6; + break; default: throw new IllegalArgumentException("Unknown type" + annotation.type()); } @@ -373,6 +381,11 @@ public class Struct { buf.get(array); value = array; break; + case EUI48: + final byte[] macAddress = new byte[6]; + buf.get(macAddress); + value = MacAddress.fromBytes(macAddress); + break; default: throw new IllegalArgumentException("Unknown type:" + fieldInfo.annotation.type()); } @@ -442,6 +455,10 @@ public class Struct { case ByteArray: output.put((byte[]) value); break; + case EUI48: + final byte[] macAddress = ((MacAddress) value).toByteArray(); + output.put(macAddress); + break; default: throw new IllegalArgumentException("Unknown type:" + fieldInfo.annotation.type()); } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java index 1b03e75016..47b34b929c 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.net.IpPrefix; +import android.net.MacAddress; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -663,4 +664,37 @@ public class StructTest { private ByteBuffer toByteBuffer(final String hexString) { return ByteBuffer.wrap(HexDump.hexStringToByteArray(hexString)); } + + static class MacAddressMessage extends Struct { + @Field(order = 0, type = Type.EUI48) final MacAddress mMac1; + @Field(order = 1, type = Type.EUI48) final MacAddress mMac2; + + MacAddressMessage(final MacAddress mac1, final MacAddress mac2) { + this.mMac1 = mac1; + this.mMac2 = mac2; + } + } + + @Test + public void testMacAddressType() { + final MacAddressMessage msg = doParsingMessageTest("001122334455" + "ffffffffffff", + MacAddressMessage.class, ByteOrder.BIG_ENDIAN); + + assertEquals(MacAddress.fromString("00:11:22:33:44:55"), msg.mMac1); + assertEquals(MacAddress.fromString("ff:ff:ff:ff:ff:ff"), msg.mMac2); + + assertEquals(12, Struct.getSize(MacAddressMessage.class)); + assertArrayEquals(toByteBuffer("001122334455" + "ffffffffffff").array(), + msg.writeToBytes(ByteOrder.BIG_ENDIAN)); + } + + static class BadMacAddressType extends Struct { + @Field(order = 0, type = Type.EUI48) byte[] mMac; + } + + @Test + public void testIncorrectType_EUI48WithByteArray() { + assertThrows(IllegalArgumentException.class, + () -> Struct.parse(BadMacAddressType.class, toByteBuffer("ffffffffffff"))); + } } From 57969d0ec969bb6f2b3ae90e5eda2f97da63ec00 Mon Sep 17 00:00:00 2001 From: Serik Beketayev Date: Wed, 9 Dec 2020 19:48:42 -0800 Subject: [PATCH 092/777] [Mainline] ProxyInfo migration Bug: 173455434 Test: mma Change-Id: I49f7f491acc657051d9c79fc24605d4896cbc315 --- .../android/net/module/util/ProxyUtils.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 staticlibs/framework/com/android/net/module/util/ProxyUtils.java diff --git a/staticlibs/framework/com/android/net/module/util/ProxyUtils.java b/staticlibs/framework/com/android/net/module/util/ProxyUtils.java new file mode 100644 index 0000000000..a7b8393807 --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/ProxyUtils.java @@ -0,0 +1,48 @@ +/* + * Copyright 2020 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 com.android.net.module.util; + +import android.text.TextUtils; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +/** + * Collection of network common utilities. + * + * @hide + */ +public final class ProxyUtils { + + /** Converts exclusion list from String to List. */ + public static List exclusionStringAsList(String exclusionList) { + if (exclusionList == null) { + return Collections.emptyList(); + } + return Arrays.asList(exclusionList.toLowerCase(Locale.ROOT).split(",")); + } + + /** Converts exclusion list from List to string */ + public static String exclusionListAsString(String[] exclusionList) { + if (exclusionList == null) { + return ""; + } + return TextUtils.join(",", exclusionList); + } +} From b86b34da48118c4e51900648c0827dba29d21605 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 1 Dec 2020 18:29:21 +0900 Subject: [PATCH 093/777] Split NetworkStackUtils to frameworks/libs/net Split DeviceConfig and collections-related utilities to CollectionUtils and DeviceConfigUtils in frameworks/libs/net. Also add implementations for contains(array, value), to avoid usage of internal non-API utils. The original tests are based on mockito-extended, so also add to NetworkStackTests as a dependency. This also requires setting the test app as debuggable in its manifest. Bug: 17454103 Test: atest NetworkStaticLibTests Change-Id: Ie9bed66a08b7370ebe50d0a7240b788f8b31aa77 --- staticlibs/Android.bp | 1 + .../net/module/util/CollectionUtils.java | 106 +++++++++ .../net/module/util/DeviceConfigUtils.java | 162 ++++++++++++++ .../net/module/util/ConnectivityUtils.java | 66 ++++++ staticlibs/tests/unit/Android.bp | 6 + staticlibs/tests/unit/AndroidManifest.xml | 2 +- .../module/util/ConnectivityUtilsTest.java | 46 ++++ .../module/util/DeviceConfigUtilsTest.java | 202 ++++++++++++++++++ 8 files changed, 590 insertions(+), 1 deletion(-) create mode 100644 staticlibs/device/com/android/net/module/util/CollectionUtils.java create mode 100644 staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java create mode 100644 staticlibs/framework/com/android/net/module/util/ConnectivityUtils.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/ConnectivityUtilsTest.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 80a358932a..8943453a89 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -143,6 +143,7 @@ filegroup { name: "net-utils-services-common-srcs", srcs: [ "device/android/net/NetworkFactory.java", + "device/com/android/net/module/util/CollectionUtils.java", ], visibility: [ "//frameworks/base/services/net", diff --git a/staticlibs/device/com/android/net/module/util/CollectionUtils.java b/staticlibs/device/com/android/net/module/util/CollectionUtils.java new file mode 100644 index 0000000000..74f738dafd --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/CollectionUtils.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.util.SparseArray; + +import java.util.Collection; +import java.util.Objects; +import java.util.function.Predicate; + +/** + * Utilities for {@link Collection} and arrays. + */ +public final class CollectionUtils { + private CollectionUtils() {} + + /** + * @return True if the array is null or 0-length. + */ + public static boolean isEmpty(@Nullable T[] array) { + return array == null || array.length == 0; + } + + /** + * Returns an int array from the given Integer list. + */ + @NonNull + public static int[] toIntArray(@NonNull Collection list) { + int[] array = new int[list.size()]; + int i = 0; + for (Integer item : list) { + array[i] = item; + i++; + } + return array; + } + + /** + * Returns a long array from the given long list. + */ + @NonNull + public static long[] toLongArray(@NonNull Collection list) { + long[] array = new long[list.size()]; + int i = 0; + for (Long item : list) { + array[i] = item; + i++; + } + return array; + } + + /** + * @return True if there exists at least one element in the sparse array for which + * condition {@code predicate} + */ + public static boolean any(@NonNull SparseArray array, @NonNull Predicate predicate) { + for (int i = 0; i < array.size(); ++i) { + if (predicate.test(array.valueAt(i))) { + return true; + } + } + return false; + } + + /** + * @return true if the array contains the specified value. + */ + public static boolean contains(@Nullable int[] array, int value) { + if (array == null) return false; + for (int element : array) { + if (element == value) { + return true; + } + } + return false; + } + + /** + * @return true if the array contains the specified value. + */ + public static boolean contains(@Nullable T[] array, @Nullable T value) { + if (array == null) return false; + for (T element : array) { + if (Objects.equals(element, value)) { + return true; + } + } + return false; + } +} diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java new file mode 100644 index 0000000000..5fec0dde84 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.provider.DeviceConfig; +import android.util.Log; + +import androidx.annotation.BoolRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** + * Utilities for modules to query {@link DeviceConfig} and flags. + */ +public final class DeviceConfigUtils { + private DeviceConfigUtils() {} + + private static final String TAG = DeviceConfigUtils.class.getSimpleName(); + + /** + * Look up the value of a property for a particular namespace from {@link DeviceConfig}. + * @param namespace The namespace containing the property to look up. + * @param name The name of the property to look up. + * @param defaultValue The value to return if the property does not exist or has no valid value. + * @return the corresponding value, or defaultValue if none exists. + */ + @Nullable + public static String getDeviceConfigProperty(@NonNull String namespace, @NonNull String name, + @Nullable String defaultValue) { + String value = DeviceConfig.getProperty(namespace, name); + return value != null ? value : defaultValue; + } + + /** + * Look up the value of a property for a particular namespace from {@link DeviceConfig}. + * @param namespace The namespace containing the property to look up. + * @param name The name of the property to look up. + * @param defaultValue The value to return if the property does not exist or its value is null. + * @return the corresponding value, or defaultValue if none exists. + */ + public static int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name, + int defaultValue) { + String value = getDeviceConfigProperty(namespace, name, null /* defaultValue */); + try { + return (value != null) ? Integer.parseInt(value) : defaultValue; + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * Look up the value of a property for a particular namespace from {@link DeviceConfig}. + * + * Flags like timeouts should use this method and set an appropriate min/max range: if invalid + * values like "0" or "1" are pushed to devices, everything would timeout. The min/max range + * protects against this kind of breakage. + * @param namespace The namespace containing the property to look up. + * @param name The name of the property to look up. + * @param minimumValue The minimum value of a property. + * @param maximumValue The maximum value of a property. + * @param defaultValue The value to return if the property does not exist or its value is null. + * @return the corresponding value, or defaultValue if none exists or the fetched value is + * not in the provided range. + */ + public static int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name, + int minimumValue, int maximumValue, int defaultValue) { + int value = getDeviceConfigPropertyInt(namespace, name, defaultValue); + if (value < minimumValue || value > maximumValue) return defaultValue; + return value; + } + + /** + * Look up the value of a property for a particular namespace from {@link DeviceConfig}. + * @param namespace The namespace containing the property to look up. + * @param name The name of the property to look up. + * @param defaultValue The value to return if the property does not exist or its value is null. + * @return the corresponding value, or defaultValue if none exists. + */ + public static boolean getDeviceConfigPropertyBoolean(@NonNull String namespace, + @NonNull String name, boolean defaultValue) { + String value = getDeviceConfigProperty(namespace, name, null /* defaultValue */); + return (value != null) ? Boolean.parseBoolean(value) : defaultValue; + } + + /** + * Check whether or not one specific experimental feature for a particular namespace from + * {@link DeviceConfig} is enabled by comparing module package version + * with current version of property. If this property version is valid, the corresponding + * experimental feature would be enabled, otherwise disabled. + * + * This is useful to ensure that if a module install is rolled back, flags are not left fully + * rolled out on a version where they have not been well tested. + * @param context The global context information about an app environment. + * @param namespace The namespace containing the property to look up. + * @param name The name of the property to look up. + * @return true if this feature is enabled, or false if disabled. + */ + public static boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, + @NonNull String name) { + return isFeatureEnabled(context, namespace, name, false /* defaultEnabled */); + } + + /** + * Check whether or not one specific experimental feature for a particular namespace from + * {@link DeviceConfig} is enabled by comparing module package version + * with current version of property. If this property version is valid, the corresponding + * experimental feature would be enabled, otherwise disabled. + * + * This is useful to ensure that if a module install is rolled back, flags are not left fully + * rolled out on a version where they have not been well tested. + * @param context The global context information about an app environment. + * @param namespace The namespace containing the property to look up. + * @param name The name of the property to look up. + * @param defaultEnabled The value to return if the property does not exist or its value is + * null. + * @return true if this feature is enabled, or false if disabled. + */ + public static boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, + @NonNull String name, boolean defaultEnabled) { + try { + final int propertyVersion = getDeviceConfigPropertyInt(namespace, name, + 0 /* default value */); + final long packageVersion = context.getPackageManager().getPackageInfo( + context.getPackageName(), 0).getLongVersionCode(); + return (propertyVersion == 0 && defaultEnabled) + || (propertyVersion != 0 && packageVersion >= (long) propertyVersion); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Could not find the package name", e); + return false; + } + } + + /** + * Gets boolean config from resources. + */ + public static boolean getResBooleanConfig(@NonNull final Context context, + @BoolRes int configResource, final boolean defaultValue) { + final Resources res = context.getResources(); + try { + return res.getBoolean(configResource); + } catch (Resources.NotFoundException e) { + return defaultValue; + } + } +} diff --git a/staticlibs/framework/com/android/net/module/util/ConnectivityUtils.java b/staticlibs/framework/com/android/net/module/util/ConnectivityUtils.java new file mode 100644 index 0000000000..382912bf8d --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/ConnectivityUtils.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + + +import android.annotation.Nullable; + +import java.net.Inet6Address; +import java.net.InetAddress; + +/** + * Various utilities used in connectivity code. + */ +public final class ConnectivityUtils { + private ConnectivityUtils() {} + + + /** + * Return IP address and port in a string format. + */ + public static String addressAndPortToString(InetAddress address, int port) { + return String.format( + (address instanceof Inet6Address) ? "[%s]:%d" : "%s:%d", + address.getHostAddress(), port); + } + + /** + * Return true if the provided address is non-null and an IPv6 Unique Local Address (RFC4193). + */ + public static boolean isIPv6ULA(@Nullable InetAddress addr) { + return addr instanceof Inet6Address + && ((addr.getAddress()[0] & 0xfe) == 0xfc); + } + + /** + * Returns the {@code int} nearest in value to {@code value}. + * + * @param value any {@code long} value + * @return the same value cast to {@code int} if it is in the range of the {@code int} + * type, {@link Integer#MAX_VALUE} if it is too large, or {@link Integer#MIN_VALUE} if + * it is too small + */ + public static int saturatedCast(long value) { + if (value > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + if (value < Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } + return (int) value; + } +} diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index 537340ef78..c00202e63f 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -9,6 +9,7 @@ android_library { static_libs: [ "net-utils-framework-common", "androidx.test.rules", + "mockito-target-extended-minus-junit4", "net-utils-device-common", "net-tests-utils-host-device-common", ], @@ -29,6 +30,11 @@ android_test { static_libs: [ "NetworkStaticLibTestsLib", ], + jni_libs: [ + // For mockito extended + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", + ], jarjar_rules: "jarjar-rules.txt", test_suites: ["device-tests"], } diff --git a/staticlibs/tests/unit/AndroidManifest.xml b/staticlibs/tests/unit/AndroidManifest.xml index c747c8a585..84a20a277b 100644 --- a/staticlibs/tests/unit/AndroidManifest.xml +++ b/staticlibs/tests/unit/AndroidManifest.xml @@ -19,7 +19,7 @@ - + diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/ConnectivityUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/ConnectivityUtilsTest.java new file mode 100644 index 0000000000..8af01965fa --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/ConnectivityUtilsTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import static android.net.InetAddresses.parseNumericAddress; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import static com.android.net.module.util.ConnectivityUtils.isIPv6ULA; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Tests for ConnectivityUtils */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class ConnectivityUtilsTest { + @Test + public void testIsIPv6ULA() { + assertTrue(isIPv6ULA(parseNumericAddress("fc00::"))); + assertTrue(isIPv6ULA(parseNumericAddress("fc00::1"))); + assertTrue(isIPv6ULA(parseNumericAddress("fc00:1234::5678"))); + assertTrue(isIPv6ULA(parseNumericAddress("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); + + assertFalse(isIPv6ULA(parseNumericAddress("fe00::"))); + assertFalse(isIPv6ULA(parseNumericAddress("2480:1248::123:456"))); + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java new file mode 100644 index 0000000000..bb78854c79 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.eq; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.Resources; +import android.provider.DeviceConfig; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.MockitoSession; + + +/** + * Tests for DeviceConfigUtils. + * + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class DeviceConfigUtilsTest { + private static final String TEST_NAME_SPACE = "connectivity"; + private static final String TEST_EXPERIMENT_FLAG = "experiment_flag"; + private static final int TEST_FLAG_VALUE = 28; + private static final String TEST_FLAG_VALUE_STRING = "28"; + private static final int TEST_DEFAULT_FLAG_VALUE = 0; + private static final int TEST_MAX_FLAG_VALUE = 1000; + private static final int TEST_MIN_FLAG_VALUE = 100; + private static final long TEST_PACKAGE_VERSION = 290000000; + private static final String TEST_PACKAGE_NAME = "test.package.name"; + private MockitoSession mSession; + + @Mock private Context mContext; + @Mock private PackageManager mPm; + @Mock private PackageInfo mPi; + @Mock private Resources mResources; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mSession = mockitoSession().spyStatic(DeviceConfig.class).startMocking(); + + final PackageInfo pi = new PackageInfo(); + pi.setLongVersionCode(TEST_PACKAGE_VERSION); + + doReturn(mPm).when(mContext).getPackageManager(); + doReturn(TEST_PACKAGE_NAME).when(mContext).getPackageName(); + doReturn(pi).when(mPm).getPackageInfo(anyString(), anyInt()); + doReturn(mResources).when(mContext).getResources(); + } + + @After + public void tearDown() { + mSession.finishMocking(); + } + + @Test + public void testGetDeviceConfigPropertyInt_Null() { + doReturn(null).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), + eq(TEST_EXPERIMENT_FLAG))); + assertEquals(TEST_DEFAULT_FLAG_VALUE, DeviceConfigUtils.getDeviceConfigPropertyInt( + TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, + TEST_DEFAULT_FLAG_VALUE /* default value */)); + } + + @Test + public void testGetDeviceConfigPropertyInt_NotNull() { + doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), + eq(TEST_EXPERIMENT_FLAG))); + assertEquals(TEST_FLAG_VALUE, DeviceConfigUtils.getDeviceConfigPropertyInt( + TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, + TEST_DEFAULT_FLAG_VALUE /* default value */)); + } + + @Test + public void testGetDeviceConfigPropertyInt_NormalValue() { + doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), + eq(TEST_EXPERIMENT_FLAG))); + assertEquals(TEST_FLAG_VALUE, DeviceConfigUtils.getDeviceConfigPropertyInt( + TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, 0 /* minimum value */, + TEST_MAX_FLAG_VALUE /* maximum value */, + TEST_DEFAULT_FLAG_VALUE /* default value */)); + } + + @Test + public void testGetDeviceConfigPropertyInt_NullValue() { + doReturn(null).when(() -> DeviceConfig.getProperty( + eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); + assertEquals(TEST_DEFAULT_FLAG_VALUE, DeviceConfigUtils.getDeviceConfigPropertyInt( + TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, 0 /* minimum value */, + TEST_MAX_FLAG_VALUE /* maximum value */, + TEST_DEFAULT_FLAG_VALUE /* default value */)); + } + + @Test + public void testGetDeviceConfigPropertyInt_OverMaximumValue() { + doReturn(Integer.toString(TEST_MAX_FLAG_VALUE + 10)).when(() -> DeviceConfig.getProperty( + eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); + assertEquals(TEST_DEFAULT_FLAG_VALUE, DeviceConfigUtils.getDeviceConfigPropertyInt( + TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_MIN_FLAG_VALUE /* minimum value */, + TEST_MAX_FLAG_VALUE /* maximum value */, + TEST_DEFAULT_FLAG_VALUE /* default value */)); + } + + @Test + public void testGetDeviceConfigPropertyInt_BelowMinimumValue() { + doReturn(Integer.toString(TEST_MIN_FLAG_VALUE - 10)).when(() -> DeviceConfig.getProperty( + eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); + assertEquals(TEST_DEFAULT_FLAG_VALUE, DeviceConfigUtils.getDeviceConfigPropertyInt( + TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_MIN_FLAG_VALUE /* minimum value */, + TEST_MAX_FLAG_VALUE /* maximum value */, + TEST_DEFAULT_FLAG_VALUE /* default value */)); + } + + @Test + public void testGetDeviceConfigPropertyBoolean_Null() { + doReturn(null).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), + eq(TEST_EXPERIMENT_FLAG))); + assertFalse(DeviceConfigUtils.getDeviceConfigPropertyBoolean( + TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, + false /* default value */)); + } + + @Test + public void testGetDeviceConfigPropertyBoolean_NotNull() { + doReturn("true").when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), + eq(TEST_EXPERIMENT_FLAG))); + assertTrue(DeviceConfigUtils.getDeviceConfigPropertyBoolean( + TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, + false /* default value */)); + } + + @Test + public void testFeatureIsEnabledWithExceptionsEnabled() { + doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), + eq(TEST_EXPERIMENT_FLAG))); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG)); + } + + @Test + public void testFeatureIsNotEnabled() { + doReturn(null).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), + eq(TEST_EXPERIMENT_FLAG))); + assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG)); + } + + @Test + public void testFeatureIsEnabledWithException() throws Exception { + doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), + eq(TEST_EXPERIMENT_FLAG))); + doThrow(NameNotFoundException.class).when(mPm).getPackageInfo(anyString(), anyInt()); + assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG)); + } + + @Test + public void testGetResBooleanConfig() { + final int someResId = 1234; + doReturn(true).when(mResources).getBoolean(someResId); + assertTrue(DeviceConfigUtils.getResBooleanConfig(mContext, someResId, false)); + doReturn(false).when(mResources).getBoolean(someResId); + assertFalse(DeviceConfigUtils.getResBooleanConfig(mContext, someResId, false)); + doThrow(new Resources.NotFoundException()).when(mResources).getBoolean(someResId); + assertFalse(DeviceConfigUtils.getResBooleanConfig(mContext, someResId, false)); + } +} From a744975b3e9016fc0de2dd47c39d1d99c13adf5b Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 24 Dec 2020 19:03:04 +0900 Subject: [PATCH 094/777] Add getDisplayTransport While networks can have multiple transports, users generally think of them as "wifi", "mobile data", "vpn" and expect them to be classified as such in UI such as settings. Add a getDisplayTransport utility that returns which transport should be used for UI display, from a list of transports of a network. Bug: 174436414 Test: atest NetworkStaticLibTests Change-Id: Iaefb47bcaa2f6ce2e7a2ae5011c340154009ac3c --- .../module/util/NetworkCapabilitiesUtils.java | 80 +++++++++++++++++++ .../util/NetworkCapabilitiesUtilsTest.kt | 61 ++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/NetworkCapabilitiesUtils.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt diff --git a/staticlibs/device/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/device/com/android/net/module/util/NetworkCapabilitiesUtils.java new file mode 100644 index 0000000000..dd5a4812ed --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; + +import androidx.annotation.NonNull; + +/** + * Utilities to examine {@link android.net.NetworkCapabilities}. + */ +public final class NetworkCapabilitiesUtils { + // Transports considered to classify networks in UI, in order of which transport should be + // surfaced when there are multiple transports. Transports not in this list do not have + // an ordering preference (in practice they will have a deterministic order based on the + // transport int itself). + private static final int[] DISPLAY_TRANSPORT_PRIORITIES = new int[] { + // Users think of their VPNs as VPNs, not as any of the underlying nets + TRANSPORT_VPN, + // If the network has cell, prefer showing that because it's usually metered. + TRANSPORT_CELLULAR, + // If the network has WiFi aware, prefer showing that as it's a more specific use case. + // Ethernet can masquerade as other transports, where the device uses ethernet to connect to + // a box providing cell or wifi. Today this is represented by only the masqueraded type for + // backward compatibility, but these networks should morally have Ethernet & the masqueraded + // type. Because of this, prefer other transports instead of Ethernet. + TRANSPORT_WIFI_AWARE, + TRANSPORT_BLUETOOTH, + TRANSPORT_WIFI, + TRANSPORT_ETHERNET + + // Notably, TRANSPORT_TEST is not in this list as any network that has TRANSPORT_TEST and + // one of the above transports should be counted as that transport, to keep tests as + // realistic as possible. + }; + + /** + * Get a transport that can be used to classify a network when displaying its info to users. + * + * While networks can have multiple transports, users generally think of them as "wifi", + * "mobile data", "vpn" and expect them to be classified as such in UI such as settings. + * @param transports Non-empty array of transports on a network + * @return A single transport + * @throws IllegalArgumentException The array is empty + */ + public static int getDisplayTransport(@NonNull int[] transports) { + for (int transport : DISPLAY_TRANSPORT_PRIORITIES) { + if (CollectionUtils.contains(transports, transport)) { + return transport; + } + } + + if (transports.length < 1) { + // All NetworkCapabilities representing a network have at least one transport, so an + // empty transport array would be created by the caller instead of extracted from + // NetworkCapabilities. + throw new IllegalArgumentException("No transport in the provided array"); + } + return transports[0]; + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt new file mode 100644 index 0000000000..e94d132811 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util + +import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH +import android.net.NetworkCapabilities.TRANSPORT_CELLULAR +import android.net.NetworkCapabilities.TRANSPORT_ETHERNET +import android.net.NetworkCapabilities.TRANSPORT_TEST +import android.net.NetworkCapabilities.TRANSPORT_VPN +import android.net.NetworkCapabilities.TRANSPORT_WIFI +import android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport +import org.junit.Test +import org.junit.runner.RunWith +import java.lang.IllegalArgumentException +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith + +@RunWith(AndroidJUnit4::class) +@SmallTest +class NetworkCapabilitiesUtilsTest { + + @Test + fun testGetAccountingTransport() { + assertEquals(TRANSPORT_WIFI, getDisplayTransport(intArrayOf(TRANSPORT_WIFI))) + assertEquals(TRANSPORT_CELLULAR, getDisplayTransport(intArrayOf(TRANSPORT_CELLULAR))) + assertEquals(TRANSPORT_BLUETOOTH, getDisplayTransport(intArrayOf(TRANSPORT_BLUETOOTH))) + assertEquals(TRANSPORT_ETHERNET, getDisplayTransport(intArrayOf(TRANSPORT_ETHERNET))) + assertEquals(TRANSPORT_WIFI_AWARE, getDisplayTransport(intArrayOf(TRANSPORT_WIFI_AWARE))) + + assertEquals(TRANSPORT_VPN, getDisplayTransport( + intArrayOf(TRANSPORT_VPN, TRANSPORT_WIFI))) + assertEquals(TRANSPORT_VPN, getDisplayTransport( + intArrayOf(TRANSPORT_CELLULAR, TRANSPORT_VPN))) + + assertEquals(TRANSPORT_WIFI, getDisplayTransport( + intArrayOf(TRANSPORT_ETHERNET, TRANSPORT_WIFI))) + assertEquals(TRANSPORT_ETHERNET, getDisplayTransport( + intArrayOf(TRANSPORT_ETHERNET, TRANSPORT_TEST))) + + assertFailsWith(IllegalArgumentException::class) { + getDisplayTransport(intArrayOf()) + } + } +} \ No newline at end of file From 31c6d82be040ddd345fe539016d6d59e428adeb3 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 25 Dec 2020 16:48:33 +0900 Subject: [PATCH 095/777] Add DeviceConfigUtils version caching and tests Querying the APK version can be relatively expensive, so cache it with a static. Package version cannot change without restarting the process. Also add some testing for flags being equal to the min/max values. Bug: 17454103 Test: atest NetworkStaticLibTests Change-Id: I18c298beb843e0a9f76162d353623bb15ab155f1 --- .../net/module/util/DeviceConfigUtils.java | 19 ++++++++- .../module/util/DeviceConfigUtilsTest.java | 40 ++++++++++++++++++- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index 5fec0dde84..271cc6ead2 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -25,6 +25,7 @@ import android.util.Log; import androidx.annotation.BoolRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; /** * Utilities for modules to query {@link DeviceConfig} and flags. @@ -34,6 +35,21 @@ public final class DeviceConfigUtils { private static final String TAG = DeviceConfigUtils.class.getSimpleName(); + @VisibleForTesting + protected static volatile long sPackageVersion = -1; + private static long getPackageVersion(@NonNull final Context context) + throws PackageManager.NameNotFoundException { + // sPackageVersion may be set by another thread just after this check, but querying the + // package version several times on rare occasions is fine. + if (sPackageVersion >= 0) { + return sPackageVersion; + } + final long version = context.getPackageManager().getPackageInfo( + context.getPackageName(), 0).getLongVersionCode(); + sPackageVersion = version; + return version; + } + /** * Look up the value of a property for a particular namespace from {@link DeviceConfig}. * @param namespace The namespace containing the property to look up. @@ -137,8 +153,7 @@ public final class DeviceConfigUtils { try { final int propertyVersion = getDeviceConfigPropertyInt(namespace, name, 0 /* default value */); - final long packageVersion = context.getPackageManager().getPackageInfo( - context.getPackageName(), 0).getLongVersionCode(); + final long packageVersion = getPackageVersion(context); return (propertyVersion == 0 && defaultEnabled) || (propertyVersion != 0 && packageVersion >= (long) propertyVersion); } catch (PackageManager.NameNotFoundException e) { diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java index bb78854c79..982dbe7c81 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -26,6 +26,8 @@ import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import android.content.Context; import android.content.pm.PackageInfo; @@ -86,6 +88,7 @@ public class DeviceConfigUtilsTest { @After public void tearDown() { mSession.finishMocking(); + DeviceConfigUtils.sPackageVersion = -1L; } @Test @@ -136,6 +139,16 @@ public class DeviceConfigUtilsTest { TEST_DEFAULT_FLAG_VALUE /* default value */)); } + @Test + public void testGetDeviceConfigPropertyInt_EqualsMaximumValue() { + doReturn(Integer.toString(TEST_MAX_FLAG_VALUE)).when(() -> DeviceConfig.getProperty( + eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); + assertEquals(TEST_MAX_FLAG_VALUE, DeviceConfigUtils.getDeviceConfigPropertyInt( + TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_MIN_FLAG_VALUE /* minimum value */, + TEST_MAX_FLAG_VALUE /* maximum value */, + TEST_DEFAULT_FLAG_VALUE /* default value */)); + } + @Test public void testGetDeviceConfigPropertyInt_BelowMinimumValue() { doReturn(Integer.toString(TEST_MIN_FLAG_VALUE - 10)).when(() -> DeviceConfig.getProperty( @@ -146,6 +159,16 @@ public class DeviceConfigUtilsTest { TEST_DEFAULT_FLAG_VALUE /* default value */)); } + @Test + public void testGetDeviceConfigPropertyInt_EqualsMinimumValue() { + doReturn(Integer.toString(TEST_MIN_FLAG_VALUE)).when(() -> DeviceConfig.getProperty( + eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); + assertEquals(TEST_MIN_FLAG_VALUE, DeviceConfigUtils.getDeviceConfigPropertyInt( + TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_MIN_FLAG_VALUE /* minimum value */, + TEST_MAX_FLAG_VALUE /* maximum value */, + TEST_DEFAULT_FLAG_VALUE /* default value */)); + } + @Test public void testGetDeviceConfigPropertyBoolean_Null() { doReturn(null).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), @@ -165,7 +188,7 @@ public class DeviceConfigUtilsTest { } @Test - public void testFeatureIsEnabledWithExceptionsEnabled() { + public void testFeatureIsEnabled() { doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, @@ -189,6 +212,21 @@ public class DeviceConfigUtilsTest { TEST_EXPERIMENT_FLAG)); } + @Test + public void testFeatureIsEnabledCaching() throws Exception { + doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), + eq(TEST_EXPERIMENT_FLAG))); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG)); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG)); + + // Package info is only queried once + verify(mContext, times(1)).getPackageManager(); + verify(mContext, times(1)).getPackageName(); + verify(mPm, times(1)).getPackageInfo(anyString(), anyInt()); + } + @Test public void testGetResBooleanConfig() { final int someResId = 1234; From fcbda3ac6699647e9be9291be1f1f927a938b99f Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Thu, 24 Dec 2020 06:12:25 +0000 Subject: [PATCH 096/777] Adjust visibility rules for migration Adjusting visibility to accomodate migration of frameworks/opt/net/wifi to packages/modules/Wifi. BUG: 137323948 Test: TH Change-Id: Iee3f2dc6fc5f3262fa9e81626a3e15a3226e4ab7 --- staticlibs/Android.bp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 4e78d20649..c6a17feeaf 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -48,6 +48,7 @@ java_library { "//packages/modules/Connectivity/Tethering", "//frameworks/opt/net/ike", "//frameworks/opt/net/wifi/service", + "//packages/modules/Wifi/service", "//frameworks/opt/net/telephony", "//frameworks/base/packages/Connectivity:__subpackages__", "//packages/modules/Connectivity:__subpackages__", @@ -140,7 +141,7 @@ java_library { "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", - "//packages/modules/Wifi/framework/tests:__subpackages__", + "//packages/modules/Wifi/framework/tests:__subpackages__", ] } @@ -205,5 +206,6 @@ filegroup { ], visibility: [ "//frameworks/opt/net/wifi/service", + "//packages/modules/Wifi/service", ], } From 22bfada06e63f5d23de49f4a9a84b95661359025 Mon Sep 17 00:00:00 2001 From: markchien Date: Fri, 1 Jan 2021 01:18:47 +0800 Subject: [PATCH 097/777] Default write to byte array with native order Bug: 173167302 Test: atest BpfMapTest atest StructTest Change-Id: I60a22ea4cd44697773d98d1720c02cc771643a9e --- .../com/android/net/module/util/Struct.java | 5 +++++ .../android/net/module/util/StructTest.java | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/Struct.java b/staticlibs/device/com/android/net/module/util/Struct.java index 6d8d3011db..07a7e7aa87 100644 --- a/staticlibs/device/com/android/net/module/util/Struct.java +++ b/staticlibs/device/com/android/net/module/util/Struct.java @@ -602,4 +602,9 @@ public class Struct { writeToByteBufferInternal(buffer, fieldInfos); return output; } + + /** Convert the parsed Struct subclass object to byte array with native order. */ + public final byte[] writeToBytes() { + return writeToBytes(ByteOrder.nativeOrder()); + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java index 47b34b929c..d5e27fb333 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java @@ -697,4 +697,23 @@ public class StructTest { assertThrows(IllegalArgumentException.class, () -> Struct.parse(BadMacAddressType.class, toByteBuffer("ffffffffffff"))); } + + @Test + public void testStructToByteArray() { + final SignedDataMessage littleEndianMsg = doParsingMessageTest(SIGNED_DATA, + SignedDataMessage.class, ByteOrder.LITTLE_ENDIAN); + assertArrayEquals(toByteBuffer(SIGNED_DATA).array(), + littleEndianMsg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); + + final SignedDataMessage bigEndianMsg = doParsingMessageTest(SIGNED_DATA, + SignedDataMessage.class, ByteOrder.BIG_ENDIAN); + assertArrayEquals(toByteBuffer(SIGNED_DATA).array(), + bigEndianMsg.writeToBytes(ByteOrder.BIG_ENDIAN)); + + final SignedDataMessage nativeOrderMsg = ByteOrder.nativeOrder().equals( + ByteOrder.LITTLE_ENDIAN) ? littleEndianMsg : bigEndianMsg; + assertArrayEquals(toByteBuffer(SIGNED_DATA).array(), + nativeOrderMsg.writeToBytes()); + + } } From df3191ada890cebe8dd91b983804041bb20a6543 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 28 Dec 2020 14:09:48 +0900 Subject: [PATCH 098/777] Move NetworkCapabilitiesUtils to framework-common Also move CollectionUtils which is a dependency. NetworkCapabilitiesUtils is needed in BatteryStatsImpl, which is in frameworks/base/core, so it uses the framework-common library. The current framework-common target cannot use androidx annotations due to users of this filegroup. This is being addressed in another change; use android.annotation annotations in the meantime. Bug: 174436414 Test: m Change-Id: Ie188572a6db7c1bea37550a3410d7d828409a902 --- staticlibs/Android.bp | 1 - .../com/android/net/module/util/CollectionUtils.java | 0 .../com/android/net/module/util/NetworkCapabilitiesUtils.java | 3 ++- 3 files changed, 2 insertions(+), 2 deletions(-) rename staticlibs/{device => framework}/com/android/net/module/util/CollectionUtils.java (100%) rename staticlibs/{device => framework}/com/android/net/module/util/NetworkCapabilitiesUtils.java (99%) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index c7a4bd55bd..c6a17feeaf 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -149,7 +149,6 @@ filegroup { name: "net-utils-services-common-srcs", srcs: [ "device/android/net/NetworkFactory.java", - "device/com/android/net/module/util/CollectionUtils.java", ], visibility: [ "//frameworks/base/services/net", diff --git a/staticlibs/device/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java similarity index 100% rename from staticlibs/device/com/android/net/module/util/CollectionUtils.java rename to staticlibs/framework/com/android/net/module/util/CollectionUtils.java diff --git a/staticlibs/device/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java similarity index 99% rename from staticlibs/device/com/android/net/module/util/NetworkCapabilitiesUtils.java rename to staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index dd5a4812ed..5a0200ffaf 100644 --- a/staticlibs/device/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -23,7 +23,8 @@ import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; -import androidx.annotation.NonNull; +import android.annotation.NonNull; + /** * Utilities to examine {@link android.net.NetworkCapabilities}. From 37a2effb0711324d36421e896d0f9a7b2b8c4e49 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Wed, 30 Dec 2020 10:19:09 +0800 Subject: [PATCH 099/777] Have a new library - netd-client in frameworks/libs/net Move BaseNetdUnsolicitedEventListener from tethering module to frameworks/libs/net and have a new library for it. Tethering module can still use BaseNetdUnsolicitedEventListener through netd-client and ConnectivityService and Nat464Xlat also can use it when both of them are under frameworks/base. Bug: 174837473 Test: Manual test and check the log. Change-Id: I44dff1c7639e50b8f20b54c6d5733139b20e2986 --- staticlibs/client-libs/Android.bp | 19 +++++ .../BaseNetdUnsolicitedEventListener.java | 75 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 staticlibs/client-libs/Android.bp create mode 100644 staticlibs/client-libs/netd/com/android/net/module/util/BaseNetdUnsolicitedEventListener.java diff --git a/staticlibs/client-libs/Android.bp b/staticlibs/client-libs/Android.bp new file mode 100644 index 0000000000..f6d781c048 --- /dev/null +++ b/staticlibs/client-libs/Android.bp @@ -0,0 +1,19 @@ +java_library { + name: "netd-client", + srcs: ["netd/**/*"], + sdk_version: "system_current", + min_sdk_version: "29", + apex_available: [ + "//apex_available:platform", + "com.android.tethering" + ], + visibility: [ + "//packages/modules/Connectivity/Tethering", + "//frameworks/base/services:__subpackages__" + ], + libs: ["androidx.annotation_annotation"], + static_libs: [ + "netd_aidl_interface-java", + "netd_event_listener_interface-java" + ] +} diff --git a/staticlibs/client-libs/netd/com/android/net/module/util/BaseNetdUnsolicitedEventListener.java b/staticlibs/client-libs/netd/com/android/net/module/util/BaseNetdUnsolicitedEventListener.java new file mode 100644 index 0000000000..526dd8b1cb --- /dev/null +++ b/staticlibs/client-libs/netd/com/android/net/module/util/BaseNetdUnsolicitedEventListener.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util; + +import android.net.INetdUnsolicitedEventListener; + +import androidx.annotation.NonNull; + +/** + * Base {@link INetdUnsolicitedEventListener} that provides no-op implementations which can be + * overridden. + */ +public class BaseNetdUnsolicitedEventListener extends INetdUnsolicitedEventListener.Stub { + + @Override + public void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, + int uid) { } + + @Override + public void onQuotaLimitReached(@NonNull String alertName, @NonNull String ifName) { } + + @Override + public void onInterfaceDnsServerInfo(@NonNull String ifName, long lifetimeS, + @NonNull String[] servers) { } + + @Override + public void onInterfaceAddressUpdated(@NonNull String addr, String ifName, int flags, + int scope) { } + + @Override + public void onInterfaceAddressRemoved(@NonNull String addr, @NonNull String ifName, int flags, + int scope) { } + + @Override + public void onInterfaceAdded(@NonNull String ifName) { } + + @Override + public void onInterfaceRemoved(@NonNull String ifName) { } + + @Override + public void onInterfaceChanged(@NonNull String ifName, boolean up) { } + + @Override + public void onInterfaceLinkStateChanged(@NonNull String ifName, boolean up) { } + + @Override + public void onRouteChanged(boolean updated, @NonNull String route, @NonNull String gateway, + @NonNull String ifName) { } + + @Override + public void onStrictCleartextDetected(int uid, @NonNull String hex) { } + + @Override + public int getInterfaceVersion() { + return INetdUnsolicitedEventListener.VERSION; + } + + @Override + public String getInterfaceHash() { + return INetdUnsolicitedEventListener.HASH; + } +} From caf7014b2fc221afd29d8a37592ccfd1e5ad435e Mon Sep 17 00:00:00 2001 From: paulhu Date: Mon, 11 Jan 2021 00:24:46 +0800 Subject: [PATCH 100/777] Add PermissionUtils Lots of methods are needed to check if the caller has any of permission. So add PermissionUtils to support enforceAnyPermissionOf() and checkAnyPermissionOf() usage. Bug: 177187957 Test: buid, flash, boot to home. Change-Id: Ie282989f1e73b614093feff28c497af6573a9ef8 --- .../net/module/util/PermissionUtils.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 staticlibs/framework/com/android/net/module/util/PermissionUtils.java diff --git a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java new file mode 100644 index 0000000000..ce8a74549b --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java @@ -0,0 +1,52 @@ +/* + * Copyright 2021 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 com.android.net.module.util; + +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + +import android.annotation.NonNull; +import android.content.Context; + +/** + * Collection of permission utilities. + * @hide + */ +public final class PermissionUtils { + /** + * Return true if the context has one of given permission. + */ + public static boolean checkAnyPermissionOf(@NonNull Context context, + @NonNull String... permissions) { + for (String permission : permissions) { + if (context.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) { + return true; + } + } + return false; + } + + /** + * Enforce permission check on the context that should have one of given permission. + */ + public static void enforceAnyPermissionOf(@NonNull Context context, + @NonNull String... permissions) { + if (!checkAnyPermissionOf(context, permissions)) { + throw new SecurityException("Requires one of the following permissions: " + + String.join(", ", permissions) + "."); + } + } +} From 6f99e869ef8fd8bf193a4e5133fb45b7ca56a13e Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 12 Jan 2021 16:03:22 +0900 Subject: [PATCH 101/777] [NS01] Add scoreless methods for non-score users Test: FrameworksNetTests NetworkStackTests Change-Id: I9ebd5cf17ec96b3e7c09ff041d65ee88d0b37cbf --- .../device/android/net/NetworkFactory.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/staticlibs/device/android/net/NetworkFactory.java b/staticlibs/device/android/net/NetworkFactory.java index 55edd293de..4ddb0dac0a 100644 --- a/staticlibs/device/android/net/NetworkFactory.java +++ b/staticlibs/device/android/net/NetworkFactory.java @@ -244,6 +244,12 @@ public class NetworkFactory extends Handler { evalRequests(); } + /** @deprecated None of the implementors use the score, remove this method */ + @Deprecated + public boolean acceptRequest(NetworkRequest request, int score) { + return true; + } + /** * Overridable function to provide complex filtering. * Called for every request every time a new NetworkRequest is seen @@ -263,7 +269,7 @@ public class NetworkFactory extends Handler { * * @return {@code true} to accept the request. */ - public boolean acceptRequest(NetworkRequest request, int score) { + public boolean acceptRequest(NetworkRequest request) { return true; } @@ -357,11 +363,17 @@ public class NetworkFactory extends Handler { protected void startNetwork() { } protected void stopNetwork() { } - // override to do fancier stuff + /** @deprecated none of the implementors use the score : migrate them */ + @Deprecated protected void needNetworkFor(NetworkRequest networkRequest, int score) { if (++mRefCount == 1) startNetwork(); } + // override to do fancier stuff + protected void needNetworkFor(NetworkRequest networkRequest) { + needNetworkFor(networkRequest, 0); + } + protected void releaseNetworkFor(NetworkRequest networkRequest) { if (--mRefCount == 0) stopNetwork(); } From 5b76d8d7dc1ef7b1af5deb9b84fedf73b58a8be4 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 13 Jan 2021 16:01:06 +0900 Subject: [PATCH 102/777] [NS01.5] Fix an embarrassing bug The existing implementations override the function with the int, so the default impl of the function with the int has to call the new one, not the other way around. Otherwise, when implementations are migrated to overriding the new one the old code continues to call the function with the int and that wouldn't work as expected if it didn't call the newly overridden method. Test: TH Change-Id: Ic31cec6481781e0185a0ba150be52390597737e7 --- staticlibs/device/android/net/NetworkFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/device/android/net/NetworkFactory.java b/staticlibs/device/android/net/NetworkFactory.java index 4ddb0dac0a..4bc45cfce2 100644 --- a/staticlibs/device/android/net/NetworkFactory.java +++ b/staticlibs/device/android/net/NetworkFactory.java @@ -366,12 +366,12 @@ public class NetworkFactory extends Handler { /** @deprecated none of the implementors use the score : migrate them */ @Deprecated protected void needNetworkFor(NetworkRequest networkRequest, int score) { - if (++mRefCount == 1) startNetwork(); + needNetworkFor(networkRequest); } // override to do fancier stuff protected void needNetworkFor(NetworkRequest networkRequest) { - needNetworkFor(networkRequest, 0); + if (++mRefCount == 1) startNetwork(); } protected void releaseNetworkFor(NetworkRequest networkRequest) { From a728a7049796fa8adb32571bee759dbc0ab7b3c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Mon, 11 Jan 2021 19:08:33 -0800 Subject: [PATCH 103/777] Wrap BPF system calls into a versioned module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This isn't new code, this is basically copied verbatim from //system/bpf/libbpf_android/include/bpf/BpfUtils.h Test: atest BpfMapTest, TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I80523c9ee0c1e4431f3192eb409ad68c737390a6 --- .../native/bpf_syscall_wrappers/Android.bp | 35 ++++ .../include/BpfSyscallWrappers.h | 149 ++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 staticlibs/native/bpf_syscall_wrappers/Android.bp create mode 100644 staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp new file mode 100644 index 0000000000..ae6eee0ddf --- /dev/null +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -0,0 +1,35 @@ +// Copyright (C) 2021 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. + +cc_library_headers { + name: "bpf_syscall_wrappers", + vendor_available: false, + host_supported: false, + native_bridge_supported: true, + export_include_dirs: ["include"], + cflags: [ + "-Wall", + "-Werror", + ], + sdk_version: "30", + min_sdk_version: "30", + apex_available: [ + "//apex_available:platform", + "com.android.tethering", + ], + visibility: [ + "//packages/modules/Connectivity/Tethering", + "//system/bpf/libbpf_android", + ], +} diff --git a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h new file mode 100644 index 0000000000..72eebf3cb2 --- /dev/null +++ b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2021 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. + */ + +#pragma once + +#include +#include + +#ifdef BPF_FD_JUST_USE_INT + #define BPF_FD_TYPE int + #define BPF_FD_TO_U32(x) static_cast<__u32>(x) +#else + #include + #define BPF_FD_TYPE base::unique_fd& + #define BPF_FD_TO_U32(x) static_cast<__u32>((x).get()) +#endif + +#define ptr_to_u64(x) ((uint64_t)(uintptr_t)(x)) + +namespace android { +namespace bpf { + +/* Note: bpf_attr is a union which might have a much larger size then the anonymous struct portion + * of it that we are using. The kernel's bpf() system call will perform a strict check to ensure + * all unused portions are zero. It will fail with E2BIG if we don't fully zero bpf_attr. + */ + +inline int bpf(int cmd, const bpf_attr& attr) { + return syscall(__NR_bpf, cmd, &attr, sizeof(attr)); +} + +inline int createMap(bpf_map_type map_type, uint32_t key_size, uint32_t value_size, + uint32_t max_entries, uint32_t map_flags) { + return bpf(BPF_MAP_CREATE, { + .map_type = map_type, + .key_size = key_size, + .value_size = value_size, + .max_entries = max_entries, + .map_flags = map_flags, + }); +} + +inline int writeToMapEntry(const BPF_FD_TYPE map_fd, const void* key, const void* value, + uint64_t flags) { + return bpf(BPF_MAP_UPDATE_ELEM, { + .map_fd = BPF_FD_TO_U32(map_fd), + .key = ptr_to_u64(key), + .value = ptr_to_u64(value), + .flags = flags, + }); +} + +inline int findMapEntry(const BPF_FD_TYPE map_fd, const void* key, void* value) { + return bpf(BPF_MAP_LOOKUP_ELEM, { + .map_fd = BPF_FD_TO_U32(map_fd), + .key = ptr_to_u64(key), + .value = ptr_to_u64(value), + }); +} + +inline int deleteMapEntry(const BPF_FD_TYPE map_fd, const void* key) { + return bpf(BPF_MAP_DELETE_ELEM, { + .map_fd = BPF_FD_TO_U32(map_fd), + .key = ptr_to_u64(key), + }); +} + +inline int getNextMapKey(const BPF_FD_TYPE map_fd, const void* key, void* next_key) { + return bpf(BPF_MAP_GET_NEXT_KEY, { + .map_fd = BPF_FD_TO_U32(map_fd), + .key = ptr_to_u64(key), + .next_key = ptr_to_u64(next_key), + }); +} + +inline int getFirstMapKey(const BPF_FD_TYPE map_fd, void* firstKey) { + return getNextMapKey(map_fd, NULL, firstKey); +} + +inline int bpfFdPin(const BPF_FD_TYPE map_fd, const char* pathname) { + return bpf(BPF_OBJ_PIN, { + .pathname = ptr_to_u64(pathname), + .bpf_fd = BPF_FD_TO_U32(map_fd), + }); +} + +inline int bpfFdGet(const char* pathname, uint32_t flag) { + return bpf(BPF_OBJ_GET, { + .pathname = ptr_to_u64(pathname), + .file_flags = flag, + }); +} + +inline int mapRetrieve(const char* pathname, uint32_t flag) { + return bpfFdGet(pathname, flag); +} + +inline int mapRetrieveRW(const char* pathname) { + return mapRetrieve(pathname, 0); +} + +inline int mapRetrieveRO(const char* pathname) { + return mapRetrieve(pathname, BPF_F_RDONLY); +} + +inline int mapRetrieveWO(const char* pathname) { + return mapRetrieve(pathname, BPF_F_WRONLY); +} + +inline int retrieveProgram(const char* pathname) { + return bpfFdGet(pathname, BPF_F_RDONLY); +} + +inline int attachProgram(bpf_attach_type type, const BPF_FD_TYPE prog_fd, + const BPF_FD_TYPE cg_fd) { + return bpf(BPF_PROG_ATTACH, { + .target_fd = BPF_FD_TO_U32(cg_fd), + .attach_bpf_fd = BPF_FD_TO_U32(prog_fd), + .attach_type = type, + }); +} + +inline int detachProgram(bpf_attach_type type, const BPF_FD_TYPE cg_fd) { + return bpf(BPF_PROG_DETACH, { + .target_fd = BPF_FD_TO_U32(cg_fd), + .attach_type = type, + }); +} + +} // namespace bpf +} // namespace android + +#undef ptr_to_u64 +#undef BPF_FD_TO_U32 +#undef BPF_FD_TYPE +#undef BPF_FD_JUST_USE_INT From 312b5519a204abf463f54f5ca4c95cc3c3e6fa74 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 15 Jan 2021 14:36:44 +0900 Subject: [PATCH 104/777] Fix an embarrassing bug... again. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the same reason as aosp/1549479, the old method needs to call the new one. It's not enough that they have the same implementation ; when NF calls the old one, it needs to indeed call the overridden new version. Test: TH Change-Id: I5e8700fc7455317da382f2328e3f548b3392ca41 --- staticlibs/device/android/net/NetworkFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/device/android/net/NetworkFactory.java b/staticlibs/device/android/net/NetworkFactory.java index 4bc45cfce2..bcc60897b4 100644 --- a/staticlibs/device/android/net/NetworkFactory.java +++ b/staticlibs/device/android/net/NetworkFactory.java @@ -247,7 +247,7 @@ public class NetworkFactory extends Handler { /** @deprecated None of the implementors use the score, remove this method */ @Deprecated public boolean acceptRequest(NetworkRequest request, int score) { - return true; + return acceptRequest(request); } /** From ef9fd0ae5916d771f7a5cf399e2406e06bae798e Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 15 Jan 2021 07:24:57 +0000 Subject: [PATCH 105/777] Make a copy of HexDump in the frameworks/libs/net. Make HexDump as a part of module-shared library, being able to share among of modules. As the first step, moving it to frameworks/libs/net and be able to use inside net-utils-device-common. Bug: 177622619 Test: m Change-Id: I640f343dc6c334b7b4d44960cd043e32a989898d --- .../com/android/net/module/util/HexDump.java | 239 ++++++++++++++++++ .../android/net/module/util/HexDumpTest.java | 72 ++++++ 2 files changed, 311 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/HexDump.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/HexDumpTest.java diff --git a/staticlibs/device/com/android/net/module/util/HexDump.java b/staticlibs/device/com/android/net/module/util/HexDump.java new file mode 100644 index 0000000000..d8c0fb5625 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/HexDump.java @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util; + +import android.annotation.Nullable; + +/** + * Hex utility functions. + * + * A copy from frameworks/base/core/java/com/android/internal/util/HexDump.java, to be shared + * by multiple modules. + */ +public class HexDump { + private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' }; + private static final char[] HEX_LOWER_CASE_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + + /** + * Dump the hex string corresponding to the specified byte array. + * + * @param array byte array to be dumped. + */ + public static String dumpHexString(@Nullable byte[] array) { + if (array == null) return "(null)"; + return dumpHexString(array, 0, array.length); + } + + /** + * Dump the hex string corresponding to the specified byte array. + * + * @param array byte array to be dumped. + * @param offset the offset in array where dump should start. + * @param length the length of bytes to be dumped. + */ + public static String dumpHexString(@Nullable byte[] array, int offset, int length) { + if (array == null) return "(null)"; + StringBuilder result = new StringBuilder(); + + byte[] line = new byte[16]; + int lineIndex = 0; + + result.append("\n0x"); + result.append(toHexString(offset)); + + for (int i = offset; i < offset + length; i++) { + if (lineIndex == 16) { + result.append(" "); + + for (int j = 0; j < 16; j++) { + if (line[j] > ' ' && line[j] < '~') { + result.append(new String(line, j, 1)); + } else { + result.append("."); + } + } + + result.append("\n0x"); + result.append(toHexString(i)); + lineIndex = 0; + } + + byte b = array[i]; + result.append(" "); + result.append(HEX_DIGITS[(b >>> 4) & 0x0F]); + result.append(HEX_DIGITS[b & 0x0F]); + + line[lineIndex++] = b; + } + + if (lineIndex != 16) { + int count = (16 - lineIndex) * 3; + count++; + for (int i = 0; i < count; i++) { + result.append(" "); + } + + for (int i = 0; i < lineIndex; i++) { + if (line[i] > ' ' && line[i] < '~') { + result.append(new String(line, i, 1)); + } else { + result.append("."); + } + } + } + + return result.toString(); + } + + /** + * Convert a byte to an uppercase hex string. + * + * @param b the byte to be converted. + */ + public static String toHexString(byte b) { + return toHexString(toByteArray(b)); + } + + /** + * Convert a byte array to an uppercase hex string. + * + * @param array the byte array to be converted. + */ + public static String toHexString(byte[] array) { + return toHexString(array, 0, array.length, true); + } + + /** + * Convert a byte array to a hex string. + * + * @param array the byte array to be converted. + * @param upperCase whether the converted hex string should be uppercase or not. + */ + public static String toHexString(byte[] array, boolean upperCase) { + return toHexString(array, 0, array.length, upperCase); + } + + /** + * Convert a byte array to hex string. + * + * @param array the byte array to be converted. + * @param offset the offset in array where conversion should start. + * @param length the length of bytes to be converted. + */ + public static String toHexString(byte[] array, int offset, int length) { + return toHexString(array, offset, length, true); + } + + /** + * Convert a byte array to hex string. + * + * @param array the byte array to be converted. + * @param offset the offset in array where conversion should start. + * @param length the length of bytes to be converted. + * @param upperCase whether the converted hex string should be uppercase or not. + */ + public static String toHexString(byte[] array, int offset, int length, boolean upperCase) { + char[] digits = upperCase ? HEX_DIGITS : HEX_LOWER_CASE_DIGITS; + char[] buf = new char[length * 2]; + + int bufIndex = 0; + for (int i = offset; i < offset + length; i++) { + byte b = array[i]; + buf[bufIndex++] = digits[(b >>> 4) & 0x0F]; + buf[bufIndex++] = digits[b & 0x0F]; + } + + return new String(buf); + } + + /** + * Convert an integer to hex string. + * + * @param i the integer to be converted. + */ + public static String toHexString(int i) { + return toHexString(toByteArray(i)); + } + + /** + * Convert a byte to byte array. + * + * @param b the byte to be converted. + */ + public static byte[] toByteArray(byte b) { + byte[] array = new byte[1]; + array[0] = b; + return array; + } + + /** + * Convert an integer to byte array. + * + * @param i the integer to be converted. + */ + public static byte[] toByteArray(int i) { + byte[] array = new byte[4]; + + array[3] = (byte) (i & 0xFF); + array[2] = (byte) ((i >> 8) & 0xFF); + array[1] = (byte) ((i >> 16) & 0xFF); + array[0] = (byte) ((i >> 24) & 0xFF); + + return array; + } + + private static int toByte(char c) { + if (c >= '0' && c <= '9') return (c - '0'); + if (c >= 'A' && c <= 'F') return (c - 'A' + 10); + if (c >= 'a' && c <= 'f') return (c - 'a' + 10); + + throw new RuntimeException("Invalid hex char '" + c + "'"); + } + + /** + * Convert a hex string to a byte array. + * + * @param hexString the string to be converted. + */ + public static byte[] hexStringToByteArray(String hexString) { + int length = hexString.length(); + byte[] buffer = new byte[length / 2]; + + for (int i = 0; i < length; i += 2) { + buffer[i / 2] = + (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(hexString.charAt(i + 1))); + } + + return buffer; + } + + /** + * Convert a byte to hex string and append it to StringBuilder. + * + * @param sb StringBuilder instance. + * @param b the byte to be converted. + * @param upperCase whether the converted hex string should be uppercase or not. + */ + public static StringBuilder appendByteAsHex(StringBuilder sb, byte b, boolean upperCase) { + char[] digits = upperCase ? HEX_DIGITS : HEX_LOWER_CASE_DIGITS; + sb.append(digits[(b >> 4) & 0xf]); + sb.append(digits[b & 0xf]); + return sb; + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/HexDumpTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/HexDumpTest.java new file mode 100644 index 0000000000..7e6c7e2157 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/HexDumpTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class HexDumpTest { + @Test + public void testBytesToHexString() { + assertEquals("abcdef", HexDump.toHexString( + new byte[]{(byte) 0xab, (byte) 0xcd, (byte) 0xef}, false)); + assertEquals("ABCDEF", HexDump.toHexString( + new byte[]{(byte) 0xab, (byte) 0xcd, (byte) 0xef}, true)); + } + + @Test + public void testNullArray() { + assertEquals("(null)", HexDump.dumpHexString(null)); + } + + @Test + public void testHexStringToBytes() { + assertArrayEquals(new byte[]{(byte) 0xab, (byte) 0xcd, (byte) 0xef}, + HexDump.hexStringToByteArray("abcdef")); + assertArrayEquals(new byte[]{(byte) 0xAB, (byte) 0xCD, (byte) 0xEF}, + HexDump.hexStringToByteArray("ABCDEF")); + } + + @Test + public void testIntegerToBytes() { + assertArrayEquals(new byte[]{(byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x04}, + HexDump.toByteArray((int) 0xff000004)); + } + + @Test + public void testByteToBytes() { + assertArrayEquals(new byte[]{(byte) 0x7f}, HexDump.toByteArray((byte) 0x7f)); + } + + @Test + public void testIntegerToHexString() { + assertEquals("FF000004", HexDump.toHexString((int) 0xff000004)); + } + + @Test + public void testByteToHexString() { + assertEquals("7F", HexDump.toHexString((byte) 0x7f)); + } +} From 01c0fe54530fc20214d5e927c64b77b56db7c4ad Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Mon, 28 Dec 2020 09:45:31 +0000 Subject: [PATCH 106/777] Implement generic toString/equals/hashCode in Struct. Bug: 163492391 Test: atest NetworkStaticLibTests Change-Id: I485e0bbc6949c1eb239d52401ff0403dd447619b --- .../com/android/net/module/util/Struct.java | 75 +++++- .../android/net/module/util/StructTest.java | 231 +++++++++++++++++- 2 files changed, 304 insertions(+), 2 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/Struct.java b/staticlibs/device/com/android/net/module/util/Struct.java index 07a7e7aa87..afc2e646d9 100644 --- a/staticlibs/device/com/android/net/module/util/Struct.java +++ b/staticlibs/device/com/android/net/module/util/Struct.java @@ -30,6 +30,8 @@ import java.math.BigInteger; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.Arrays; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; /** @@ -111,7 +113,7 @@ public class Struct { UBE63, // unsigned long(MSB: 0) in network order, size = 8 bytes UBE64, // unsigned long in network order, size = 8 bytes ByteArray, // byte array with predefined length - EUI48, // a 48-bits long MAC address + EUI48, // IEEE Extended Unique Identifier, a 48-bits long MAC address in network order } /** @@ -607,4 +609,75 @@ public class Struct { public final byte[] writeToBytes() { return writeToBytes(ByteOrder.nativeOrder()); } + + @Override + public boolean equals(Object obj) { + if (obj == null || this.getClass() != obj.getClass()) return false; + + final FieldInfo[] fieldInfos = getClassFieldInfo(this.getClass()); + for (int i = 0; i < fieldInfos.length; i++) { + try { + final Object value = fieldInfos[i].field.get(this); + final Object otherValue = fieldInfos[i].field.get(obj); + + // Use Objects#deepEquals because the equals method on arrays does not check the + // contents of the array. The only difference between Objects#deepEquals and + // Objects#equals is that the former will call Arrays#deepEquals when comparing + // arrays. In turn, the only difference between Arrays#deepEquals is that it + // supports nested arrays. Struct does not currently support these, and if it did, + // Objects#deepEquals might be more correct. + if (!Objects.deepEquals(value, otherValue)) return false; + } catch (IllegalAccessException e) { + throw new IllegalStateException("Cannot access field: " + fieldInfos[i].field, e); + } + } + return true; + } + + @Override + public int hashCode() { + final FieldInfo[] fieldInfos = getClassFieldInfo(this.getClass()); + final Object[] values = new Object[fieldInfos.length]; + for (int i = 0; i < fieldInfos.length; i++) { + final Object value; + try { + value = fieldInfos[i].field.get(this); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Cannot access field: " + fieldInfos[i].field, e); + } + // For byte array field, put the hash code generated based on the array content into + // the Object array instead of the reference to byte array, which might change and cause + // to get a different hash code even with the exact same elements. + if (fieldInfos[i].field.getType() == byte[].class) { + values[i] = Arrays.hashCode((byte[]) value); + } else { + values[i] = value; + } + } + return Objects.hash(values); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + final FieldInfo[] fieldInfos = getClassFieldInfo(this.getClass()); + for (int i = 0; i < fieldInfos.length; i++) { + sb.append(fieldInfos[i].field.getName()).append(": "); + final Object value; + try { + value = fieldInfos[i].field.get(this); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Cannot access field: " + fieldInfos[i].field, e); + } + if (value == null) { + sb.append("null"); + } else if (fieldInfos[i].field.getType() == byte[].class) { + sb.append("0x").append(HexDump.toHexString((byte[]) value)); + } else { + sb.append(value.toString()); + } + if (i != fieldInfos.length - 1) sb.append(", "); + } + return sb.toString(); + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java index d5e27fb333..253b9118b9 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java @@ -20,6 +20,8 @@ import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import android.net.IpPrefix; @@ -67,6 +69,10 @@ public class StructTest { // PREF64 option, 2001:db8:3:4:5:6::/96, lifetime: 10064 private static final String OPT_PREF64 = "2750" + "20010db80003000400050006"; + private static final byte[] TEST_PREFIX64 = new byte[]{ + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, (byte) 0x00, (byte) 0x03, + (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x06, + }; private T doParsingMessageTest(final String hexString, final Class clazz, final ByteOrder order) { @@ -699,7 +705,7 @@ public class StructTest { } @Test - public void testStructToByteArray() { + public void testStructToByteArrayRoundTrip() { final SignedDataMessage littleEndianMsg = doParsingMessageTest(SIGNED_DATA, SignedDataMessage.class, ByteOrder.LITTLE_ENDIAN); assertArrayEquals(toByteBuffer(SIGNED_DATA).array(), @@ -714,6 +720,229 @@ public class StructTest { ByteOrder.LITTLE_ENDIAN) ? littleEndianMsg : bigEndianMsg; assertArrayEquals(toByteBuffer(SIGNED_DATA).array(), nativeOrderMsg.writeToBytes()); + } + + @Test + public void testStructToByteArray() { + final SignedDataMessage msg = new SignedDataMessage((byte) -5, (short) 42, (int) 0xff000004, + (long) 0xff000004ff000005L); + final String leHexString = "fb" + "2a00" + "040000ff" + "050000ff040000ff"; + final String beHexString = "fb" + "002a" + "ff000004" + "ff000004ff000005"; + final String hexString = ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN) + ? leHexString : beHexString; + assertArrayEquals(toByteBuffer(hexString).array(), msg.writeToBytes()); + } + + static class FullTypeMessage extends Struct { + @Field(order = 0, type = Type.U8) public final short u8; + @Field(order = 1, type = Type.U16) public final int u16; + @Field(order = 2, type = Type.U32) public final long u32; + @Field(order = 3, type = Type.U63) public final long u63; + @Field(order = 4, type = Type.U64) public final BigInteger u64; + @Field(order = 5, type = Type.S8) public final byte s8; + @Field(order = 6, type = Type.S16) public final short s16; + @Field(order = 7, type = Type.S32) public final int s32; + @Field(order = 8, type = Type.S64) public final long s64; + @Field(order = 9, type = Type.UBE16) public final int ube16; + @Field(order = 10, type = Type.UBE32) public final long ube32; + @Field(order = 11, type = Type.UBE63) public final long ube63; + @Field(order = 12, type = Type.UBE64) public final BigInteger ube64; + @Field(order = 13, type = Type.ByteArray, arraysize = 12) public final byte[] bytes; + @Field(order = 14, type = Type.EUI48) public final MacAddress eui48; + + FullTypeMessage(final short u8, final int u16, final long u32, final long u63, + final BigInteger u64, final byte s8, final short s16, final int s32, final long s64, + final int ube16, final long ube32, final long ube63, final BigInteger ube64, + final byte[] bytes, final MacAddress eui48) { + this.u8 = u8; + this.u16 = u16; + this.u32 = u32; + this.u63 = u63; + this.u64 = u64; + this.s8 = s8; + this.s16 = s16; + this.s32 = s32; + this.s64 = s64; + this.ube16 = ube16; + this.ube32 = ube32; + this.ube63 = ube63; + this.ube64 = ube64; + this.bytes = bytes; + this.eui48 = eui48; + } + } + + private static final String FULL_TYPE_DATA = "ff" + "ffff" + "ffffffff" + "7fffffffffffffff" + + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + "7fffffffffffffff" + "7fff" + + "7fffffff" + "7fffffffffffffff" + "ffffffffffffffff" + "20010db80003000400050006" + + "001122334455"; + private static final String FULL_TYPE_DATA_DIFF_MAC = "ff" + "ffff" + "ffffffff" + + "7fffffffffffffff" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + + "7fffffffffffffff" + "7fff" + "7fffffff" + "7fffffffffffffff" + "ffffffffffffffff" + + "20010db80003000400050006" + "112233445566"; + private static final String FULL_TYPE_DATA_DIFF_LONG = "ff" + "ffff" + "ffffffff" + + "7ffffffffffffffe" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + + "7fffffffffffffff" + "7fff" + "7fffffff" + "7fffffffffffffff" + "ffffffffffffffff" + + "20010db80003000400050006" + "001122334455"; + private static final String FULL_TYPE_DATA_DIFF_INTEGER = "ff" + "ffff" + "ffffffff" + + "7fffffffffffffff" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + + "7fffffffffffffff" + "7fff" + "ffffff7f" + "7fffffffffffffff" + "ffffffffffffffff" + + "20010db80003000400050006" + "001122334455"; + @Test + public void testStructClass_equals() { + final FullTypeMessage msg = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class, + ByteOrder.BIG_ENDIAN); + + assertEquals(255, msg.u8); + assertEquals(65535, msg.u16); + assertEquals(4294967295L, msg.u32); + assertEquals(9223372036854775807L, msg.u63); + assertEquals(new BigInteger("18446744073709551615"), msg.u64); + assertEquals(127, msg.s8); + assertEquals(32767, msg.s16); + assertEquals(2147483647, msg.s32); + assertEquals(9223372036854775807L, msg.s64); + assertEquals(32767, msg.ube16); + assertEquals(2147483647, msg.ube32); + assertEquals(9223372036854775807L, msg.ube63); + assertEquals(new BigInteger("18446744073709551615"), msg.ube64); + assertArrayEquals(TEST_PREFIX64, msg.bytes); + assertEquals(MacAddress.fromString("00:11:22:33:44:55"), msg.eui48); + + assertEquals(78, msg.getSize(FullTypeMessage.class)); + assertArrayEquals(toByteBuffer(FULL_TYPE_DATA).array(), + msg.writeToBytes(ByteOrder.BIG_ENDIAN)); + + final FullTypeMessage msg1 = new FullTypeMessage((short) 0xff, (int) 0xffff, + (long) 0xffffffffL, (long) 0x7fffffffffffffffL, + new BigInteger("18446744073709551615"), (byte) 0x7f, (short) 0x7fff, + (int) 0x7fffffff, (long) 0x7fffffffffffffffL, (int) 0x7fff, (long) 0x7fffffffL, + (long) 0x7fffffffffffffffL, new BigInteger("18446744073709551615"), TEST_PREFIX64, + MacAddress.fromString("00:11:22:33:44:55")); + assertTrue(msg.equals(msg1)); + } + + static class FullTypeMessageWithDupType extends Struct { + @Field(order = 0, type = Type.U8) public final short u8; + @Field(order = 1, type = Type.U16) public final int u16; + @Field(order = 2, type = Type.U32) public final long u32; + @Field(order = 3, type = Type.S64) public final long u63; // old: U63, new: S64 + @Field(order = 4, type = Type.UBE64) public final BigInteger u64; // old: U64, new: UBE64 + @Field(order = 5, type = Type.S8) public final byte s8; + @Field(order = 6, type = Type.S16) public final short s16; + @Field(order = 7, type = Type.S32) public final int s32; + @Field(order = 8, type = Type.S64) public final long s64; + @Field(order = 9, type = Type.U16) public final int ube16; // old:UBE16, new: U16 + @Field(order = 10, type = Type.UBE32) public final long ube32; + @Field(order = 11, type = Type.UBE63) public final long ube63; + @Field(order = 12, type = Type.UBE64) public final BigInteger ube64; + @Field(order = 13, type = Type.ByteArray, arraysize = 12) public final byte[] bytes; + @Field(order = 14, type = Type.EUI48) public final MacAddress eui48; + + FullTypeMessageWithDupType(final short u8, final int u16, final long u32, final long u63, + final BigInteger u64, final byte s8, final short s16, final int s32, final long s64, + final int ube16, final long ube32, final long ube63, final BigInteger ube64, + final byte[] bytes, final MacAddress eui48) { + this.u8 = u8; + this.u16 = u16; + this.u32 = u32; + this.u63 = u63; + this.u64 = u64; + this.s8 = s8; + this.s16 = s16; + this.s32 = s32; + this.s64 = s64; + this.ube16 = ube16; + this.ube32 = ube32; + this.ube63 = ube63; + this.ube64 = ube64; + this.bytes = bytes; + this.eui48 = eui48; + } + } + + @Test + public void testStructClass_notEqualWithDifferentClass() { + final FullTypeMessage msg = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class, + ByteOrder.BIG_ENDIAN); + final FullTypeMessageWithDupType msg1 = doParsingMessageTest(FULL_TYPE_DATA, + FullTypeMessageWithDupType.class, ByteOrder.BIG_ENDIAN); + + assertFalse(msg.equals(msg1)); + } + + @Test + public void testStructClass_notEqualWithDifferentValue() { + final FullTypeMessage msg = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class, + ByteOrder.BIG_ENDIAN); + + // With different MAC address. + final FullTypeMessage msg1 = doParsingMessageTest(FULL_TYPE_DATA_DIFF_MAC, + FullTypeMessage.class, ByteOrder.BIG_ENDIAN); + assertNotEquals(msg.eui48, msg1.eui48); + assertFalse(msg.equals(msg1)); + + // With different byte array. + final FullTypeMessage msg2 = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class, + ByteOrder.BIG_ENDIAN); + msg2.bytes[5] = (byte) 42; // change one byte in the array. + assertFalse(msg.equals(msg2)); + + // With different Long primitive. + final FullTypeMessage msg3 = doParsingMessageTest(FULL_TYPE_DATA_DIFF_LONG, + FullTypeMessage.class, ByteOrder.BIG_ENDIAN); + assertNotEquals(msg.u63, msg3.u63); + assertFalse(msg.equals(msg3)); + + // With different Integer primitive. + final FullTypeMessage msg4 = doParsingMessageTest(FULL_TYPE_DATA_DIFF_INTEGER, + FullTypeMessage.class, ByteOrder.BIG_ENDIAN); + assertNotEquals(msg.ube32, msg4.ube32); + assertFalse(msg.equals(msg4)); } + + @Test + public void testStructClass_toString() { + final String expected = "u8: 255, u16: 65535, u32: 4294967295," + + " u63: 9223372036854775807, u64: 18446744073709551615, s8: 127, s16: 32767," + + " s32: 2147483647, s64: 9223372036854775807, ube16: 32767, ube32: 2147483647," + + " ube63: 9223372036854775807, ube64: 18446744073709551615," + + " bytes: 0x20010DB80003000400050006," + + " eui48: 00:11:22:33:44:55"; + + final FullTypeMessage msg = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class, + ByteOrder.BIG_ENDIAN); + assertEquals(expected, msg.toString()); + } + + @Test + public void testStructClass_toStringWithNullMember() { + final String expected = "u8: 255, u16: 65535, u32: 4294967295," + + " u63: 9223372036854775807, u64: null, s8: 127, s16: 32767," + + " s32: 2147483647, s64: 9223372036854775807, ube16: 32767, ube32: 2147483647," + + " ube63: 9223372036854775807, ube64: 18446744073709551615," + + " bytes: null, eui48: null"; + + final FullTypeMessage msg = new FullTypeMessage((short) 0xff, (int) 0xffff, + (long) 0xffffffffL, (long) 0x7fffffffffffffffL, + null /* u64 */, (byte) 0x7f, (short) 0x7fff, + (int) 0x7fffffff, (long) 0x7fffffffffffffffL, (int) 0x7fff, (long) 0x7fffffffL, + (long) 0x7fffffffffffffffL, new BigInteger("18446744073709551615"), + null /* bytes */, null /* eui48 */); + assertEquals(expected, msg.toString()); + } + + @Test + public void testStructClass_hashcode() { + final FullTypeMessage msg = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class, + ByteOrder.BIG_ENDIAN); + final FullTypeMessage msg1 = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class, + ByteOrder.BIG_ENDIAN); + + assertNotEquals(0, msg.hashCode()); + assertNotEquals(0, msg1.hashCode()); + assertTrue(msg.equals(msg1)); + assertEquals(msg.hashCode(), msg1.hashCode()); + } } From 0d05d57b89fa76364c12510ed8eeb01fdaac99dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 19 Jan 2021 18:33:35 -0800 Subject: [PATCH 107/777] add maze to OWNERS for common/native MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (there's bpf related stuff in here) Test: N/A Signed-off-by: Maciej Żenczykowski Change-Id: I7fcc19cdf48e468dfcbe5ee34f7bc07e261756b8 --- staticlibs/native/OWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 staticlibs/native/OWNERS diff --git a/staticlibs/native/OWNERS b/staticlibs/native/OWNERS new file mode 100644 index 0000000000..76553385b4 --- /dev/null +++ b/staticlibs/native/OWNERS @@ -0,0 +1 @@ +maze@google.com From 229b17ac0c38eff8959d6be3977edad7bd39e17c Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Mon, 28 Dec 2020 14:11:04 +0000 Subject: [PATCH 108/777] Support IPv4/6 address type in Struct. Bug: 163492391 Test: atest NetworkStaticLibTests Change-Id: I17a753ea495f24d186b69083923a71a7ebccdc7b --- .../com/android/net/module/util/HexDump.java | 3 - .../com/android/net/module/util/Struct.java | 69 +++++++++--- .../android/net/module/util/HexDumpTest.java | 6 +- .../android/net/module/util/StructTest.java | 104 ++++++++++++++++-- 4 files changed, 149 insertions(+), 33 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/HexDump.java b/staticlibs/device/com/android/net/module/util/HexDump.java index d8c0fb5625..6d36487b07 100644 --- a/staticlibs/device/com/android/net/module/util/HexDump.java +++ b/staticlibs/device/com/android/net/module/util/HexDump.java @@ -20,9 +20,6 @@ import android.annotation.Nullable; /** * Hex utility functions. - * - * A copy from frameworks/base/core/java/com/android/internal/util/HexDump.java, to be shared - * by multiple modules. */ public class HexDump { private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', diff --git a/staticlibs/device/com/android/net/module/util/Struct.java b/staticlibs/device/com/android/net/module/util/Struct.java index afc2e646d9..f11a5acea5 100644 --- a/staticlibs/device/com/android/net/module/util/Struct.java +++ b/staticlibs/device/com/android/net/module/util/Struct.java @@ -27,6 +27,10 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.math.BigInteger; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -99,21 +103,23 @@ import java.util.concurrent.ConcurrentHashMap; */ public class Struct { public enum Type { - U8, // unsigned byte, size = 1 byte - U16, // unsigned short, size = 2 bytes - U32, // unsigned int, size = 4 bytes - U63, // unsigned long(MSB: 0), size = 8 bytes - U64, // unsigned long, size = 8 bytes - S8, // signed byte, size = 1 byte - S16, // signed short, size = 2 bytes - S32, // signed int, size = 4 bytes - S64, // signed long, size = 8 bytes - UBE16, // unsigned short in network order, size = 2 bytes - UBE32, // unsigned int in network order, size = 4 bytes - UBE63, // unsigned long(MSB: 0) in network order, size = 8 bytes - UBE64, // unsigned long in network order, size = 8 bytes - ByteArray, // byte array with predefined length - EUI48, // IEEE Extended Unique Identifier, a 48-bits long MAC address in network order + U8, // unsigned byte, size = 1 byte + U16, // unsigned short, size = 2 bytes + U32, // unsigned int, size = 4 bytes + U63, // unsigned long(MSB: 0), size = 8 bytes + U64, // unsigned long, size = 8 bytes + S8, // signed byte, size = 1 byte + S16, // signed short, size = 2 bytes + S32, // signed int, size = 4 bytes + S64, // signed long, size = 8 bytes + UBE16, // unsigned short in network order, size = 2 bytes + UBE32, // unsigned int in network order, size = 4 bytes + UBE63, // unsigned long(MSB: 0) in network order, size = 8 bytes + UBE64, // unsigned long in network order, size = 8 bytes + ByteArray, // byte array with predefined length + EUI48, // IEEE Extended Unique Identifier, a 48-bits long MAC address in network order + Ipv4Address, // IPv4 address in network order + Ipv6Address, // IPv6 address in network order } /** @@ -186,6 +192,12 @@ public class Struct { case EUI48: if (fieldType == MacAddress.class) return; break; + case Ipv4Address: + if (fieldType == Inet4Address.class) return; + break; + case Ipv6Address: + if (fieldType == Inet6Address.class) return; + break; default: throw new IllegalArgumentException("Unknown type" + annotation.type()); } @@ -223,6 +235,12 @@ public class Struct { case EUI48: length = 6; break; + case Ipv4Address: + length = 4; + break; + case Ipv6Address: + length = 16; + break; default: throw new IllegalArgumentException("Unknown type" + annotation.type()); } @@ -388,6 +406,17 @@ public class Struct { buf.get(macAddress); value = MacAddress.fromBytes(macAddress); break; + case Ipv4Address: + case Ipv6Address: + final boolean isIpv6 = (fieldInfo.annotation.type() == Type.Ipv6Address); + final byte[] address = new byte[isIpv6 ? 16 : 4]; + buf.get(address); + try { + value = InetAddress.getByAddress(address); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("illegal length of IP address", e); + } + break; default: throw new IllegalArgumentException("Unknown type:" + fieldInfo.annotation.type()); } @@ -461,6 +490,11 @@ public class Struct { final byte[] macAddress = ((MacAddress) value).toByteArray(); output.put(macAddress); break; + case Ipv4Address: + case Ipv6Address: + final byte[] address = ((InetAddress) value).getAddress(); + output.put(address); + break; default: throw new IllegalArgumentException("Unknown type:" + fieldInfo.annotation.type()); } @@ -671,8 +705,11 @@ public class Struct { } if (value == null) { sb.append("null"); - } else if (fieldInfos[i].field.getType() == byte[].class) { + } else if (fieldInfos[i].annotation.type() == Type.ByteArray) { sb.append("0x").append(HexDump.toHexString((byte[]) value)); + } else if (fieldInfos[i].annotation.type() == Type.Ipv4Address + || fieldInfos[i].annotation.type() == Type.Ipv6Address) { + sb.append(((InetAddress) value).getHostAddress()); } else { sb.append(value.toString()); } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/HexDumpTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/HexDumpTest.java index 7e6c7e2157..5a15585d20 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/HexDumpTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/HexDumpTest.java @@ -42,7 +42,7 @@ public class HexDumpTest { } @Test - public void testHexStringToBytes() { + public void testHexStringToByteArray() { assertArrayEquals(new byte[]{(byte) 0xab, (byte) 0xcd, (byte) 0xef}, HexDump.hexStringToByteArray("abcdef")); assertArrayEquals(new byte[]{(byte) 0xAB, (byte) 0xCD, (byte) 0xEF}, @@ -50,13 +50,13 @@ public class HexDumpTest { } @Test - public void testIntegerToBytes() { + public void testIntegerToByteArray() { assertArrayEquals(new byte[]{(byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x04}, HexDump.toByteArray((int) 0xff000004)); } @Test - public void testByteToBytes() { + public void testByteToByteArray() { assertArrayEquals(new byte[]{(byte) 0x7f}, HexDump.toByteArray((byte) 0x7f)); } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java index 253b9118b9..b172e2142b 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import android.net.InetAddresses; import android.net.IpPrefix; import android.net.MacAddress; @@ -38,6 +39,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.math.BigInteger; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; @@ -74,6 +77,11 @@ public class StructTest { (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x06, }; + private static final Inet4Address TEST_IPV4_ADDRESS = + (Inet4Address) InetAddresses.parseNumericAddress("192.168.100.1"); + private static final Inet6Address TEST_IPV6_ADDRESS = + (Inet6Address) InetAddresses.parseNumericAddress("2001:db8:3:4:5:6:7:8"); + private T doParsingMessageTest(final String hexString, final Class clazz, final ByteOrder order) { final ByteBuffer buf = toByteBuffer(hexString); @@ -733,6 +741,41 @@ public class StructTest { assertArrayEquals(toByteBuffer(hexString).array(), msg.writeToBytes()); } + static class IpAddressMessage extends Struct { + @Field(order = 0, type = Type.Ipv4Address) public final Inet4Address ipv4Address; + @Field(order = 1, type = Type.Ipv6Address) public final Inet6Address ipv6Address; + + IpAddressMessage(final Inet4Address ipv4Address, final Inet6Address ipv6Address) { + this.ipv4Address = ipv4Address; + this.ipv6Address = ipv6Address; + } + } + + @Test + public void testIpAddressType() { + final IpAddressMessage msg = doParsingMessageTest("c0a86401" + + "20010db8000300040005000600070008", IpAddressMessage.class, ByteOrder.BIG_ENDIAN); + + assertEquals(TEST_IPV4_ADDRESS, msg.ipv4Address); + assertEquals(TEST_IPV6_ADDRESS, msg.ipv6Address); + + assertEquals(20, Struct.getSize(IpAddressMessage.class)); + assertArrayEquals(toByteBuffer("c0a86401" + "20010db8000300040005000600070008").array(), + msg.writeToBytes(ByteOrder.BIG_ENDIAN)); + } + + static class WrongIpAddressType extends Struct { + @Field(order = 0, type = Type.Ipv4Address) public byte[] ipv4Address; + @Field(order = 1, type = Type.Ipv6Address) public byte[] ipv6Address; + } + + @Test + public void testIncorrectType_IpAddressWithByteArray() { + assertThrows(IllegalArgumentException.class, + () -> Struct.parse(WrongIpAddressType.class, + toByteBuffer("c0a86401" + "20010db8000300040005000600070008"))); + } + static class FullTypeMessage extends Struct { @Field(order = 0, type = Type.U8) public final short u8; @Field(order = 1, type = Type.U16) public final int u16; @@ -749,11 +792,14 @@ public class StructTest { @Field(order = 12, type = Type.UBE64) public final BigInteger ube64; @Field(order = 13, type = Type.ByteArray, arraysize = 12) public final byte[] bytes; @Field(order = 14, type = Type.EUI48) public final MacAddress eui48; + @Field(order = 15, type = Type.Ipv4Address) public final Inet4Address ipv4Address; + @Field(order = 16, type = Type.Ipv6Address) public final Inet6Address ipv6Address; FullTypeMessage(final short u8, final int u16, final long u32, final long u63, final BigInteger u64, final byte s8, final short s16, final int s32, final long s64, final int ube16, final long ube32, final long ube63, final BigInteger ube64, - final byte[] bytes, final MacAddress eui48) { + final byte[] bytes, final MacAddress eui48, final Inet4Address ipv4Address, + final Inet6Address ipv6Address) { this.u8 = u8; this.u16 = u16; this.u32 = u32; @@ -769,25 +815,40 @@ public class StructTest { this.ube64 = ube64; this.bytes = bytes; this.eui48 = eui48; + this.ipv4Address = ipv4Address; + this.ipv6Address = ipv6Address; } } private static final String FULL_TYPE_DATA = "ff" + "ffff" + "ffffffff" + "7fffffffffffffff" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + "7fffffffffffffff" + "7fff" + "7fffffff" + "7fffffffffffffff" + "ffffffffffffffff" + "20010db80003000400050006" - + "001122334455"; + + "001122334455" + "c0a86401" + "20010db8000300040005000600070008"; private static final String FULL_TYPE_DATA_DIFF_MAC = "ff" + "ffff" + "ffffffff" + "7fffffffffffffff" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + "7fffffffffffffff" + "7fff" + "7fffffff" + "7fffffffffffffff" + "ffffffffffffffff" - + "20010db80003000400050006" + "112233445566"; + + "20010db80003000400050006" + "112233445566" + + "c0a86401" + "20010db8000300040005000600070008"; private static final String FULL_TYPE_DATA_DIFF_LONG = "ff" + "ffff" + "ffffffff" + "7ffffffffffffffe" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + "7fffffffffffffff" + "7fff" + "7fffffff" + "7fffffffffffffff" + "ffffffffffffffff" - + "20010db80003000400050006" + "001122334455"; + + "20010db80003000400050006" + "001122334455" + + "c0a86401" + "20010db8000300040005000600070008"; private static final String FULL_TYPE_DATA_DIFF_INTEGER = "ff" + "ffff" + "ffffffff" + "7fffffffffffffff" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + "7fffffffffffffff" + "7fff" + "ffffff7f" + "7fffffffffffffff" + "ffffffffffffffff" - + "20010db80003000400050006" + "001122334455"; + + "20010db80003000400050006" + "001122334455" + + "c0a86401" + "20010db8000300040005000600070008"; + private static final String FULL_TYPE_DATA_DIFF_IPV4 = "ff" + "ffff" + "ffffffff" + + "7fffffffffffffff" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + + "7fffffffffffffff" + "7fff" + "ffffff7f" + "7fffffffffffffff" + "ffffffffffffffff" + + "20010db80003000400050006" + "001122334455" + + "c0a81010" + "20010db8000300040005000600070008"; + private static final String FULL_TYPE_DATA_DIFF_IPV6 = "ff" + "ffff" + "ffffffff" + + "7fffffffffffffff" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + + "7fffffffffffffff" + "7fff" + "ffffff7f" + "7fffffffffffffff" + "ffffffffffffffff" + + "20010db80003000400050006" + "001122334455" + + "c0a86401" + "20010db800030004000500060007000a"; @Test public void testStructClass_equals() { final FullTypeMessage msg = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class, @@ -808,8 +869,10 @@ public class StructTest { assertEquals(new BigInteger("18446744073709551615"), msg.ube64); assertArrayEquals(TEST_PREFIX64, msg.bytes); assertEquals(MacAddress.fromString("00:11:22:33:44:55"), msg.eui48); + assertEquals(TEST_IPV4_ADDRESS, msg.ipv4Address); + assertEquals(TEST_IPV6_ADDRESS, msg.ipv6Address); - assertEquals(78, msg.getSize(FullTypeMessage.class)); + assertEquals(98, msg.getSize(FullTypeMessage.class)); assertArrayEquals(toByteBuffer(FULL_TYPE_DATA).array(), msg.writeToBytes(ByteOrder.BIG_ENDIAN)); @@ -818,7 +881,7 @@ public class StructTest { new BigInteger("18446744073709551615"), (byte) 0x7f, (short) 0x7fff, (int) 0x7fffffff, (long) 0x7fffffffffffffffL, (int) 0x7fff, (long) 0x7fffffffL, (long) 0x7fffffffffffffffL, new BigInteger("18446744073709551615"), TEST_PREFIX64, - MacAddress.fromString("00:11:22:33:44:55")); + MacAddress.fromString("00:11:22:33:44:55"), TEST_IPV4_ADDRESS, TEST_IPV6_ADDRESS); assertTrue(msg.equals(msg1)); } @@ -838,11 +901,14 @@ public class StructTest { @Field(order = 12, type = Type.UBE64) public final BigInteger ube64; @Field(order = 13, type = Type.ByteArray, arraysize = 12) public final byte[] bytes; @Field(order = 14, type = Type.EUI48) public final MacAddress eui48; + @Field(order = 15, type = Type.Ipv4Address) public final Inet4Address ipv4Address; + @Field(order = 16, type = Type.Ipv6Address) public final Inet6Address ipv6Address; FullTypeMessageWithDupType(final short u8, final int u16, final long u32, final long u63, final BigInteger u64, final byte s8, final short s16, final int s32, final long s64, final int ube16, final long ube32, final long ube63, final BigInteger ube64, - final byte[] bytes, final MacAddress eui48) { + final byte[] bytes, final MacAddress eui48, final Inet4Address ipv4Address, + final Inet6Address ipv6Address) { this.u8 = u8; this.u16 = u16; this.u32 = u32; @@ -858,6 +924,8 @@ public class StructTest { this.ube64 = ube64; this.bytes = bytes; this.eui48 = eui48; + this.ipv4Address = ipv4Address; + this.ipv6Address = ipv6Address; } } @@ -900,6 +968,17 @@ public class StructTest { assertNotEquals(msg.ube32, msg4.ube32); assertFalse(msg.equals(msg4)); + // With different IPv4 address. + final FullTypeMessage msg5 = doParsingMessageTest(FULL_TYPE_DATA_DIFF_IPV4, + FullTypeMessage.class, ByteOrder.BIG_ENDIAN); + assertNotEquals(msg.ipv4Address, msg5.ipv4Address); + assertFalse(msg.equals(msg5)); + + // With different IPv6 address. + final FullTypeMessage msg6 = doParsingMessageTest(FULL_TYPE_DATA_DIFF_IPV6, + FullTypeMessage.class, ByteOrder.BIG_ENDIAN); + assertNotEquals(msg.ipv6Address, msg6.ipv6Address); + assertFalse(msg.equals(msg6)); } @Test @@ -909,7 +988,9 @@ public class StructTest { + " s32: 2147483647, s64: 9223372036854775807, ube16: 32767, ube32: 2147483647," + " ube63: 9223372036854775807, ube64: 18446744073709551615," + " bytes: 0x20010DB80003000400050006," - + " eui48: 00:11:22:33:44:55"; + + " eui48: 00:11:22:33:44:55," + + " ipv4Address: 192.168.100.1," + + " ipv6Address: 2001:db8:3:4:5:6:7:8"; final FullTypeMessage msg = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class, ByteOrder.BIG_ENDIAN); @@ -922,14 +1003,15 @@ public class StructTest { + " u63: 9223372036854775807, u64: null, s8: 127, s16: 32767," + " s32: 2147483647, s64: 9223372036854775807, ube16: 32767, ube32: 2147483647," + " ube63: 9223372036854775807, ube64: 18446744073709551615," - + " bytes: null, eui48: null"; + + " bytes: null, eui48: null, ipv4Address: 192.168.100.1," + + " ipv6Address: null"; final FullTypeMessage msg = new FullTypeMessage((short) 0xff, (int) 0xffff, (long) 0xffffffffL, (long) 0x7fffffffffffffffL, null /* u64 */, (byte) 0x7f, (short) 0x7fff, (int) 0x7fffffff, (long) 0x7fffffffffffffffL, (int) 0x7fff, (long) 0x7fffffffL, (long) 0x7fffffffffffffffL, new BigInteger("18446744073709551615"), - null /* bytes */, null /* eui48 */); + null /* bytes */, null /* eui48 */, TEST_IPV4_ADDRESS, null /* ipv6Address */); assertEquals(expected, msg.toString()); } From dc0a5687d6b8e222740b2395fe777f12314a4c25 Mon Sep 17 00:00:00 2001 From: David Su Date: Fri, 29 Jan 2021 04:42:27 +0000 Subject: [PATCH 109/777] net-utils-services-common - set min_sdk_level to 30 Bug: 178711289 Test: compiles Change-Id: I8105265b726cb095375191693caa0ccfd7d66276 --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index c6a17feeaf..bcbee079d1 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -162,6 +162,7 @@ java_library { ":framework-annotations", ], sdk_version: "system_current", + min_sdk_version: "30", visibility: [ "//frameworks/base/services/net", ], From a19b59d8fc70df678a6fe2b39fbead01ad0c702e Mon Sep 17 00:00:00 2001 From: lucaslin Date: Mon, 1 Feb 2021 15:22:56 +0800 Subject: [PATCH 110/777] Add common CollectionUtils.{any,all} methods. Test: new tests for this Change-Id: I482c958af499bf8cdc8824c9586e9da619cd1f39 --- .../net/module/util/CollectionUtils.java | 22 ++++++++ .../net/module/util/CollectionUtilsTest.kt | 54 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index 74f738dafd..cb1e3e7435 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -65,6 +65,28 @@ public final class CollectionUtils { return array; } + /** + * @return True if all elements satisfy the predicate, false otherwise. + * Note that means this always returns true for empty collections. + */ + public static boolean all(@NonNull Collection elem, @NonNull Predicate predicate) { + for (final T e : elem) { + if (!predicate.test(e)) return false; + } + return true; + + } + /** + * @return True if any element satisfies the predicate, false otherwise. + * Note that means this always returns false for empty collections. + */ + public static boolean any(@NonNull Collection elem, @NonNull Predicate predicate) { + for (final T e : elem) { + if (predicate.test(e)) return true; + } + return false; + } + /** * @return True if there exists at least one element in the sparse array for which * condition {@code predicate} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt new file mode 100644 index 0000000000..00077420de --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util + +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +@RunWith(AndroidJUnit4::class) +@SmallTest +class CollectionUtilsTest { + @Test + fun testAny() { + assertTrue(CollectionUtils.any(listOf("A", "B", "C", "D", "E")) { it == "E" }) + assertFalse(CollectionUtils.any(listOf("A", "B", "C", "D", "E")) { it == "F" }) + assertTrue(CollectionUtils.any(listOf("AA", "BBB")) { it.length >= 3 }) + assertFalse(CollectionUtils.any(listOf("A", "BB", "CCC")) { it.length >= 4 }) + assertFalse(CollectionUtils.any(listOf("A", "BB", "CCC")) { it.length < 0 }) + assertFalse(CollectionUtils.any(listOf()) { true }) + assertFalse(CollectionUtils.any(listOf()) { false }) + assertTrue(CollectionUtils.any(listOf("A")) { true }) + assertFalse(CollectionUtils.any(listOf("A")) { false }) + } + + @Test + fun testAll() { + assertFalse(CollectionUtils.all(listOf("A", "B", "C", "D", "E")) { it != "E" }) + assertTrue(CollectionUtils.all(listOf("A", "B", "C", "D", "E")) { it != "F" }) + assertFalse(CollectionUtils.all(listOf("A", "BB", "CCC")) { it.length > 2 }) + assertTrue(CollectionUtils.all(listOf("A", "BB", "CCC")) { it.length >= 1 }) + assertTrue(CollectionUtils.all(listOf("A", "BB", "CCC")) { it.length < 4 }) + assertTrue(CollectionUtils.all(listOf()) { true }) + assertTrue(CollectionUtils.all(listOf()) { false }) + assertTrue(CollectionUtils.all(listOf(1)) { true }) + assertFalse(CollectionUtils.all(listOf(1)) { false }) + } +} From e2d02e7c98a000b381e2571d089d47010240e7dc Mon Sep 17 00:00:00 2001 From: lucaslin Date: Fri, 29 Jan 2021 19:19:27 +0800 Subject: [PATCH 111/777] Have a collection of utilities for netd - NetdUtils Some files which will be inside mainline module depend on NetworkManagementService to talk to netd, but after they become a part of mainline module, they cannot access @hide API of NetworkManagementService. So create a NetdUtils to help them to talk to netd. Bug: 170598012 Test: atest CtsNetTestCasesLatestSdk NetdStaticLibTests Change-Id: I8bee1204b9533b70844da0b3768427438fd0c890 --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index c6a17feeaf..a30917e98a 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -73,6 +73,7 @@ java_library { host_supported: true, visibility: [ "//frameworks/libs/net/common/tests:__subpackages__", + "//frameworks/libs/net/client-libs/tests:__subpackages__", ], static_libs: [ "kotlin-test" From 5c620643b7a291a51c54f65c1f17ea4b59ca9842 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Fri, 29 Jan 2021 19:19:27 +0800 Subject: [PATCH 112/777] Have a collection of utilities for netd - NetdUtils Some files which will be inside mainline module depend on NetworkManagementService to talk to netd, but after they become a part of mainline module, they cannot access @hide API of NetworkManagementService. So create a NetdUtils to help them to talk to netd. Bug: 170598012 Test: atest CtsNetTestCasesLatestSdk NetdStaticLibTests Change-Id: I8bee1204b9533b70844da0b3768427438fd0c890 --- staticlibs/client-libs/Android.bp | 4 +- .../android/net/module/util/NetdUtils.java | 105 ++++++++++++++++++ staticlibs/client-libs/tests/unit/Android.bp | 39 +++++++ .../tests/unit/AndroidManifest.xml | 28 +++++ .../net/module/util/NetdUtilsTest.java | 103 +++++++++++++++++ 5 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java create mode 100644 staticlibs/client-libs/tests/unit/Android.bp create mode 100644 staticlibs/client-libs/tests/unit/AndroidManifest.xml create mode 100644 staticlibs/client-libs/tests/unit/src/com/android/net/module/util/NetdUtilsTest.java diff --git a/staticlibs/client-libs/Android.bp b/staticlibs/client-libs/Android.bp index f6d781c048..e1a1086448 100644 --- a/staticlibs/client-libs/Android.bp +++ b/staticlibs/client-libs/Android.bp @@ -9,7 +9,9 @@ java_library { ], visibility: [ "//packages/modules/Connectivity/Tethering", - "//frameworks/base/services:__subpackages__" + "//frameworks/base/services:__subpackages__", + "//frameworks/base/packages:__subpackages__", + "//frameworks/libs/net/client-libs/tests:__subpackages__", ], libs: ["androidx.annotation_annotation"], static_libs: [ diff --git a/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java b/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java new file mode 100644 index 0000000000..1f31912944 --- /dev/null +++ b/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util; + +import static android.net.INetd.IF_STATE_DOWN; +import static android.net.INetd.IF_STATE_UP; + +import android.net.INetd; +import android.net.InterfaceConfigurationParcel; +import android.os.RemoteException; +import android.os.ServiceSpecificException; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; + +import java.util.ArrayList; + +/** + * Collection of utilities for netd. + */ +public class NetdUtils { + /** + * Get InterfaceConfigurationParcel from netd. + */ + public static InterfaceConfigurationParcel getInterfaceConfigParcel(@NonNull INetd netd, + @NonNull String iface) { + try { + return netd.interfaceGetCfg(iface); + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } + } + + private static void validateFlag(String flag) { + if (flag.indexOf(' ') >= 0) { + throw new IllegalArgumentException("flag contains space: " + flag); + } + } + + @VisibleForTesting + protected static String[] removeAndAddFlags(@NonNull String[] flags, @NonNull String remove, + @NonNull String add) { + final ArrayList result = new ArrayList<>(); + try { + // Validate the add flag first, so that the for-loop can be ignore once the format of + // add flag is invalid. + validateFlag(add); + for (String flag : flags) { + // Simply ignore both of remove and add flags first, then add the add flag after + // exiting the loop to prevent adding the duplicate flag. + if (remove.equals(flag) || add.equals(flag)) continue; + result.add(flag); + } + result.add(add); + return result.toArray(new String[result.size()]); + } catch (IllegalArgumentException iae) { + throw new IllegalStateException("Invalid InterfaceConfigurationParcel", iae); + } + } + + /** + * Set interface configuration to netd by passing InterfaceConfigurationParcel. + */ + public static void setInterfaceConfig(INetd netd, InterfaceConfigurationParcel configParcel) { + try { + netd.interfaceSetCfg(configParcel); + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } + } + + /** + * Set the given interface up. + */ + public static void setInterfaceUp(INetd netd, String iface) { + final InterfaceConfigurationParcel configParcel = getInterfaceConfigParcel(netd, iface); + configParcel.flags = removeAndAddFlags(configParcel.flags, IF_STATE_DOWN /* remove */, + IF_STATE_UP /* add */); + setInterfaceConfig(netd, configParcel); + } + + /** + * Set the given interface down. + */ + public static void setInterfaceDown(INetd netd, String iface) { + final InterfaceConfigurationParcel configParcel = getInterfaceConfigParcel(netd, iface); + configParcel.flags = removeAndAddFlags(configParcel.flags, IF_STATE_UP /* remove */, + IF_STATE_DOWN /* add */); + setInterfaceConfig(netd, configParcel); + } +} diff --git a/staticlibs/client-libs/tests/unit/Android.bp b/staticlibs/client-libs/tests/unit/Android.bp new file mode 100644 index 0000000000..fc8a2c6ce9 --- /dev/null +++ b/staticlibs/client-libs/tests/unit/Android.bp @@ -0,0 +1,39 @@ +android_library { + name: "NetdStaticLibTestsLib", + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], + min_sdk_version: "29", + static_libs: [ + "androidx.test.rules", + "mockito-target-extended-minus-junit4", + "net-tests-utils-host-device-common", + "netd-client", + ], + libs: [ + "android.test.runner", + "android.test.base", + ], + visibility: [ + // Visible for Tethering and NetworkStack integration test and link NetdStaticLibTestsLib + // there, so that the tests under client-libs can also be run when running tethering and + // NetworkStack MTS. + "//packages/modules/Connectivity/Tethering/tests/integration", + "//packages/modules/NetworkStack/tests/integration", + ] +} + +android_test { + name: "NetdStaticLibTests", + certificate: "platform", + static_libs: [ + "NetdStaticLibTestsLib", + ], + jni_libs: [ + // For mockito extended + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", + ], + test_suites: ["device-tests"], +} diff --git a/staticlibs/client-libs/tests/unit/AndroidManifest.xml b/staticlibs/client-libs/tests/unit/AndroidManifest.xml new file mode 100644 index 0000000000..7a07d3d549 --- /dev/null +++ b/staticlibs/client-libs/tests/unit/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + diff --git a/staticlibs/client-libs/tests/unit/src/com/android/net/module/util/NetdUtilsTest.java b/staticlibs/client-libs/tests/unit/src/com/android/net/module/util/NetdUtilsTest.java new file mode 100644 index 0000000000..306b1bb2f6 --- /dev/null +++ b/staticlibs/client-libs/tests/unit/src/com/android/net/module/util/NetdUtilsTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util; + +import static com.android.testutils.MiscAsserts.assertThrows; + +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.net.INetd; +import android.net.InterfaceConfigurationParcel; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Arrays; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class NetdUtilsTest { + @Mock private INetd mNetd; + + private static final String IFACE = "TEST_IFACE"; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + } + + private void setupFlagsForInterfaceConfiguration(String[] flags) throws Exception { + final InterfaceConfigurationParcel config = new InterfaceConfigurationParcel(); + config.flags = flags; + when(mNetd.interfaceGetCfg(eq(IFACE))).thenReturn(config); + } + + private void verifyMethodsAndArgumentsOfSetInterface(boolean ifaceUp) throws Exception { + final String[] flagsContainDownAndUp = new String[] {"flagA", "down", "flagB", "up"}; + final String[] flagsForInterfaceDown = new String[] {"flagA", "down", "flagB"}; + final String[] flagsForInterfaceUp = new String[] {"flagA", "up", "flagB"}; + final String[] expectedFinalFlags; + setupFlagsForInterfaceConfiguration(flagsContainDownAndUp); + if (ifaceUp) { + // "down" flag will be removed from flagsContainDownAndUp when interface is up. Set + // expectedFinalFlags to flagsForInterfaceUp. + expectedFinalFlags = flagsForInterfaceUp; + NetdUtils.setInterfaceUp(mNetd, IFACE); + } else { + // "up" flag will be removed from flagsContainDownAndUp when interface is down. Set + // expectedFinalFlags to flagsForInterfaceDown. + expectedFinalFlags = flagsForInterfaceDown; + NetdUtils.setInterfaceDown(mNetd, IFACE); + } + verify(mNetd).interfaceSetCfg( + argThat(config -> + // Check if actual flags are the same as expected flags. + // TODO: Have a function in MiscAsserts to check if two arrays are the same. + CollectionUtils.all(Arrays.asList(expectedFinalFlags), + flag -> Arrays.asList(config.flags).contains(flag)) + && CollectionUtils.all(Arrays.asList(config.flags), + flag -> Arrays.asList(expectedFinalFlags).contains(flag)))); + } + + @Test + public void testSetInterfaceUp() throws Exception { + verifyMethodsAndArgumentsOfSetInterface(true /* ifaceUp */); + } + + @Test + public void testSetInterfaceDown() throws Exception { + verifyMethodsAndArgumentsOfSetInterface(false /* ifaceUp */); + } + + @Test + public void testRemoveAndAddFlags() throws Exception { + final String[] flags = new String[] {"flagA", "down", "flagB"}; + // Add an invalid flag and expect to get an IllegalStateException. + assertThrows(IllegalStateException.class, + () -> NetdUtils.removeAndAddFlags(flags, "down" /* remove */, "u p" /* add */)); + } +} + From e658c7b5dd9b3d9d218c6ba8df756e1d7ec9a80f Mon Sep 17 00:00:00 2001 From: paulhu Date: Tue, 26 Jan 2021 18:05:27 +0800 Subject: [PATCH 113/777] Add indexOf method PermissionMonitor is using ArrayUtils#indexOf often in checking permission methods. It's better to have this method in CollectionUtils. Also implement contains() by indexOf method. Bug: 174541037 Test: atest FrameworksNetTests Change-Id: I32e2ca815dd35eae9c31188856068eaf3458d250 --- .../net/module/util/CollectionUtils.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index 74f738dafd..6e8c6fee32 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -95,12 +95,17 @@ public final class CollectionUtils { * @return true if the array contains the specified value. */ public static boolean contains(@Nullable T[] array, @Nullable T value) { - if (array == null) return false; - for (T element : array) { - if (Objects.equals(element, value)) { - return true; - } + return indexOf(array, value) != -1; + } + + /** + * Return first index of value in given array, or -1 if not found. + */ + public static int indexOf(@Nullable T[] array, @Nullable T value) { + if (array == null) return -1; + for (int i = 0; i < array.length; i++) { + if (Objects.equals(array[i], value)) return i; } - return false; + return -1; } } From f51099dae345f89d70a71d364d5534fdfecf3d1b Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 29 Jan 2021 20:35:10 +0800 Subject: [PATCH 114/777] [FUI21.1] Create NetworkIdentityUtils class This patch creates a class in the static lib that contains utils of NetworkIdentity. Test: atest NetworkIdentityUtilsTest Bug: 174123988 Change-Id: I6f0780190017b5eef3312b764107ac1f00e06833 --- .../net/module/util/NetworkIdentityUtils.java | 51 +++++++++++++++++++ .../module/util/NetworkIdentityUtilsTest.kt | 49 ++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 staticlibs/framework/com/android/net/module/util/NetworkIdentityUtils.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/NetworkIdentityUtilsTest.kt diff --git a/staticlibs/framework/com/android/net/module/util/NetworkIdentityUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkIdentityUtils.java new file mode 100644 index 0000000000..94e60178fc --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/NetworkIdentityUtils.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +/** + * Utilities to examine {@link android.net.NetworkIdentity}. + */ +public class NetworkIdentityUtils { + /** + * Scrub given IMSI on production builds. + */ + @NonNull + public static String scrubSubscriberId(@Nullable String subscriberId) { + if (subscriberId != null) { + // TODO: parse this as MCC+MNC instead of hard-coding + return subscriberId.substring(0, Math.min(6, subscriberId.length())) + "..."; + } else { + return "null"; + } + } + + /** + * Scrub given IMSI on production builds. + */ + @Nullable + public static String[] scrubSubscriberIds(@Nullable String[] subscriberIds) { + if (subscriberIds == null) return null; + final String[] res = new String[subscriberIds.length]; + for (int i = 0; i < res.length; i++) { + res[i] = scrubSubscriberId(subscriberIds[i]); + } + return res; + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkIdentityUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkIdentityUtilsTest.kt new file mode 100644 index 0000000000..2904e1239c --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkIdentityUtilsTest.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util + +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.net.module.util.NetworkIdentityUtils.scrubSubscriberId +import com.android.net.module.util.NetworkIdentityUtils.scrubSubscriberIds +import com.android.testutils.assertContainsStringsExactly +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.test.assertEquals +import kotlin.test.assertNull + +@RunWith(AndroidJUnit4::class) +@SmallTest +class NetworkIdentityUtilsTest { + @Test + fun testScrubSubscriberId() { + assertEquals("123456...", scrubSubscriberId("1234567890123")) + assertEquals("123456...", scrubSubscriberId("1234567")) + assertEquals("123...", scrubSubscriberId("123")) + assertEquals("...", scrubSubscriberId("")) + assertEquals("null", scrubSubscriberId(null)) + } + + @Test + fun testScrubSubscriberIds() { + assertContainsStringsExactly(scrubSubscriberIds(arrayOf("1234567", "", null))!!, + "123456...", "...", "null") + assertContainsStringsExactly(scrubSubscriberIds(arrayOf("12345"))!!, "12345...") + assertContainsStringsExactly(scrubSubscriberIds(arrayOf())!!) + assertNull(scrubSubscriberIds(null)) + } +} \ No newline at end of file From 2e7313af5cb59b50d52a6a656d1408445c485441 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 3 Feb 2021 18:18:13 +0800 Subject: [PATCH 115/777] Move shared methods to NetUtils The getNetworkPart() method is used by Settings and wifi. The method was inside NetworkUtils, but NetworkUtils is moving to connectivity mainline module. Methods in NetworkUtils will not be accessible outside module. Thus, move the shared method and the corresponding helper method to share lib. Bug: 172183305 Test: atest FrameworksNetTests Change-Id: Ic39f0debf1146dd84db962857dcead6b498aec49 --- .../com/android/net/module/util/NetUtils.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetUtils.java b/staticlibs/framework/com/android/net/module/util/NetUtils.java index 4331b65de0..f08257ae17 100644 --- a/staticlibs/framework/com/android/net/module/util/NetUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetUtils.java @@ -23,6 +23,7 @@ import android.net.RouteInfo; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.Collection; /** @@ -67,4 +68,44 @@ public final class NetUtils { } return bestRoute; } + + /** + * Get InetAddress masked with prefixLength. Will never return null. + * @param address the IP address to mask with + * @param prefixLength the prefixLength used to mask the IP + */ + public static InetAddress getNetworkPart(InetAddress address, int prefixLength) { + byte[] array = address.getAddress(); + maskRawAddress(array, prefixLength); + + InetAddress netPart = null; + try { + netPart = InetAddress.getByAddress(array); + } catch (UnknownHostException e) { + throw new RuntimeException("getNetworkPart error - " + e.toString()); + } + return netPart; + } + + /** + * Masks a raw IP address byte array with the specified prefix length. + */ + public static void maskRawAddress(byte[] array, int prefixLength) { + if (prefixLength < 0 || prefixLength > array.length * 8) { + throw new RuntimeException("IP address with " + array.length + + " bytes has invalid prefix length " + prefixLength); + } + + int offset = prefixLength / 8; + int remainder = prefixLength % 8; + byte mask = (byte) (0xFF << (8 - remainder)); + + if (offset < array.length) array[offset] = (byte) (array[offset] & mask); + + offset++; + + for (; offset < array.length; offset++) { + array[offset] = 0; + } + } } From 3d475dc5785d50f781e1a8dd9e0868cc28db3fdb Mon Sep 17 00:00:00 2001 From: Serik Beketayev Date: Thu, 4 Feb 2021 15:39:03 -0800 Subject: [PATCH 116/777] [Mainline] Core Platform APIs migration * java/net/InetAddress;->parseNumericAddress(Ljava/lang/String;)Ljava/net/InetAddress; * libcore/io/IoUtils;->closeQuietly(Ljava/io/FileDescriptor;)V * libcore/io/IoUtils;->closeQuietly(Ljava/lang/AutoCloseable;)V * libcore/io/IoUtils;->setBlocking(Ljava/io/FileDescriptor;Z)V * java/net/Inet4Address;->ANY:Ljava/net/InetAddress; * java/net/Inet6Address;->ANY:Ljava/net/InetAddress; Bug: 177260833 Test: mma Change-Id: I1357dba41beb27df17a7631317c4b05f98854f27 --- .../net/module/util/NetworkStackConstants.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index a2275054c7..b656ed2e14 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -17,6 +17,7 @@ package com.android.net.module.util; import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; @@ -98,7 +99,11 @@ public final class NetworkStackConstants { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff); public static final Inet4Address IPV4_ADDR_ANY = makeInet4Address( (byte) 0, (byte) 0, (byte) 0, (byte) 0); - + public static final Inet6Address IPV6_ADDR_ANY = makeInet6Address(new byte[]{ + (byte) 0, (byte) 0, (byte) 0, (byte) 0, + (byte) 0, (byte) 0, (byte) 0, (byte) 0, + (byte) 0, (byte) 0, (byte) 0, (byte) 0, + (byte) 0, (byte) 0, (byte) 0, (byte) 0 }); /** * IPv6 constants. * @@ -182,6 +187,16 @@ public final class NetworkStackConstants { } } + /** + * Make an Inet6Address from 16 bytes in network byte order. + */ + private static Inet6Address makeInet6Address(byte[] bytes) { + try { + return (Inet6Address) InetAddress.getByAddress(bytes); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("addr must be 16 bytes: this should never happen"); + } + } private NetworkStackConstants() { throw new UnsupportedOperationException("This class is not to be instantiated"); } From e59cf43d08fc9db3e05938744a0aea5b4be93f7b Mon Sep 17 00:00:00 2001 From: Jeongik Cha Date: Tue, 26 Jan 2021 22:34:53 +0900 Subject: [PATCH 117/777] Specify version for aidl_interface explicitly Bug: 150578172 Test: m Change-Id: I8b1e35a84e4ad4be479fd1508f06514879b174da --- staticlibs/client-libs/Android.bp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/client-libs/Android.bp b/staticlibs/client-libs/Android.bp index f6d781c048..c61422d415 100644 --- a/staticlibs/client-libs/Android.bp +++ b/staticlibs/client-libs/Android.bp @@ -13,7 +13,7 @@ java_library { ], libs: ["androidx.annotation_annotation"], static_libs: [ - "netd_aidl_interface-java", - "netd_event_listener_interface-java" + "netd_aidl_interface-lateststable-java", + "netd_event_listener_interface-lateststable-java" ] } From c291b2137f9c8f68f67daafddb76c66b8cca3a66 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Fri, 5 Feb 2021 16:39:15 +0800 Subject: [PATCH 118/777] Move shared methods and constants from Proxy to shared lib Proxy is moving into connectivity mainline and its hidden methods are not accessible outside the module. Thus, move the shared methods and constants to ProxyUtils to share between module and platform. Bug: 172183305 Test: atest FrameworksNetTests Test: atest CtsNetTestCases:ProxyInfoTest Change-Id: I7153ce4e77b80964ffad67254b6329973ed61f30 --- .../android/net/module/util/ProxyUtils.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/ProxyUtils.java b/staticlibs/framework/com/android/net/module/util/ProxyUtils.java index a7b8393807..fdd7dca1ce 100644 --- a/staticlibs/framework/com/android/net/module/util/ProxyUtils.java +++ b/staticlibs/framework/com/android/net/module/util/ProxyUtils.java @@ -22,6 +22,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Collection of network common utilities. @@ -30,6 +32,28 @@ import java.util.Locale; */ public final class ProxyUtils { + public static final int PROXY_VALID = 0; + public static final int PROXY_HOSTNAME_EMPTY = 1; + public static final int PROXY_HOSTNAME_INVALID = 2; + public static final int PROXY_PORT_EMPTY = 3; + public static final int PROXY_PORT_INVALID = 4; + public static final int PROXY_EXCLLIST_INVALID = 5; + + // Hostname / IP REGEX validation + // Matches blank input, ips, and domain names + private static final String NAME_IP_REGEX = + "[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*(\\.[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*)*"; + private static final Pattern HOSTNAME_PATTERN; + private static final String HOSTNAME_REGEXP = "^$|^" + NAME_IP_REGEX + "$"; + private static final Pattern EXCLLIST_PATTERN; + private static final String EXCL_REGEX = + "[a-zA-Z0-9*]+(\\-[a-zA-Z0-9*]+)*(\\.[a-zA-Z0-9*]+(\\-[a-zA-Z0-9*]+)*)*"; + private static final String EXCLLIST_REGEXP = "^$|^" + EXCL_REGEX + "(," + EXCL_REGEX + ")*$"; + static { + HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP); + EXCLLIST_PATTERN = Pattern.compile(EXCLLIST_REGEXP); + } + /** Converts exclusion list from String to List. */ public static List exclusionStringAsList(String exclusionList) { if (exclusionList == null) { @@ -45,4 +69,30 @@ public final class ProxyUtils { } return TextUtils.join(",", exclusionList); } + + /** + * Validate syntax of hostname, port and exclusion list entries + */ + public static int validate(String hostname, String port, String exclList) { + Matcher match = HOSTNAME_PATTERN.matcher(hostname); + Matcher listMatch = EXCLLIST_PATTERN.matcher(exclList); + + if (!match.matches()) return PROXY_HOSTNAME_INVALID; + + if (!listMatch.matches()) return PROXY_EXCLLIST_INVALID; + + if (hostname.length() > 0 && port.length() == 0) return PROXY_PORT_EMPTY; + + if (port.length() > 0) { + if (hostname.length() == 0) return PROXY_HOSTNAME_EMPTY; + int portVal = -1; + try { + portVal = Integer.parseInt(port); + } catch (NumberFormatException ex) { + return PROXY_PORT_INVALID; + } + if (portVal <= 0 || portVal > 0xFFFF) return PROXY_PORT_INVALID; + } + return PROXY_VALID; + } } From e50bee1b98e42b4297c464b155533d16d29b32c5 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 27 Jan 2021 16:49:27 +0000 Subject: [PATCH 119/777] Add the constant for IPv6 all-routers/nodes/hosts multicast address. Also remove the DEFAULT_LINK_MTU constant, it's dup with ETHER_MTU. The caller should select the appropriate MTU based on specific link layer MTU. Bug: 138926174 Test: atest NetworkStackIntegrationTest Change-Id: I85e2c487298efaa0032eff3914029801580bb2c4 --- .../net/module/util/NetworkStackConstants.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index a2275054c7..0cbb65c064 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -16,7 +16,10 @@ package com.android.net.module.util; +import android.net.InetAddresses; + import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; @@ -51,8 +54,6 @@ public final class NetworkStackConstants { (byte) 0xff, (byte) 0xff, (byte) 0xff, }; - public static final int DEFAULT_LINK_MTU = 1500; - /** * ARP constants. * @@ -112,6 +113,12 @@ public final class NetworkStackConstants { public static final int IPV6_SRC_ADDR_OFFSET = 8; public static final int IPV6_DST_ADDR_OFFSET = 24; public static final int IPV6_MIN_MTU = 1280; + public static final Inet6Address IPV6_ADDR_ALL_NODES_MULTICAST = + (Inet6Address) InetAddresses.parseNumericAddress("ff02::1"); + public static final Inet6Address IPV6_ADDR_ALL_ROUTERS_MULTICAST = + (Inet6Address) InetAddresses.parseNumericAddress("ff02::2"); + public static final Inet6Address IPV6_ADDR_ALL_HOSTS_MULTICAST = + (Inet6Address) InetAddresses.parseNumericAddress("ff02::3"); /** * ICMPv6 constants. From 1b8c744bcd617f37699ca9717598cd9eab402049 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Fri, 12 Feb 2021 15:39:10 -0800 Subject: [PATCH 120/777] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/libs/net Added SPDX-license-identifier-Apache-2.0 to: client-libs/Android.bp client-libs/tests/unit/Android.bp common/Android.bp common/native/bpf_syscall_wrappers/Android.bp common/native/netjniutils/Android.bp common/tests/unit/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: I2d4abaee12c1f20c39a7e2c9e02e2fccb96fa3ee Merged-in: I6942c6844c89048f785f2b6eaa4bb33a24fa6f93 --- staticlibs/Android.bp | 4 ++++ staticlibs/native/bpf_syscall_wrappers/Android.bp | 4 ++++ staticlibs/native/netjniutils/Android.bp | 4 ++++ staticlibs/tests/unit/Android.bp | 5 ++++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index ecff6c7fee..a3bfbce94a 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -27,6 +27,10 @@ // included in the bootclasspath, they could incorrectly be included in the SDK documentation even // though they are not in the current.txt files. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + java_library { name: "net-utils-device-common", srcs: [ diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index ae6eee0ddf..fa90655433 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + cc_library_headers { name: "bpf_syscall_wrappers", vendor_available: false, diff --git a/staticlibs/native/netjniutils/Android.bp b/staticlibs/native/netjniutils/Android.bp index 8417c52327..d8e6a04c26 100644 --- a/staticlibs/native/netjniutils/Android.bp +++ b/staticlibs/native/netjniutils/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + cc_library_static { name: "libnetjniutils", srcs: ["netjniutils.cpp"], diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index c00202e63f..4ce4b0ea18 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -2,6 +2,10 @@ // Build NetworkStaticLibTests package //######################################################################## +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + android_library { name: "NetworkStaticLibTestsLib", srcs: ["src/**/*.java","src/**/*.kt"], @@ -38,4 +42,3 @@ android_test { jarjar_rules: "jarjar-rules.txt", test_suites: ["device-tests"], } - From 5e043f16a9f25f05d71dffe940d1f4df176ac776 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Fri, 12 Feb 2021 15:39:10 -0800 Subject: [PATCH 121/777] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/libs/net Added SPDX-license-identifier-Apache-2.0 to: client-libs/Android.bp client-libs/tests/unit/Android.bp common/Android.bp common/native/bpf_syscall_wrappers/Android.bp common/native/netjniutils/Android.bp common/tests/unit/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: I2d4abaee12c1f20c39a7e2c9e02e2fccb96fa3ee Merged-in: I6942c6844c89048f785f2b6eaa4bb33a24fa6f93 --- staticlibs/client-libs/Android.bp | 4 ++++ staticlibs/client-libs/tests/unit/Android.bp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/staticlibs/client-libs/Android.bp b/staticlibs/client-libs/Android.bp index cc1b4e744b..9cedd29f4f 100644 --- a/staticlibs/client-libs/Android.bp +++ b/staticlibs/client-libs/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + java_library { name: "netd-client", srcs: ["netd/**/*"], diff --git a/staticlibs/client-libs/tests/unit/Android.bp b/staticlibs/client-libs/tests/unit/Android.bp index fc8a2c6ce9..2cd39bdcd6 100644 --- a/staticlibs/client-libs/tests/unit/Android.bp +++ b/staticlibs/client-libs/tests/unit/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + android_library { name: "NetdStaticLibTestsLib", srcs: [ From 221bb08d51c504e34086e499c781c8d537528f06 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Thu, 18 Feb 2021 04:38:55 +0000 Subject: [PATCH 122/777] [automerger skipped] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/libs/net am: a119946899 am: e99a4b20cd -s ours am skip reason: Change-Id I6942c6844c89048f785f2b6eaa4bb33a24fa6f93 with SHA-1 72e3e74277 is in history Original change: https://android-review.googlesource.com/c/platform/frameworks/libs/net/+/1588168 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: Iba21ec83c36fc00216f614777f40af5c1ab1efa5 --- staticlibs/client-libs/Android.bp | 4 ---- staticlibs/client-libs/tests/unit/Android.bp | 4 ---- 2 files changed, 8 deletions(-) diff --git a/staticlibs/client-libs/Android.bp b/staticlibs/client-libs/Android.bp index 9cedd29f4f..cc1b4e744b 100644 --- a/staticlibs/client-libs/Android.bp +++ b/staticlibs/client-libs/Android.bp @@ -1,7 +1,3 @@ -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - java_library { name: "netd-client", srcs: ["netd/**/*"], diff --git a/staticlibs/client-libs/tests/unit/Android.bp b/staticlibs/client-libs/tests/unit/Android.bp index 2cd39bdcd6..fc8a2c6ce9 100644 --- a/staticlibs/client-libs/tests/unit/Android.bp +++ b/staticlibs/client-libs/tests/unit/Android.bp @@ -1,7 +1,3 @@ -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - android_library { name: "NetdStaticLibTestsLib", srcs: [ From e3b2f3cffb85c52643dd7b27f45bcb4c43797d1a Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Thu, 18 Feb 2021 05:24:21 +0000 Subject: [PATCH 123/777] [automerger skipped] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/libs/net am: a119946899 am: e99a4b20cd am: bc3f1f3fd3 -s ours am skip reason: Change-Id I6942c6844c89048f785f2b6eaa4bb33a24fa6f93 with SHA-1 72e3e74277 is in history Original change: https://android-review.googlesource.com/c/platform/frameworks/libs/net/+/1588168 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: I3e3e11150d029c91497129b2babd333b23d6ccfa --- staticlibs/client-libs/Android.bp | 4 ---- staticlibs/client-libs/tests/unit/Android.bp | 4 ---- 2 files changed, 8 deletions(-) diff --git a/staticlibs/client-libs/Android.bp b/staticlibs/client-libs/Android.bp index 9cedd29f4f..cc1b4e744b 100644 --- a/staticlibs/client-libs/Android.bp +++ b/staticlibs/client-libs/Android.bp @@ -1,7 +1,3 @@ -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - java_library { name: "netd-client", srcs: ["netd/**/*"], diff --git a/staticlibs/client-libs/tests/unit/Android.bp b/staticlibs/client-libs/tests/unit/Android.bp index 2cd39bdcd6..fc8a2c6ce9 100644 --- a/staticlibs/client-libs/tests/unit/Android.bp +++ b/staticlibs/client-libs/tests/unit/Android.bp @@ -1,7 +1,3 @@ -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - android_library { name: "NetdStaticLibTestsLib", srcs: [ From 4242767a07d44bccacc34b24aa12d345b32de8e1 Mon Sep 17 00:00:00 2001 From: paulhu Date: Mon, 25 Jan 2021 17:49:07 +0800 Subject: [PATCH 124/777] Add checking NetworkStack permission methods and tests These methods migrate from android.net.NetworkStack. checkNetworkStackPermission() checkNetworkStackPermissionOr() Bug: 178352309 Test: atest NetworkStaticLibTests Change-Id: Iba4daaac3c662b87fec038f7c557e4fd6544c069 --- .../net/module/util/PermissionUtils.java | 31 +++++++ .../net/module/util/PermissionUtilsTest.kt | 93 +++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt diff --git a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java index ce8a74549b..10eda57632 100644 --- a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java @@ -16,11 +16,16 @@ package com.android.net.module.util; +import static android.Manifest.permission.NETWORK_STACK; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import android.annotation.NonNull; import android.content.Context; +import java.util.ArrayList; +import java.util.Arrays; + /** * Collection of permission utilities. * @hide @@ -49,4 +54,30 @@ public final class PermissionUtils { + String.join(", ", permissions) + "."); } } + + /** + * If the NetworkStack, MAINLINE_NETWORK_STACK are not allowed for a particular process, throw a + * {@link SecurityException}. + * + * @param context {@link android.content.Context} for the process. + */ + public static void enforceNetworkStackPermission(final @NonNull Context context) { + enforceNetworkStackPermissionOr(context); + } + + /** + * If the NetworkStack, MAINLINE_NETWORK_STACK or other specified permissions are not allowed + * for a particular process, throw a {@link SecurityException}. + * + * @param context {@link android.content.Context} for the process. + * @param otherPermissions The set of permissions that could be the candidate permissions , or + * empty string if none of other permissions needed. + */ + public static void enforceNetworkStackPermissionOr(final @NonNull Context context, + final @NonNull String... otherPermissions) { + ArrayList permissions = new ArrayList(Arrays.asList(otherPermissions)); + permissions.add(NETWORK_STACK); + permissions.add(PERMISSION_MAINLINE_NETWORK_STACK); + enforceAnyPermissionOf(context, permissions.toArray(new String[0])); + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt new file mode 100644 index 0000000000..6da5e7d018 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util + +import android.Manifest.permission.NETWORK_STACK +import android.content.Context +import android.content.pm.PackageManager.PERMISSION_DENIED +import android.content.pm.PackageManager.PERMISSION_GRANTED +import android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.net.module.util.PermissionUtils.checkAnyPermissionOf +import com.android.net.module.util.PermissionUtils.enforceNetworkStackPermission +import com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr +import com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.mock +import kotlin.test.assertFailsWith + +/** Tests for PermissionUtils */ +@RunWith(AndroidJUnit4::class) +@SmallTest +class PermissionUtilsTest { + private val TEST_PERMISSION1 = "android.permission.TEST_PERMISSION1" + private val TEST_PERMISSION2 = "android.permission.TEST_PERMISSION2" + private val context = mock(Context::class.java) + + @Test + fun testEnforceAnyPermissionOf() { + doReturn(PERMISSION_GRANTED).`when`(context).checkCallingOrSelfPermission(TEST_PERMISSION1) + doReturn(PERMISSION_DENIED).`when`(context).checkCallingOrSelfPermission(TEST_PERMISSION2) + assertTrue(checkAnyPermissionOf(context, TEST_PERMISSION1, TEST_PERMISSION2)) + enforceAnyPermissionOf(context, TEST_PERMISSION1, TEST_PERMISSION2) + + doReturn(PERMISSION_DENIED).`when`(context).checkCallingOrSelfPermission(TEST_PERMISSION1) + doReturn(PERMISSION_GRANTED).`when`(context).checkCallingOrSelfPermission(TEST_PERMISSION2) + assertTrue(checkAnyPermissionOf(context, TEST_PERMISSION1, TEST_PERMISSION2)) + enforceAnyPermissionOf(context, TEST_PERMISSION1, TEST_PERMISSION2) + + doReturn(PERMISSION_DENIED).`when`(context).checkCallingOrSelfPermission(any()) + assertFalse(checkAnyPermissionOf(context, TEST_PERMISSION1, TEST_PERMISSION2)) + assertFailsWith("Expect fail but permission granted.") { + enforceAnyPermissionOf(context, TEST_PERMISSION1, TEST_PERMISSION2) } + } + + @Test + fun testEnforceNetworkStackPermissionOr() { + doReturn(PERMISSION_GRANTED).`when`(context).checkCallingOrSelfPermission(NETWORK_STACK) + doReturn(PERMISSION_DENIED).`when`(context) + .checkCallingOrSelfPermission(PERMISSION_MAINLINE_NETWORK_STACK) + enforceNetworkStackPermission(context) + enforceNetworkStackPermissionOr(context, TEST_PERMISSION1) + + doReturn(PERMISSION_DENIED).`when`(context).checkCallingOrSelfPermission(NETWORK_STACK) + doReturn(PERMISSION_GRANTED).`when`(context) + .checkCallingOrSelfPermission(PERMISSION_MAINLINE_NETWORK_STACK) + enforceNetworkStackPermission(context) + enforceNetworkStackPermissionOr(context, TEST_PERMISSION2) + + doReturn(PERMISSION_DENIED).`when`(context).checkCallingOrSelfPermission(NETWORK_STACK) + doReturn(PERMISSION_DENIED).`when`(context) + .checkCallingOrSelfPermission(PERMISSION_MAINLINE_NETWORK_STACK) + doReturn(PERMISSION_GRANTED).`when`(context).checkCallingOrSelfPermission(TEST_PERMISSION1) + assertFailsWith("Expect fail but permission granted.") { + enforceNetworkStackPermission(context) } + enforceNetworkStackPermissionOr(context, TEST_PERMISSION1) + + doReturn(PERMISSION_DENIED).`when`(context).checkCallingOrSelfPermission(any()) + assertFailsWith("Expect fail but permission granted.") { + enforceNetworkStackPermission(context) } + assertFailsWith("Expect fail but permission granted.") { + enforceNetworkStackPermissionOr(context, TEST_PERMISSION2) } + } +} From b9fc3ad8e33f967236fe3440cfc426a5f6a6d632 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 19 Feb 2021 10:08:58 +0000 Subject: [PATCH 125/777] Add a public test method to reset package version Instead of having the cached version field protected, which is only usable by DeviceConfigUtilsTest, have a public method to reset it to -1 so that other tests exercising feature flags can reset it before and after running. Bug: 173068192 Test: atest NetworkStaticLibTests Change-Id: I8f5be3c91b2a47070507d5bf263e2e5d7d9d9d14 --- .../com/android/net/module/util/DeviceConfigUtils.java | 6 +++++- .../com/android/net/module/util/DeviceConfigUtilsTest.java | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index 271cc6ead2..5d03dfd279 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -36,7 +36,11 @@ public final class DeviceConfigUtils { private static final String TAG = DeviceConfigUtils.class.getSimpleName(); @VisibleForTesting - protected static volatile long sPackageVersion = -1; + public static void resetPackageVersionCacheForTest() { + sPackageVersion = -1; + } + + private static volatile long sPackageVersion = -1; private static long getPackageVersion(@NonNull final Context context) throws PackageManager.NameNotFoundException { // sPackageVersion may be set by another thread just after this check, but querying the diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java index 982dbe7c81..57316b2f42 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -88,7 +88,7 @@ public class DeviceConfigUtilsTest { @After public void tearDown() { mSession.finishMocking(); - DeviceConfigUtils.sPackageVersion = -1L; + DeviceConfigUtils.resetPackageVersionCacheForTest(); } @Test From 15e5bd140e54f1a5be9ad5222d2dd5d98bd2a68f Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Mon, 22 Feb 2021 16:10:07 -0800 Subject: [PATCH 126/777] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/libs/net Added SPDX-license-identifier-Apache-2.0 to: client-libs/Android.bp client-libs/tests/unit/Android.bp common/Android.bp common/native/bpf_syscall_wrappers/Android.bp common/native/netjniutils/Android.bp common/tests/unit/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: I6ea23b03b1fadb54c7974c9f716f0f13795f84c5 --- staticlibs/Android.bp | 4 ++++ staticlibs/native/bpf_syscall_wrappers/Android.bp | 4 ++++ staticlibs/native/netjniutils/Android.bp | 4 ++++ staticlibs/tests/unit/Android.bp | 5 ++++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index ecff6c7fee..a3bfbce94a 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -27,6 +27,10 @@ // included in the bootclasspath, they could incorrectly be included in the SDK documentation even // though they are not in the current.txt files. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + java_library { name: "net-utils-device-common", srcs: [ diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index ae6eee0ddf..fa90655433 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + cc_library_headers { name: "bpf_syscall_wrappers", vendor_available: false, diff --git a/staticlibs/native/netjniutils/Android.bp b/staticlibs/native/netjniutils/Android.bp index 8417c52327..d8e6a04c26 100644 --- a/staticlibs/native/netjniutils/Android.bp +++ b/staticlibs/native/netjniutils/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + cc_library_static { name: "libnetjniutils", srcs: ["netjniutils.cpp"], diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index c00202e63f..4ce4b0ea18 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -2,6 +2,10 @@ // Build NetworkStaticLibTests package //######################################################################## +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + android_library { name: "NetworkStaticLibTestsLib", srcs: ["src/**/*.java","src/**/*.kt"], @@ -38,4 +42,3 @@ android_test { jarjar_rules: "jarjar-rules.txt", test_suites: ["device-tests"], } - From 37cd99a0ed8e86986b54780d3df5aafc58589a98 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Mon, 22 Feb 2021 16:10:07 -0800 Subject: [PATCH 127/777] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/libs/net Added SPDX-license-identifier-Apache-2.0 to: client-libs/Android.bp client-libs/tests/unit/Android.bp common/Android.bp common/native/bpf_syscall_wrappers/Android.bp common/native/netjniutils/Android.bp common/tests/unit/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: I6ea23b03b1fadb54c7974c9f716f0f13795f84c5 --- staticlibs/client-libs/Android.bp | 4 ++++ staticlibs/client-libs/tests/unit/Android.bp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/staticlibs/client-libs/Android.bp b/staticlibs/client-libs/Android.bp index cc1b4e744b..9cedd29f4f 100644 --- a/staticlibs/client-libs/Android.bp +++ b/staticlibs/client-libs/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + java_library { name: "netd-client", srcs: ["netd/**/*"], diff --git a/staticlibs/client-libs/tests/unit/Android.bp b/staticlibs/client-libs/tests/unit/Android.bp index fc8a2c6ce9..2cd39bdcd6 100644 --- a/staticlibs/client-libs/tests/unit/Android.bp +++ b/staticlibs/client-libs/tests/unit/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + android_library { name: "NetdStaticLibTestsLib", srcs: [ From 019601fb36f16d45d9bf8c5024f38e0aeeb33c1a Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Mon, 22 Feb 2021 12:24:58 -0800 Subject: [PATCH 128/777] DO NOT MERGE [LSC] Add LOCAL_LICENSE_KINDS to frameworks/libs/net Added SPDX-license-identifier-Apache-2.0 to: client-libs/Android.bp client-libs/tests/unit/Android.bp common/Android.bp common/native/bpf_syscall_wrappers/Android.bp common/native/netjniutils/Android.bp common/tests/unit/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: I8ba82a15e5fdf859e497d558983ef41afebf1bbb Merged-in: I2d4abaee12c1f20c39a7e2c9e02e2fccb96fa3ee Merged-in: I6ea23b03b1fadb54c7974c9f716f0f13795f84c5 --- staticlibs/Android.bp | 4 ++++ staticlibs/native/bpf_syscall_wrappers/Android.bp | 4 ++++ staticlibs/native/netjniutils/Android.bp | 4 ++++ staticlibs/tests/unit/Android.bp | 5 ++++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index ecff6c7fee..a3bfbce94a 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -27,6 +27,10 @@ // included in the bootclasspath, they could incorrectly be included in the SDK documentation even // though they are not in the current.txt files. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + java_library { name: "net-utils-device-common", srcs: [ diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index ae6eee0ddf..fa90655433 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + cc_library_headers { name: "bpf_syscall_wrappers", vendor_available: false, diff --git a/staticlibs/native/netjniutils/Android.bp b/staticlibs/native/netjniutils/Android.bp index 8417c52327..d8e6a04c26 100644 --- a/staticlibs/native/netjniutils/Android.bp +++ b/staticlibs/native/netjniutils/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + cc_library_static { name: "libnetjniutils", srcs: ["netjniutils.cpp"], diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index c00202e63f..4ce4b0ea18 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -2,6 +2,10 @@ // Build NetworkStaticLibTests package //######################################################################## +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + android_library { name: "NetworkStaticLibTestsLib", srcs: ["src/**/*.java","src/**/*.kt"], @@ -38,4 +42,3 @@ android_test { jarjar_rules: "jarjar-rules.txt", test_suites: ["device-tests"], } - From 121ccf9c60d0361e68e1a390f543da3af87b02cb Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Mon, 22 Feb 2021 12:24:58 -0800 Subject: [PATCH 129/777] DO NOT MERGE [LSC] Add LOCAL_LICENSE_KINDS to frameworks/libs/net Added SPDX-license-identifier-Apache-2.0 to: client-libs/Android.bp client-libs/tests/unit/Android.bp common/Android.bp common/native/bpf_syscall_wrappers/Android.bp common/native/netjniutils/Android.bp common/tests/unit/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: I8ba82a15e5fdf859e497d558983ef41afebf1bbb Merged-in: I2d4abaee12c1f20c39a7e2c9e02e2fccb96fa3ee Merged-in: I6ea23b03b1fadb54c7974c9f716f0f13795f84c5 --- staticlibs/client-libs/Android.bp | 4 ++++ staticlibs/client-libs/tests/unit/Android.bp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/staticlibs/client-libs/Android.bp b/staticlibs/client-libs/Android.bp index cc1b4e744b..9cedd29f4f 100644 --- a/staticlibs/client-libs/Android.bp +++ b/staticlibs/client-libs/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + java_library { name: "netd-client", srcs: ["netd/**/*"], diff --git a/staticlibs/client-libs/tests/unit/Android.bp b/staticlibs/client-libs/tests/unit/Android.bp index fc8a2c6ce9..2cd39bdcd6 100644 --- a/staticlibs/client-libs/tests/unit/Android.bp +++ b/staticlibs/client-libs/tests/unit/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + android_library { name: "NetdStaticLibTestsLib", srcs: [ From 4dfe1ff50a9aaee99983e65cdaededf8b7e7ef81 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 24 Feb 2021 17:54:33 +0800 Subject: [PATCH 130/777] Add helper function to check if collection is empty Bug: 172183305 Test: m Change-Id: I3b7b415d39f8a1fffb43ace58772da554412d25e --- .../com/android/net/module/util/CollectionUtils.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index e5bb58d4ba..cd1d35e1fe 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -37,6 +37,13 @@ public final class CollectionUtils { return array == null || array.length == 0; } + /** + * @return True if the collection is null or 0-length. + */ + public static boolean isEmpty(@Nullable Collection collection) { + return collection == null || collection.isEmpty(); + } + /** * Returns an int array from the given Integer list. */ From 6344a8cdae0822b6af67c9a78884350f749ecdea Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 3 Feb 2021 05:55:30 +0000 Subject: [PATCH 131/777] Add utilities to create IPv6 ICMP messages. The utilities replace the ones from IpClientIntegrationTests. Original Kotlin implementation is aosp/1440812. Bug: 168868607 Test: atest NetworkStackIntegrationTest Change-Id: I1c050ae42d99f541eeaa3dcd80a53574ab9bc1c3 --- staticlibs/Android.bp | 4 + .../android/net/module/util/Ipv6Utils.java | 136 ++++++++++++++++++ .../module/util/structs/EthernetHeader.java | 60 ++++++++ .../net/module/util/structs/Icmpv6Header.java | 45 ++++++ .../net/module/util/structs/Ipv6Header.java | 75 ++++++++++ .../net/module/util/structs/LlaOption.java | 59 ++++++++ .../net/module/util/structs/MtuOption.java | 65 +++++++++ .../net/module/util/structs/NaHeader.java | 57 ++++++++ .../util/structs/PrefixInformationOption.java | 97 +++++++++++++ .../net/module/util/structs/RaHeader.java | 62 ++++++++ .../net/module/util/structs/RdnssOption.java | 90 ++++++++++++ .../net/module/util/structs/RsHeader.java | 44 ++++++ 12 files changed, 794 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/Ipv6Utils.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/Icmpv6Header.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/LlaOption.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/MtuOption.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/NaHeader.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/RaHeader.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/RdnssOption.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/RsHeader.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index a3bfbce94a..03296e7304 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -60,6 +60,9 @@ java_library { "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", ], + static_libs: [ + "net-utils-framework-common", + ], libs: [ "androidx.annotation_annotation", ], @@ -146,6 +149,7 @@ java_library { "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", + "//frameworks/libs/net/common/device", "//packages/modules/Wifi/framework/tests:__subpackages__", ] } diff --git a/staticlibs/device/com/android/net/module/util/Ipv6Utils.java b/staticlibs/device/com/android/net/module/util/Ipv6Utils.java new file mode 100644 index 0000000000..73c2431d76 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/Ipv6Utils.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util; + +import static android.system.OsConstants.IPPROTO_ICMPV6; + +import static com.android.net.module.util.IpUtils.icmpv6Checksum; +import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION; + +import android.net.MacAddress; + +import com.android.net.module.util.structs.EthernetHeader; +import com.android.net.module.util.structs.Icmpv6Header; +import com.android.net.module.util.structs.Ipv6Header; +import com.android.net.module.util.structs.NaHeader; +import com.android.net.module.util.structs.RaHeader; +import com.android.net.module.util.structs.RsHeader; + +import java.net.Inet6Address; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * Utilities for IPv6 packets. + */ +public class Ipv6Utils { + /** + * Build a generic ICMPv6 packet(e.g., packet used in the neighbor discovery protocol). + */ + public static ByteBuffer buildIcmpv6Packet(final MacAddress srcMac, final MacAddress dstMac, + final Inet6Address srcIp, final Inet6Address dstIp, short type, short code, + final ByteBuffer... options) { + final int etherHeaderLen = Struct.getSize(EthernetHeader.class); + final int ipv6HeaderLen = Struct.getSize(Ipv6Header.class); + final int icmpv6HeaderLen = Struct.getSize(Icmpv6Header.class); + int payloadLen = 0; + for (ByteBuffer option: options) { + payloadLen += option.limit(); + } + final ByteBuffer packet = ByteBuffer.allocate(etherHeaderLen + ipv6HeaderLen + + icmpv6HeaderLen + payloadLen); + final EthernetHeader ethHeader = + new EthernetHeader(dstMac, srcMac, (short) ETHER_TYPE_IPV6); + final Ipv6Header ipv6Header = + new Ipv6Header((int) 0x60000000 /* version, traffic class, flowlabel */, + icmpv6HeaderLen + payloadLen /* payload length */, + (byte) IPPROTO_ICMPV6 /* next header */, (byte) 0xff /* hop limit */, srcIp, dstIp); + final Icmpv6Header icmpv6Header = new Icmpv6Header(type, code, (short) 0 /* checksum */); + + ethHeader.writeToByteBuffer(packet); + ipv6Header.writeToByteBuffer(packet); + icmpv6Header.writeToByteBuffer(packet); + for (ByteBuffer option : options) { + packet.put(option); + // in case option might be reused by caller, restore the position and + // limit of bytebuffer. + option.clear(); + } + packet.flip(); + + // Populate the ICMPv6 checksum field. + packet.putShort(etherHeaderLen + ipv6HeaderLen + 2, icmpv6Checksum(packet, + etherHeaderLen /* ipOffset */, + (int) (etherHeaderLen + ipv6HeaderLen) /* transportOffset */, + (short) (icmpv6HeaderLen + payloadLen) /* transportLen */)); + return packet; + } + + /** + * Build the ICMPv6 packet payload including payload header and specific options. + */ + private static ByteBuffer[] buildIcmpv6Payload(final ByteBuffer payloadHeader, + final ByteBuffer... options) { + final ByteBuffer[] payload = new ByteBuffer[options.length + 1]; + payload[0] = payloadHeader; + System.arraycopy(options, 0, payload, 1, options.length); + return payload; + } + + /** + * Build an ICMPv6 Router Advertisement packet from the required specified parameters. + */ + public static ByteBuffer buildRaPacket(final MacAddress srcMac, final MacAddress dstMac, + final Inet6Address srcIp, final Inet6Address dstIp, final byte flags, + final int lifetime, final long reachableTime, final long retransTimer, + final ByteBuffer... options) { + final RaHeader raHeader = new RaHeader((byte) 0 /* hopLimit, unspecified */, + flags, lifetime, reachableTime, retransTimer); + final ByteBuffer[] payload = buildIcmpv6Payload( + ByteBuffer.wrap(raHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options); + return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, + (byte) ICMPV6_ROUTER_ADVERTISEMENT /* type */, (byte) 0 /* code */, payload); + } + + /** + * Build an ICMPv6 Neighbor Advertisement packet from the required specified parameters. + */ + public static ByteBuffer buildNaPacket(final MacAddress srcMac, final MacAddress dstMac, + final Inet6Address srcIp, final Inet6Address dstIp, final int flags, + final Inet6Address target, final ByteBuffer... options) { + final NaHeader naHeader = new NaHeader(flags, target); + final ByteBuffer[] payload = buildIcmpv6Payload( + ByteBuffer.wrap(naHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options); + return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, + (byte) ICMPV6_NEIGHBOR_ADVERTISEMENT /* type */, (byte) 0 /* code */, payload); + } + + /** + * Build an ICMPv6 Router Solicitation packet from the required specified parameters. + */ + public static ByteBuffer buildRsPacket(final MacAddress srcMac, final MacAddress dstMac, + final Inet6Address srcIp, final Inet6Address dstIp, final ByteBuffer... options) { + final RsHeader rsHeader = new RsHeader((int) 0 /* reserved */); + final ByteBuffer[] payload = buildIcmpv6Payload( + ByteBuffer.wrap(rsHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options); + return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, + (byte) ICMPV6_ROUTER_SOLICITATION /* type */, (byte) 0 /* code */, payload); + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java b/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java new file mode 100644 index 0000000000..d895cfaad7 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import android.net.MacAddress; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * L2 ethernet header as per IEEE 802.3. Does not include a 802.1Q tag. + * + * 0 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Destination | + * +- -+ + * | Ethernet | + * +- -+ + * | Address | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source | + * +- -+ + * | Ethernet | + * +- -+ + * | Address | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |1 0 0 0 0 1 1 0 1 1 0 1 1 1 0 1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class EthernetHeader extends Struct { + @Field(order = 0, type = Type.EUI48) + public final MacAddress dstMac; + @Field(order = 1, type = Type.EUI48) + public final MacAddress srcMac; + @Field(order = 2, type = Type.U16) + public final int etherType; + + public EthernetHeader(final MacAddress dstMac, final MacAddress srcMac, + final int etherType) { + this.dstMac = dstMac; + this.srcMac = srcMac; + this.etherType = etherType; + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/Icmpv6Header.java b/staticlibs/device/com/android/net/module/util/structs/Icmpv6Header.java new file mode 100644 index 0000000000..c82ae02b0d --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/Icmpv6Header.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * ICMPv6 header as per https://tools.ietf.org/html/rfc4443. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class Icmpv6Header extends Struct { + @Field(order = 0, type = Type.U8) + public short type; + @Field(order = 1, type = Type.U8) + public short code; + @Field(order = 2, type = Type.S16) + public short checksum; + + public Icmpv6Header(final short type, final short code, final short checksum) { + this.type = type; + this.code = code; + this.checksum = checksum; + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java b/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java new file mode 100644 index 0000000000..3ad81570e9 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.Inet6Address; + +/** + * L3 IPv6 header as per https://tools.ietf.org/html/rfc8200. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Version| Traffic Class | Flow Label | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Payload Length | Next Header | Hop Limit | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Source Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Destination Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class Ipv6Header extends Struct { + @Field(order = 0, type = Type.S32) + public int vtf; + @Field(order = 1, type = Type.U16) + public int length; + @Field(order = 2, type = Type.S8) + public byte nextHeader; + @Field(order = 3, type = Type.U8) + public short hopLimit; + @Field(order = 4, type = Type.Ipv6Address) + public Inet6Address srcIp; + @Field(order = 5, type = Type.Ipv6Address) + public Inet6Address dstIp; + + public Ipv6Header(final int vtf, final int length, final byte nextHeader, final short hopLimit, + final Inet6Address srcIp, final Inet6Address dstIp) { + this.vtf = vtf; + this.length = length; + this.nextHeader = nextHeader; + this.hopLimit = hopLimit; + this.srcIp = srcIp; + this.dstIp = dstIp; + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/LlaOption.java b/staticlibs/device/com/android/net/module/util/structs/LlaOption.java new file mode 100644 index 0000000000..2cdeefb21c --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/LlaOption.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import android.net.MacAddress; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * ICMPv6 source/target link-layer address option, as per https://tools.ietf.org/html/rfc4861. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Link-Layer Address ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class LlaOption extends Struct { + @Field(order = 0, type = Type.S8) + // 1 for Source Link-layer Address; 2 for Target Link-layer Address. + public final byte type; + @Field(order = 1, type = Type.S8) + public final byte length; // Length in 8-byte units + @Field(order = 2, type = Type.EUI48) + public final MacAddress linkLayerAddress; + + public LlaOption(final byte type, final byte length, final MacAddress linkLayerAddress) { + this.type = type; + this.length = length; + this.linkLayerAddress = linkLayerAddress; + } + + /** + * Build a target link-layer address option from the required specified parameters. + */ + public static ByteBuffer build(final byte type, final MacAddress linkLayerAddress) { + final LlaOption option = new LlaOption(type, (byte) 1 /* option len */, linkLayerAddress); + return ByteBuffer.wrap(option.writeToBytes(ByteOrder.nativeOrder())); + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/MtuOption.java b/staticlibs/device/com/android/net/module/util/structs/MtuOption.java new file mode 100644 index 0000000000..a35b57631a --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/MtuOption.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_MTU; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * ICMPv6 MTU option, as per https://tools.ietf.org/html/rfc4861. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | MTU | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class MtuOption extends Struct { + @Field(order = 0, type = Type.S8) + public final byte type; + @Field(order = 1, type = Type.S8) + public final byte length; // Length in 8-byte units + @Field(order = 2, type = Type.S16) + public final short reserved; + @Field(order = 3, type = Type.U32) + public final long mtu; + + public MtuOption(final byte type, final byte length, final short reserved, + final long mtu) { + this.type = type; + this.length = length; + this.reserved = reserved; + this.mtu = mtu; + } + + /** + * Build a MTU option from the required specified parameters. + */ + public static ByteBuffer build(final long mtu) { + final MtuOption option = new MtuOption((byte) ICMPV6_ND_OPTION_MTU, + (byte) 1 /* option len */, (short) 0 /* reserved */, mtu); + return ByteBuffer.wrap(option.writeToBytes(ByteOrder.nativeOrder())); + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/NaHeader.java b/staticlibs/device/com/android/net/module/util/structs/NaHeader.java new file mode 100644 index 0000000000..8101b06156 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/NaHeader.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.Inet6Address; + +/** + * ICMPv6 Neighbor Advertisement header, follow [Icmpv6Header], as per + * https://tools.ietf.org/html/rfc4861. This does not contain any option. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |R|S|O| Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Target Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Options ... + * +-+-+-+-+-+-+-+-+-+-+-+- + */ +public class NaHeader extends Struct { + @Field(order = 0, type = Type.S32) + public int flags; // Router flag, Solicited flag, Override flag and 29 Reserved bits. + @Field(order = 1, type = Type.Ipv6Address) + public Inet6Address target; + + public NaHeader(final int flags, final Inet6Address target) { + this.flags = flags; + this.target = target; + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java b/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java new file mode 100644 index 0000000000..7dc0192f87 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_PIO; + +import android.annotation.NonNull; +import android.net.IpPrefix; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * ICMPv6 prefix information option, as per https://tools.ietf.org/html/rfc4861. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Prefix Length |L|A| Reserved1 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Valid Lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Preferred Lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved2 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Prefix + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class PrefixInformationOption extends Struct { + @Field(order = 0, type = Type.S8) + public final byte type; + @Field(order = 1, type = Type.S8) + public final byte length; // Length in 8-byte units + @Field(order = 2, type = Type.S8) + public final byte prefixLen; + @Field(order = 3, type = Type.S8) + // On-link flag, Autonomous address configuration flag, 6-reserved bits + public final byte flags; + @Field(order = 4, type = Type.U32) + public final long validLifetime; + @Field(order = 5, type = Type.U32) + public final long preferredLifetime; + @Field(order = 6, type = Type.S32) + public final int reserved; + @Field(order = 7, type = Type.ByteArray, arraysize = 16) + public final byte[] prefix; + + public PrefixInformationOption(final byte type, final byte length, final byte prefixLen, + final byte flags, final long validLifetime, final long preferredLifetime, + final int reserved, @NonNull final byte[] prefix) { + this.type = type; + this.length = length; + this.prefixLen = prefixLen; + this.flags = flags; + this.validLifetime = validLifetime; + this.preferredLifetime = preferredLifetime; + this.reserved = reserved; + this.prefix = prefix; + } + + /** + * Build a Prefix Information option from the required specified parameters. + */ + public static ByteBuffer build(final IpPrefix prefix, final byte flags, + final long validLifetime, final long preferredLifetime) { + final PrefixInformationOption option = new PrefixInformationOption( + (byte) ICMPV6_ND_OPTION_PIO, (byte) 4 /* option len */, + (byte) prefix.getPrefixLength(), flags, validLifetime, preferredLifetime, + (int) 0, prefix.getRawAddress()); + return ByteBuffer.wrap(option.writeToBytes(ByteOrder.nativeOrder())); + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/RaHeader.java b/staticlibs/device/com/android/net/module/util/structs/RaHeader.java new file mode 100644 index 0000000000..31a5cb76fc --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/RaHeader.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * ICMPv6 Router Advertisement header, follow [Icmpv6Header], as per + * https://tools.ietf.org/html/rfc4861. This does not contain any option. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Cur Hop Limit |M|O| Reserved | Router Lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reachable Time | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Retrans Timer | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Options ... + * +-+-+-+-+-+-+-+-+-+-+-+- + */ +public class RaHeader extends Struct { + @Field(order = 0, type = Type.S8) + public final byte hopLimit; + // "Managed address configuration", "Other configuration" bits, and 6 reserved bits + @Field(order = 1, type = Type.S8) + public final byte flags; + @Field(order = 2, type = Type.U16) + public final int lifetime; + @Field(order = 3, type = Type.U32) + public final long reachableTime; + @Field(order = 4, type = Type.U32) + public final long retransTimer; + + public RaHeader(final byte hopLimit, final byte flags, final int lifetime, + final long reachableTime, final long retransTimer) { + this.hopLimit = hopLimit; + this.flags = flags; + this.lifetime = lifetime; + this.reachableTime = reachableTime; + this.retransTimer = retransTimer; + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java b/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java new file mode 100644 index 0000000000..de55e66053 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_RDNSS; + +import android.net.InetAddresses; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.Inet6Address; +import java.nio.ByteBuffer; + +/** + * IPv6 RA recursive DNS server option, as per https://tools.ietf.org/html/rfc8106. + * This should be followed by a series of DNSv6 server addresses. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * : Addresses of IPv6 Recursive DNS Servers : + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class RdnssOption extends Struct { + @Field(order = 0, type = Type.S8) + public final byte type; + @Field(order = 1, type = Type.S8) + public final byte length; // Length in 8-byte units + @Field(order = 2, type = Type.S16) + public final short reserved; + @Field(order = 3, type = Type.U32) + public final long lifetime; + + public RdnssOption(final byte type, final byte length, final short reserved, + final long lifetime) { + this.type = type; + this.length = length; + this.reserved = reserved; + this.lifetime = lifetime; + } + + /** + * Build a RDNSS option from the required specified Inet6Address parameters. + */ + public static ByteBuffer build(final long lifetime, final Inet6Address... servers) { + final byte length = (byte) (1 + 2 * servers.length); + final RdnssOption option = new RdnssOption((byte) ICMPV6_ND_OPTION_RDNSS, + length, (short) 0, lifetime); + final ByteBuffer buffer = ByteBuffer.allocate(length * 8); + option.writeToByteBuffer(buffer); + for (Inet6Address server : servers) { + buffer.put(server.getAddress()); + } + buffer.flip(); + return buffer; + } + + /** + * Build a RDNSS option from the required specified String parameters. + */ + public static ByteBuffer build(final long lifetime, final String... servers) { + final Inet6Address[] serverArray = new Inet6Address[servers.length]; + for (int i = 0; i < servers.length; i++) { + serverArray[i] = (Inet6Address) InetAddresses.parseNumericAddress(servers[i]); + } + return build(lifetime, serverArray); + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/RsHeader.java b/staticlibs/device/com/android/net/module/util/structs/RsHeader.java new file mode 100644 index 0000000000..0b51ff25fd --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/RsHeader.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * ICMPv6 Router Solicitation header, follow [Icmpv6Header], as per + * https://tools.ietf.org/html/rfc4861. This does not contain any option. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Options ... + * +-+-+-+-+-+-+-+-+-+-+-+- + */ +public class RsHeader extends Struct { + @Field(order = 0, type = Type.S32) + public final int reserved; + + public RsHeader(final int reserved) { + this.reserved = reserved; + } +} From 9d4d4b28fbb1413bd4f9ad938fbbcc9a9642b366 Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Fri, 26 Feb 2021 20:02:44 +0000 Subject: [PATCH 132/777] Revert "Add utilities to create IPv6 ICMP messages." Revert "Rename net-utils-framework-common in FrameworksTelephony..." Revert submission 1579863-ipv6_utils Reason for revert: Build breakage Bug: 181339273 Reverted Changes: I0d3b133e5:Rename net-utils-framework-common in FrameworksTel... I1c050ae42:Add utilities to create IPv6 ICMP messages. Change-Id: I2b3a26d6fe22c24618e3cab61f717a8b991f2b4d --- staticlibs/Android.bp | 4 - .../android/net/module/util/Ipv6Utils.java | 136 ------------------ .../module/util/structs/EthernetHeader.java | 60 -------- .../net/module/util/structs/Icmpv6Header.java | 45 ------ .../net/module/util/structs/Ipv6Header.java | 75 ---------- .../net/module/util/structs/LlaOption.java | 59 -------- .../net/module/util/structs/MtuOption.java | 65 --------- .../net/module/util/structs/NaHeader.java | 57 -------- .../util/structs/PrefixInformationOption.java | 97 ------------- .../net/module/util/structs/RaHeader.java | 62 -------- .../net/module/util/structs/RdnssOption.java | 90 ------------ .../net/module/util/structs/RsHeader.java | 44 ------ 12 files changed, 794 deletions(-) delete mode 100644 staticlibs/device/com/android/net/module/util/Ipv6Utils.java delete mode 100644 staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java delete mode 100644 staticlibs/device/com/android/net/module/util/structs/Icmpv6Header.java delete mode 100644 staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java delete mode 100644 staticlibs/device/com/android/net/module/util/structs/LlaOption.java delete mode 100644 staticlibs/device/com/android/net/module/util/structs/MtuOption.java delete mode 100644 staticlibs/device/com/android/net/module/util/structs/NaHeader.java delete mode 100644 staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java delete mode 100644 staticlibs/device/com/android/net/module/util/structs/RaHeader.java delete mode 100644 staticlibs/device/com/android/net/module/util/structs/RdnssOption.java delete mode 100644 staticlibs/device/com/android/net/module/util/structs/RsHeader.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 03296e7304..a3bfbce94a 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -60,9 +60,6 @@ java_library { "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", ], - static_libs: [ - "net-utils-framework-common", - ], libs: [ "androidx.annotation_annotation", ], @@ -149,7 +146,6 @@ java_library { "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", - "//frameworks/libs/net/common/device", "//packages/modules/Wifi/framework/tests:__subpackages__", ] } diff --git a/staticlibs/device/com/android/net/module/util/Ipv6Utils.java b/staticlibs/device/com/android/net/module/util/Ipv6Utils.java deleted file mode 100644 index 73c2431d76..0000000000 --- a/staticlibs/device/com/android/net/module/util/Ipv6Utils.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util; - -import static android.system.OsConstants.IPPROTO_ICMPV6; - -import static com.android.net.module.util.IpUtils.icmpv6Checksum; -import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6; -import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT; -import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT; -import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION; - -import android.net.MacAddress; - -import com.android.net.module.util.structs.EthernetHeader; -import com.android.net.module.util.structs.Icmpv6Header; -import com.android.net.module.util.structs.Ipv6Header; -import com.android.net.module.util.structs.NaHeader; -import com.android.net.module.util.structs.RaHeader; -import com.android.net.module.util.structs.RsHeader; - -import java.net.Inet6Address; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * Utilities for IPv6 packets. - */ -public class Ipv6Utils { - /** - * Build a generic ICMPv6 packet(e.g., packet used in the neighbor discovery protocol). - */ - public static ByteBuffer buildIcmpv6Packet(final MacAddress srcMac, final MacAddress dstMac, - final Inet6Address srcIp, final Inet6Address dstIp, short type, short code, - final ByteBuffer... options) { - final int etherHeaderLen = Struct.getSize(EthernetHeader.class); - final int ipv6HeaderLen = Struct.getSize(Ipv6Header.class); - final int icmpv6HeaderLen = Struct.getSize(Icmpv6Header.class); - int payloadLen = 0; - for (ByteBuffer option: options) { - payloadLen += option.limit(); - } - final ByteBuffer packet = ByteBuffer.allocate(etherHeaderLen + ipv6HeaderLen - + icmpv6HeaderLen + payloadLen); - final EthernetHeader ethHeader = - new EthernetHeader(dstMac, srcMac, (short) ETHER_TYPE_IPV6); - final Ipv6Header ipv6Header = - new Ipv6Header((int) 0x60000000 /* version, traffic class, flowlabel */, - icmpv6HeaderLen + payloadLen /* payload length */, - (byte) IPPROTO_ICMPV6 /* next header */, (byte) 0xff /* hop limit */, srcIp, dstIp); - final Icmpv6Header icmpv6Header = new Icmpv6Header(type, code, (short) 0 /* checksum */); - - ethHeader.writeToByteBuffer(packet); - ipv6Header.writeToByteBuffer(packet); - icmpv6Header.writeToByteBuffer(packet); - for (ByteBuffer option : options) { - packet.put(option); - // in case option might be reused by caller, restore the position and - // limit of bytebuffer. - option.clear(); - } - packet.flip(); - - // Populate the ICMPv6 checksum field. - packet.putShort(etherHeaderLen + ipv6HeaderLen + 2, icmpv6Checksum(packet, - etherHeaderLen /* ipOffset */, - (int) (etherHeaderLen + ipv6HeaderLen) /* transportOffset */, - (short) (icmpv6HeaderLen + payloadLen) /* transportLen */)); - return packet; - } - - /** - * Build the ICMPv6 packet payload including payload header and specific options. - */ - private static ByteBuffer[] buildIcmpv6Payload(final ByteBuffer payloadHeader, - final ByteBuffer... options) { - final ByteBuffer[] payload = new ByteBuffer[options.length + 1]; - payload[0] = payloadHeader; - System.arraycopy(options, 0, payload, 1, options.length); - return payload; - } - - /** - * Build an ICMPv6 Router Advertisement packet from the required specified parameters. - */ - public static ByteBuffer buildRaPacket(final MacAddress srcMac, final MacAddress dstMac, - final Inet6Address srcIp, final Inet6Address dstIp, final byte flags, - final int lifetime, final long reachableTime, final long retransTimer, - final ByteBuffer... options) { - final RaHeader raHeader = new RaHeader((byte) 0 /* hopLimit, unspecified */, - flags, lifetime, reachableTime, retransTimer); - final ByteBuffer[] payload = buildIcmpv6Payload( - ByteBuffer.wrap(raHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options); - return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, - (byte) ICMPV6_ROUTER_ADVERTISEMENT /* type */, (byte) 0 /* code */, payload); - } - - /** - * Build an ICMPv6 Neighbor Advertisement packet from the required specified parameters. - */ - public static ByteBuffer buildNaPacket(final MacAddress srcMac, final MacAddress dstMac, - final Inet6Address srcIp, final Inet6Address dstIp, final int flags, - final Inet6Address target, final ByteBuffer... options) { - final NaHeader naHeader = new NaHeader(flags, target); - final ByteBuffer[] payload = buildIcmpv6Payload( - ByteBuffer.wrap(naHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options); - return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, - (byte) ICMPV6_NEIGHBOR_ADVERTISEMENT /* type */, (byte) 0 /* code */, payload); - } - - /** - * Build an ICMPv6 Router Solicitation packet from the required specified parameters. - */ - public static ByteBuffer buildRsPacket(final MacAddress srcMac, final MacAddress dstMac, - final Inet6Address srcIp, final Inet6Address dstIp, final ByteBuffer... options) { - final RsHeader rsHeader = new RsHeader((int) 0 /* reserved */); - final ByteBuffer[] payload = buildIcmpv6Payload( - ByteBuffer.wrap(rsHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options); - return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, - (byte) ICMPV6_ROUTER_SOLICITATION /* type */, (byte) 0 /* code */, payload); - } -} diff --git a/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java b/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java deleted file mode 100644 index d895cfaad7..0000000000 --- a/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import android.net.MacAddress; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * L2 ethernet header as per IEEE 802.3. Does not include a 802.1Q tag. - * - * 0 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Destination | - * +- -+ - * | Ethernet | - * +- -+ - * | Address | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Source | - * +- -+ - * | Ethernet | - * +- -+ - * | Address | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |1 0 0 0 0 1 1 0 1 1 0 1 1 1 0 1| - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class EthernetHeader extends Struct { - @Field(order = 0, type = Type.EUI48) - public final MacAddress dstMac; - @Field(order = 1, type = Type.EUI48) - public final MacAddress srcMac; - @Field(order = 2, type = Type.U16) - public final int etherType; - - public EthernetHeader(final MacAddress dstMac, final MacAddress srcMac, - final int etherType) { - this.dstMac = dstMac; - this.srcMac = srcMac; - this.etherType = etherType; - } -} diff --git a/staticlibs/device/com/android/net/module/util/structs/Icmpv6Header.java b/staticlibs/device/com/android/net/module/util/structs/Icmpv6Header.java deleted file mode 100644 index c82ae02b0d..0000000000 --- a/staticlibs/device/com/android/net/module/util/structs/Icmpv6Header.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * ICMPv6 header as per https://tools.ietf.org/html/rfc4443. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Code | Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class Icmpv6Header extends Struct { - @Field(order = 0, type = Type.U8) - public short type; - @Field(order = 1, type = Type.U8) - public short code; - @Field(order = 2, type = Type.S16) - public short checksum; - - public Icmpv6Header(final short type, final short code, final short checksum) { - this.type = type; - this.code = code; - this.checksum = checksum; - } -} diff --git a/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java b/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java deleted file mode 100644 index 3ad81570e9..0000000000 --- a/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.net.Inet6Address; - -/** - * L3 IPv6 header as per https://tools.ietf.org/html/rfc8200. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |Version| Traffic Class | Flow Label | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Payload Length | Next Header | Hop Limit | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * + + - * | | - * + Source Address + - * | | - * + + - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * + + - * | | - * + Destination Address + - * | | - * + + - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class Ipv6Header extends Struct { - @Field(order = 0, type = Type.S32) - public int vtf; - @Field(order = 1, type = Type.U16) - public int length; - @Field(order = 2, type = Type.S8) - public byte nextHeader; - @Field(order = 3, type = Type.U8) - public short hopLimit; - @Field(order = 4, type = Type.Ipv6Address) - public Inet6Address srcIp; - @Field(order = 5, type = Type.Ipv6Address) - public Inet6Address dstIp; - - public Ipv6Header(final int vtf, final int length, final byte nextHeader, final short hopLimit, - final Inet6Address srcIp, final Inet6Address dstIp) { - this.vtf = vtf; - this.length = length; - this.nextHeader = nextHeader; - this.hopLimit = hopLimit; - this.srcIp = srcIp; - this.dstIp = dstIp; - } -} diff --git a/staticlibs/device/com/android/net/module/util/structs/LlaOption.java b/staticlibs/device/com/android/net/module/util/structs/LlaOption.java deleted file mode 100644 index 2cdeefb21c..0000000000 --- a/staticlibs/device/com/android/net/module/util/structs/LlaOption.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import android.net.MacAddress; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * ICMPv6 source/target link-layer address option, as per https://tools.ietf.org/html/rfc4861. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Length | Link-Layer Address ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class LlaOption extends Struct { - @Field(order = 0, type = Type.S8) - // 1 for Source Link-layer Address; 2 for Target Link-layer Address. - public final byte type; - @Field(order = 1, type = Type.S8) - public final byte length; // Length in 8-byte units - @Field(order = 2, type = Type.EUI48) - public final MacAddress linkLayerAddress; - - public LlaOption(final byte type, final byte length, final MacAddress linkLayerAddress) { - this.type = type; - this.length = length; - this.linkLayerAddress = linkLayerAddress; - } - - /** - * Build a target link-layer address option from the required specified parameters. - */ - public static ByteBuffer build(final byte type, final MacAddress linkLayerAddress) { - final LlaOption option = new LlaOption(type, (byte) 1 /* option len */, linkLayerAddress); - return ByteBuffer.wrap(option.writeToBytes(ByteOrder.nativeOrder())); - } -} diff --git a/staticlibs/device/com/android/net/module/util/structs/MtuOption.java b/staticlibs/device/com/android/net/module/util/structs/MtuOption.java deleted file mode 100644 index a35b57631a..0000000000 --- a/staticlibs/device/com/android/net/module/util/structs/MtuOption.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_MTU; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * ICMPv6 MTU option, as per https://tools.ietf.org/html/rfc4861. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Length | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | MTU | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class MtuOption extends Struct { - @Field(order = 0, type = Type.S8) - public final byte type; - @Field(order = 1, type = Type.S8) - public final byte length; // Length in 8-byte units - @Field(order = 2, type = Type.S16) - public final short reserved; - @Field(order = 3, type = Type.U32) - public final long mtu; - - public MtuOption(final byte type, final byte length, final short reserved, - final long mtu) { - this.type = type; - this.length = length; - this.reserved = reserved; - this.mtu = mtu; - } - - /** - * Build a MTU option from the required specified parameters. - */ - public static ByteBuffer build(final long mtu) { - final MtuOption option = new MtuOption((byte) ICMPV6_ND_OPTION_MTU, - (byte) 1 /* option len */, (short) 0 /* reserved */, mtu); - return ByteBuffer.wrap(option.writeToBytes(ByteOrder.nativeOrder())); - } -} diff --git a/staticlibs/device/com/android/net/module/util/structs/NaHeader.java b/staticlibs/device/com/android/net/module/util/structs/NaHeader.java deleted file mode 100644 index 8101b06156..0000000000 --- a/staticlibs/device/com/android/net/module/util/structs/NaHeader.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.net.Inet6Address; - -/** - * ICMPv6 Neighbor Advertisement header, follow [Icmpv6Header], as per - * https://tools.ietf.org/html/rfc4861. This does not contain any option. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Code | Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |R|S|O| Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * + + - * | | - * + Target Address + - * | | - * + + - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Options ... - * +-+-+-+-+-+-+-+-+-+-+-+- - */ -public class NaHeader extends Struct { - @Field(order = 0, type = Type.S32) - public int flags; // Router flag, Solicited flag, Override flag and 29 Reserved bits. - @Field(order = 1, type = Type.Ipv6Address) - public Inet6Address target; - - public NaHeader(final int flags, final Inet6Address target) { - this.flags = flags; - this.target = target; - } -} diff --git a/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java b/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java deleted file mode 100644 index 7dc0192f87..0000000000 --- a/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_PIO; - -import android.annotation.NonNull; -import android.net.IpPrefix; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * ICMPv6 prefix information option, as per https://tools.ietf.org/html/rfc4861. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Length | Prefix Length |L|A| Reserved1 | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Valid Lifetime | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Preferred Lifetime | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Reserved2 | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * + + - * | | - * + Prefix + - * | | - * + + - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class PrefixInformationOption extends Struct { - @Field(order = 0, type = Type.S8) - public final byte type; - @Field(order = 1, type = Type.S8) - public final byte length; // Length in 8-byte units - @Field(order = 2, type = Type.S8) - public final byte prefixLen; - @Field(order = 3, type = Type.S8) - // On-link flag, Autonomous address configuration flag, 6-reserved bits - public final byte flags; - @Field(order = 4, type = Type.U32) - public final long validLifetime; - @Field(order = 5, type = Type.U32) - public final long preferredLifetime; - @Field(order = 6, type = Type.S32) - public final int reserved; - @Field(order = 7, type = Type.ByteArray, arraysize = 16) - public final byte[] prefix; - - public PrefixInformationOption(final byte type, final byte length, final byte prefixLen, - final byte flags, final long validLifetime, final long preferredLifetime, - final int reserved, @NonNull final byte[] prefix) { - this.type = type; - this.length = length; - this.prefixLen = prefixLen; - this.flags = flags; - this.validLifetime = validLifetime; - this.preferredLifetime = preferredLifetime; - this.reserved = reserved; - this.prefix = prefix; - } - - /** - * Build a Prefix Information option from the required specified parameters. - */ - public static ByteBuffer build(final IpPrefix prefix, final byte flags, - final long validLifetime, final long preferredLifetime) { - final PrefixInformationOption option = new PrefixInformationOption( - (byte) ICMPV6_ND_OPTION_PIO, (byte) 4 /* option len */, - (byte) prefix.getPrefixLength(), flags, validLifetime, preferredLifetime, - (int) 0, prefix.getRawAddress()); - return ByteBuffer.wrap(option.writeToBytes(ByteOrder.nativeOrder())); - } -} diff --git a/staticlibs/device/com/android/net/module/util/structs/RaHeader.java b/staticlibs/device/com/android/net/module/util/structs/RaHeader.java deleted file mode 100644 index 31a5cb76fc..0000000000 --- a/staticlibs/device/com/android/net/module/util/structs/RaHeader.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * ICMPv6 Router Advertisement header, follow [Icmpv6Header], as per - * https://tools.ietf.org/html/rfc4861. This does not contain any option. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Code | Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Cur Hop Limit |M|O| Reserved | Router Lifetime | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Reachable Time | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Retrans Timer | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Options ... - * +-+-+-+-+-+-+-+-+-+-+-+- - */ -public class RaHeader extends Struct { - @Field(order = 0, type = Type.S8) - public final byte hopLimit; - // "Managed address configuration", "Other configuration" bits, and 6 reserved bits - @Field(order = 1, type = Type.S8) - public final byte flags; - @Field(order = 2, type = Type.U16) - public final int lifetime; - @Field(order = 3, type = Type.U32) - public final long reachableTime; - @Field(order = 4, type = Type.U32) - public final long retransTimer; - - public RaHeader(final byte hopLimit, final byte flags, final int lifetime, - final long reachableTime, final long retransTimer) { - this.hopLimit = hopLimit; - this.flags = flags; - this.lifetime = lifetime; - this.reachableTime = reachableTime; - this.retransTimer = retransTimer; - } -} diff --git a/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java b/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java deleted file mode 100644 index de55e66053..0000000000 --- a/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_RDNSS; - -import android.net.InetAddresses; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.net.Inet6Address; -import java.nio.ByteBuffer; - -/** - * IPv6 RA recursive DNS server option, as per https://tools.ietf.org/html/rfc8106. - * This should be followed by a series of DNSv6 server addresses. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Length | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Lifetime | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * : Addresses of IPv6 Recursive DNS Servers : - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class RdnssOption extends Struct { - @Field(order = 0, type = Type.S8) - public final byte type; - @Field(order = 1, type = Type.S8) - public final byte length; // Length in 8-byte units - @Field(order = 2, type = Type.S16) - public final short reserved; - @Field(order = 3, type = Type.U32) - public final long lifetime; - - public RdnssOption(final byte type, final byte length, final short reserved, - final long lifetime) { - this.type = type; - this.length = length; - this.reserved = reserved; - this.lifetime = lifetime; - } - - /** - * Build a RDNSS option from the required specified Inet6Address parameters. - */ - public static ByteBuffer build(final long lifetime, final Inet6Address... servers) { - final byte length = (byte) (1 + 2 * servers.length); - final RdnssOption option = new RdnssOption((byte) ICMPV6_ND_OPTION_RDNSS, - length, (short) 0, lifetime); - final ByteBuffer buffer = ByteBuffer.allocate(length * 8); - option.writeToByteBuffer(buffer); - for (Inet6Address server : servers) { - buffer.put(server.getAddress()); - } - buffer.flip(); - return buffer; - } - - /** - * Build a RDNSS option from the required specified String parameters. - */ - public static ByteBuffer build(final long lifetime, final String... servers) { - final Inet6Address[] serverArray = new Inet6Address[servers.length]; - for (int i = 0; i < servers.length; i++) { - serverArray[i] = (Inet6Address) InetAddresses.parseNumericAddress(servers[i]); - } - return build(lifetime, serverArray); - } -} diff --git a/staticlibs/device/com/android/net/module/util/structs/RsHeader.java b/staticlibs/device/com/android/net/module/util/structs/RsHeader.java deleted file mode 100644 index 0b51ff25fd..0000000000 --- a/staticlibs/device/com/android/net/module/util/structs/RsHeader.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * ICMPv6 Router Solicitation header, follow [Icmpv6Header], as per - * https://tools.ietf.org/html/rfc4861. This does not contain any option. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Code | Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Options ... - * +-+-+-+-+-+-+-+-+-+-+-+- - */ -public class RsHeader extends Struct { - @Field(order = 0, type = Type.S32) - public final int reserved; - - public RsHeader(final int reserved) { - this.reserved = reserved; - } -} From 5c1745477f3cf98a1c872124006a70f91a8a4797 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Sun, 28 Feb 2021 13:09:23 +0000 Subject: [PATCH 133/777] Revert "Revert "Add utilities to create IPv6 ICMP messages."" This reverts commit 405c1bfca93fa25ae1616a93ee6e2a1f76d87d1e. Bug: 168868607 Test: atest NetworkStackIntegrationTest Reason for revert: Roll forward the previous change and try to merge it one by one instead of using the topic, which should avoid the build broken on the sc-dev branch due to the deferred auto-merge process. Change-Id: I751fbd9d978ed60206bab009212f621fe902f321 --- staticlibs/Android.bp | 4 + .../android/net/module/util/Ipv6Utils.java | 136 ++++++++++++++++++ .../module/util/structs/EthernetHeader.java | 60 ++++++++ .../net/module/util/structs/Icmpv6Header.java | 45 ++++++ .../net/module/util/structs/Ipv6Header.java | 75 ++++++++++ .../net/module/util/structs/LlaOption.java | 59 ++++++++ .../net/module/util/structs/MtuOption.java | 65 +++++++++ .../net/module/util/structs/NaHeader.java | 57 ++++++++ .../util/structs/PrefixInformationOption.java | 97 +++++++++++++ .../net/module/util/structs/RaHeader.java | 62 ++++++++ .../net/module/util/structs/RdnssOption.java | 90 ++++++++++++ .../net/module/util/structs/RsHeader.java | 44 ++++++ 12 files changed, 794 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/Ipv6Utils.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/Icmpv6Header.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/LlaOption.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/MtuOption.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/NaHeader.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/RaHeader.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/RdnssOption.java create mode 100644 staticlibs/device/com/android/net/module/util/structs/RsHeader.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index a3bfbce94a..03296e7304 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -60,6 +60,9 @@ java_library { "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", ], + static_libs: [ + "net-utils-framework-common", + ], libs: [ "androidx.annotation_annotation", ], @@ -146,6 +149,7 @@ java_library { "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", + "//frameworks/libs/net/common/device", "//packages/modules/Wifi/framework/tests:__subpackages__", ] } diff --git a/staticlibs/device/com/android/net/module/util/Ipv6Utils.java b/staticlibs/device/com/android/net/module/util/Ipv6Utils.java new file mode 100644 index 0000000000..73c2431d76 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/Ipv6Utils.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util; + +import static android.system.OsConstants.IPPROTO_ICMPV6; + +import static com.android.net.module.util.IpUtils.icmpv6Checksum; +import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION; + +import android.net.MacAddress; + +import com.android.net.module.util.structs.EthernetHeader; +import com.android.net.module.util.structs.Icmpv6Header; +import com.android.net.module.util.structs.Ipv6Header; +import com.android.net.module.util.structs.NaHeader; +import com.android.net.module.util.structs.RaHeader; +import com.android.net.module.util.structs.RsHeader; + +import java.net.Inet6Address; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * Utilities for IPv6 packets. + */ +public class Ipv6Utils { + /** + * Build a generic ICMPv6 packet(e.g., packet used in the neighbor discovery protocol). + */ + public static ByteBuffer buildIcmpv6Packet(final MacAddress srcMac, final MacAddress dstMac, + final Inet6Address srcIp, final Inet6Address dstIp, short type, short code, + final ByteBuffer... options) { + final int etherHeaderLen = Struct.getSize(EthernetHeader.class); + final int ipv6HeaderLen = Struct.getSize(Ipv6Header.class); + final int icmpv6HeaderLen = Struct.getSize(Icmpv6Header.class); + int payloadLen = 0; + for (ByteBuffer option: options) { + payloadLen += option.limit(); + } + final ByteBuffer packet = ByteBuffer.allocate(etherHeaderLen + ipv6HeaderLen + + icmpv6HeaderLen + payloadLen); + final EthernetHeader ethHeader = + new EthernetHeader(dstMac, srcMac, (short) ETHER_TYPE_IPV6); + final Ipv6Header ipv6Header = + new Ipv6Header((int) 0x60000000 /* version, traffic class, flowlabel */, + icmpv6HeaderLen + payloadLen /* payload length */, + (byte) IPPROTO_ICMPV6 /* next header */, (byte) 0xff /* hop limit */, srcIp, dstIp); + final Icmpv6Header icmpv6Header = new Icmpv6Header(type, code, (short) 0 /* checksum */); + + ethHeader.writeToByteBuffer(packet); + ipv6Header.writeToByteBuffer(packet); + icmpv6Header.writeToByteBuffer(packet); + for (ByteBuffer option : options) { + packet.put(option); + // in case option might be reused by caller, restore the position and + // limit of bytebuffer. + option.clear(); + } + packet.flip(); + + // Populate the ICMPv6 checksum field. + packet.putShort(etherHeaderLen + ipv6HeaderLen + 2, icmpv6Checksum(packet, + etherHeaderLen /* ipOffset */, + (int) (etherHeaderLen + ipv6HeaderLen) /* transportOffset */, + (short) (icmpv6HeaderLen + payloadLen) /* transportLen */)); + return packet; + } + + /** + * Build the ICMPv6 packet payload including payload header and specific options. + */ + private static ByteBuffer[] buildIcmpv6Payload(final ByteBuffer payloadHeader, + final ByteBuffer... options) { + final ByteBuffer[] payload = new ByteBuffer[options.length + 1]; + payload[0] = payloadHeader; + System.arraycopy(options, 0, payload, 1, options.length); + return payload; + } + + /** + * Build an ICMPv6 Router Advertisement packet from the required specified parameters. + */ + public static ByteBuffer buildRaPacket(final MacAddress srcMac, final MacAddress dstMac, + final Inet6Address srcIp, final Inet6Address dstIp, final byte flags, + final int lifetime, final long reachableTime, final long retransTimer, + final ByteBuffer... options) { + final RaHeader raHeader = new RaHeader((byte) 0 /* hopLimit, unspecified */, + flags, lifetime, reachableTime, retransTimer); + final ByteBuffer[] payload = buildIcmpv6Payload( + ByteBuffer.wrap(raHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options); + return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, + (byte) ICMPV6_ROUTER_ADVERTISEMENT /* type */, (byte) 0 /* code */, payload); + } + + /** + * Build an ICMPv6 Neighbor Advertisement packet from the required specified parameters. + */ + public static ByteBuffer buildNaPacket(final MacAddress srcMac, final MacAddress dstMac, + final Inet6Address srcIp, final Inet6Address dstIp, final int flags, + final Inet6Address target, final ByteBuffer... options) { + final NaHeader naHeader = new NaHeader(flags, target); + final ByteBuffer[] payload = buildIcmpv6Payload( + ByteBuffer.wrap(naHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options); + return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, + (byte) ICMPV6_NEIGHBOR_ADVERTISEMENT /* type */, (byte) 0 /* code */, payload); + } + + /** + * Build an ICMPv6 Router Solicitation packet from the required specified parameters. + */ + public static ByteBuffer buildRsPacket(final MacAddress srcMac, final MacAddress dstMac, + final Inet6Address srcIp, final Inet6Address dstIp, final ByteBuffer... options) { + final RsHeader rsHeader = new RsHeader((int) 0 /* reserved */); + final ByteBuffer[] payload = buildIcmpv6Payload( + ByteBuffer.wrap(rsHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options); + return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, + (byte) ICMPV6_ROUTER_SOLICITATION /* type */, (byte) 0 /* code */, payload); + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java b/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java new file mode 100644 index 0000000000..d895cfaad7 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import android.net.MacAddress; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * L2 ethernet header as per IEEE 802.3. Does not include a 802.1Q tag. + * + * 0 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Destination | + * +- -+ + * | Ethernet | + * +- -+ + * | Address | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source | + * +- -+ + * | Ethernet | + * +- -+ + * | Address | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |1 0 0 0 0 1 1 0 1 1 0 1 1 1 0 1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class EthernetHeader extends Struct { + @Field(order = 0, type = Type.EUI48) + public final MacAddress dstMac; + @Field(order = 1, type = Type.EUI48) + public final MacAddress srcMac; + @Field(order = 2, type = Type.U16) + public final int etherType; + + public EthernetHeader(final MacAddress dstMac, final MacAddress srcMac, + final int etherType) { + this.dstMac = dstMac; + this.srcMac = srcMac; + this.etherType = etherType; + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/Icmpv6Header.java b/staticlibs/device/com/android/net/module/util/structs/Icmpv6Header.java new file mode 100644 index 0000000000..c82ae02b0d --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/Icmpv6Header.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * ICMPv6 header as per https://tools.ietf.org/html/rfc4443. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class Icmpv6Header extends Struct { + @Field(order = 0, type = Type.U8) + public short type; + @Field(order = 1, type = Type.U8) + public short code; + @Field(order = 2, type = Type.S16) + public short checksum; + + public Icmpv6Header(final short type, final short code, final short checksum) { + this.type = type; + this.code = code; + this.checksum = checksum; + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java b/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java new file mode 100644 index 0000000000..3ad81570e9 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.Inet6Address; + +/** + * L3 IPv6 header as per https://tools.ietf.org/html/rfc8200. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Version| Traffic Class | Flow Label | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Payload Length | Next Header | Hop Limit | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Source Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Destination Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class Ipv6Header extends Struct { + @Field(order = 0, type = Type.S32) + public int vtf; + @Field(order = 1, type = Type.U16) + public int length; + @Field(order = 2, type = Type.S8) + public byte nextHeader; + @Field(order = 3, type = Type.U8) + public short hopLimit; + @Field(order = 4, type = Type.Ipv6Address) + public Inet6Address srcIp; + @Field(order = 5, type = Type.Ipv6Address) + public Inet6Address dstIp; + + public Ipv6Header(final int vtf, final int length, final byte nextHeader, final short hopLimit, + final Inet6Address srcIp, final Inet6Address dstIp) { + this.vtf = vtf; + this.length = length; + this.nextHeader = nextHeader; + this.hopLimit = hopLimit; + this.srcIp = srcIp; + this.dstIp = dstIp; + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/LlaOption.java b/staticlibs/device/com/android/net/module/util/structs/LlaOption.java new file mode 100644 index 0000000000..2cdeefb21c --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/LlaOption.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import android.net.MacAddress; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * ICMPv6 source/target link-layer address option, as per https://tools.ietf.org/html/rfc4861. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Link-Layer Address ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class LlaOption extends Struct { + @Field(order = 0, type = Type.S8) + // 1 for Source Link-layer Address; 2 for Target Link-layer Address. + public final byte type; + @Field(order = 1, type = Type.S8) + public final byte length; // Length in 8-byte units + @Field(order = 2, type = Type.EUI48) + public final MacAddress linkLayerAddress; + + public LlaOption(final byte type, final byte length, final MacAddress linkLayerAddress) { + this.type = type; + this.length = length; + this.linkLayerAddress = linkLayerAddress; + } + + /** + * Build a target link-layer address option from the required specified parameters. + */ + public static ByteBuffer build(final byte type, final MacAddress linkLayerAddress) { + final LlaOption option = new LlaOption(type, (byte) 1 /* option len */, linkLayerAddress); + return ByteBuffer.wrap(option.writeToBytes(ByteOrder.nativeOrder())); + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/MtuOption.java b/staticlibs/device/com/android/net/module/util/structs/MtuOption.java new file mode 100644 index 0000000000..a35b57631a --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/MtuOption.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_MTU; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * ICMPv6 MTU option, as per https://tools.ietf.org/html/rfc4861. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | MTU | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class MtuOption extends Struct { + @Field(order = 0, type = Type.S8) + public final byte type; + @Field(order = 1, type = Type.S8) + public final byte length; // Length in 8-byte units + @Field(order = 2, type = Type.S16) + public final short reserved; + @Field(order = 3, type = Type.U32) + public final long mtu; + + public MtuOption(final byte type, final byte length, final short reserved, + final long mtu) { + this.type = type; + this.length = length; + this.reserved = reserved; + this.mtu = mtu; + } + + /** + * Build a MTU option from the required specified parameters. + */ + public static ByteBuffer build(final long mtu) { + final MtuOption option = new MtuOption((byte) ICMPV6_ND_OPTION_MTU, + (byte) 1 /* option len */, (short) 0 /* reserved */, mtu); + return ByteBuffer.wrap(option.writeToBytes(ByteOrder.nativeOrder())); + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/NaHeader.java b/staticlibs/device/com/android/net/module/util/structs/NaHeader.java new file mode 100644 index 0000000000..8101b06156 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/NaHeader.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.Inet6Address; + +/** + * ICMPv6 Neighbor Advertisement header, follow [Icmpv6Header], as per + * https://tools.ietf.org/html/rfc4861. This does not contain any option. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |R|S|O| Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Target Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Options ... + * +-+-+-+-+-+-+-+-+-+-+-+- + */ +public class NaHeader extends Struct { + @Field(order = 0, type = Type.S32) + public int flags; // Router flag, Solicited flag, Override flag and 29 Reserved bits. + @Field(order = 1, type = Type.Ipv6Address) + public Inet6Address target; + + public NaHeader(final int flags, final Inet6Address target) { + this.flags = flags; + this.target = target; + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java b/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java new file mode 100644 index 0000000000..7dc0192f87 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_PIO; + +import android.annotation.NonNull; +import android.net.IpPrefix; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * ICMPv6 prefix information option, as per https://tools.ietf.org/html/rfc4861. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Prefix Length |L|A| Reserved1 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Valid Lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Preferred Lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved2 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Prefix + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class PrefixInformationOption extends Struct { + @Field(order = 0, type = Type.S8) + public final byte type; + @Field(order = 1, type = Type.S8) + public final byte length; // Length in 8-byte units + @Field(order = 2, type = Type.S8) + public final byte prefixLen; + @Field(order = 3, type = Type.S8) + // On-link flag, Autonomous address configuration flag, 6-reserved bits + public final byte flags; + @Field(order = 4, type = Type.U32) + public final long validLifetime; + @Field(order = 5, type = Type.U32) + public final long preferredLifetime; + @Field(order = 6, type = Type.S32) + public final int reserved; + @Field(order = 7, type = Type.ByteArray, arraysize = 16) + public final byte[] prefix; + + public PrefixInformationOption(final byte type, final byte length, final byte prefixLen, + final byte flags, final long validLifetime, final long preferredLifetime, + final int reserved, @NonNull final byte[] prefix) { + this.type = type; + this.length = length; + this.prefixLen = prefixLen; + this.flags = flags; + this.validLifetime = validLifetime; + this.preferredLifetime = preferredLifetime; + this.reserved = reserved; + this.prefix = prefix; + } + + /** + * Build a Prefix Information option from the required specified parameters. + */ + public static ByteBuffer build(final IpPrefix prefix, final byte flags, + final long validLifetime, final long preferredLifetime) { + final PrefixInformationOption option = new PrefixInformationOption( + (byte) ICMPV6_ND_OPTION_PIO, (byte) 4 /* option len */, + (byte) prefix.getPrefixLength(), flags, validLifetime, preferredLifetime, + (int) 0, prefix.getRawAddress()); + return ByteBuffer.wrap(option.writeToBytes(ByteOrder.nativeOrder())); + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/RaHeader.java b/staticlibs/device/com/android/net/module/util/structs/RaHeader.java new file mode 100644 index 0000000000..31a5cb76fc --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/RaHeader.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * ICMPv6 Router Advertisement header, follow [Icmpv6Header], as per + * https://tools.ietf.org/html/rfc4861. This does not contain any option. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Cur Hop Limit |M|O| Reserved | Router Lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reachable Time | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Retrans Timer | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Options ... + * +-+-+-+-+-+-+-+-+-+-+-+- + */ +public class RaHeader extends Struct { + @Field(order = 0, type = Type.S8) + public final byte hopLimit; + // "Managed address configuration", "Other configuration" bits, and 6 reserved bits + @Field(order = 1, type = Type.S8) + public final byte flags; + @Field(order = 2, type = Type.U16) + public final int lifetime; + @Field(order = 3, type = Type.U32) + public final long reachableTime; + @Field(order = 4, type = Type.U32) + public final long retransTimer; + + public RaHeader(final byte hopLimit, final byte flags, final int lifetime, + final long reachableTime, final long retransTimer) { + this.hopLimit = hopLimit; + this.flags = flags; + this.lifetime = lifetime; + this.reachableTime = reachableTime; + this.retransTimer = retransTimer; + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java b/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java new file mode 100644 index 0000000000..de55e66053 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_RDNSS; + +import android.net.InetAddresses; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.Inet6Address; +import java.nio.ByteBuffer; + +/** + * IPv6 RA recursive DNS server option, as per https://tools.ietf.org/html/rfc8106. + * This should be followed by a series of DNSv6 server addresses. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * : Addresses of IPv6 Recursive DNS Servers : + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class RdnssOption extends Struct { + @Field(order = 0, type = Type.S8) + public final byte type; + @Field(order = 1, type = Type.S8) + public final byte length; // Length in 8-byte units + @Field(order = 2, type = Type.S16) + public final short reserved; + @Field(order = 3, type = Type.U32) + public final long lifetime; + + public RdnssOption(final byte type, final byte length, final short reserved, + final long lifetime) { + this.type = type; + this.length = length; + this.reserved = reserved; + this.lifetime = lifetime; + } + + /** + * Build a RDNSS option from the required specified Inet6Address parameters. + */ + public static ByteBuffer build(final long lifetime, final Inet6Address... servers) { + final byte length = (byte) (1 + 2 * servers.length); + final RdnssOption option = new RdnssOption((byte) ICMPV6_ND_OPTION_RDNSS, + length, (short) 0, lifetime); + final ByteBuffer buffer = ByteBuffer.allocate(length * 8); + option.writeToByteBuffer(buffer); + for (Inet6Address server : servers) { + buffer.put(server.getAddress()); + } + buffer.flip(); + return buffer; + } + + /** + * Build a RDNSS option from the required specified String parameters. + */ + public static ByteBuffer build(final long lifetime, final String... servers) { + final Inet6Address[] serverArray = new Inet6Address[servers.length]; + for (int i = 0; i < servers.length; i++) { + serverArray[i] = (Inet6Address) InetAddresses.parseNumericAddress(servers[i]); + } + return build(lifetime, serverArray); + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/RsHeader.java b/staticlibs/device/com/android/net/module/util/structs/RsHeader.java new file mode 100644 index 0000000000..0b51ff25fd --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/RsHeader.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * ICMPv6 Router Solicitation header, follow [Icmpv6Header], as per + * https://tools.ietf.org/html/rfc4861. This does not contain any option. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Options ... + * +-+-+-+-+-+-+-+-+-+-+-+- + */ +public class RsHeader extends Struct { + @Field(order = 0, type = Type.S32) + public final int reserved; + + public RsHeader(final int reserved) { + this.reserved = reserved; + } +} From 9671ec4073f096acaeaa2e60a64810d2067f39f2 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 4 Feb 2021 16:57:19 +0900 Subject: [PATCH 134/777] Rename StringNetworkSpecifier to Ethernet To keep the tests passing on Q and R, add a CompatUtil class that will keep creating StringNetworkSpecifiers (now removed) instead. Bug: 179329291 Test: atest CtsNetTestCases Merged-In: I14c1ac7cee0ec32353b38ebca4ae6c5cd2e25541 Change-Id: I14c1ac7cee0ec32353b38ebca4ae6c5cd2e25541 --- .../com/android/testutils/CompatUtil.kt | 53 +++++++++++++++++++ .../android/testutils/TestNetworkTracker.kt | 3 +- 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 staticlibs/devicetests/com/android/testutils/CompatUtil.kt diff --git a/staticlibs/devicetests/com/android/testutils/CompatUtil.kt b/staticlibs/devicetests/com/android/testutils/CompatUtil.kt new file mode 100644 index 0000000000..4bb90a80e5 --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/CompatUtil.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 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 com.android.testutils + +import android.net.NetworkSpecifier +import android.os.Build + +/** + * Test utility to create [NetworkSpecifier]s on different SDK versions. + */ +object CompatUtil { + @JvmStatic + fun makeTestNetworkSpecifier(ifName: String): NetworkSpecifier { + // Until R, there was no TestNetworkSpecifier, StringNetworkSpecifier was used instead + if (isDevSdkInRange(minExclusive = null, maxInclusive = Build.VERSION_CODES.R)) { + makeNetworkSpecifierInternal("android.net.StringNetworkSpecifier", ifName) + } + // TestNetworkSpecifier is not part of the SDK in some branches using this utility + // TODO: replace with a direct call to the constructor + return makeNetworkSpecifierInternal("android.net.TestNetworkSpecifier", ifName) + } + + @JvmStatic + fun makeEthernetNetworkSpecifier(ifName: String): NetworkSpecifier { + // Until R, there was no EthernetNetworkSpecifier, StringNetworkSpecifier was used instead + if (isDevSdkInRange(minExclusive = null, maxInclusive = Build.VERSION_CODES.R)) { + makeNetworkSpecifierInternal("android.net.StringNetworkSpecifier", ifName) + } + // EthernetNetworkSpecifier is not part of the SDK in some branches using this utility + // TODO: replace with a direct call to the constructor + return makeNetworkSpecifierInternal("android.net.EthernetNetworkSpecifier", ifName) + } + + private fun makeNetworkSpecifierInternal(clazz: String, specifier: String): NetworkSpecifier { + // StringNetworkSpecifier was removed after R (and was hidden API before that) + return Class.forName(clazz) + .getConstructor(String::class.java).newInstance(specifier) as NetworkSpecifier + } +} \ No newline at end of file diff --git a/staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt b/staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt index 4bd9ae8eae..5b978617aa 100644 --- a/staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt +++ b/staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt @@ -23,7 +23,6 @@ import android.net.LinkAddress import android.net.Network import android.net.NetworkCapabilities import android.net.NetworkRequest -import android.net.StringNetworkSpecifier import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.os.Binder @@ -68,7 +67,7 @@ class TestNetworkTracker internal constructor( // Test networks do not have NOT_VPN or TRUSTED capabilities by default .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) - .setNetworkSpecifier(StringNetworkSpecifier(iface.interfaceName)) + .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(iface.interfaceName)) .build() networkCallback = object : NetworkCallback() { override fun onAvailable(network: Network) { From bdb1b50f7bd0af5dfb8cf7bf5cb71cfa59f70192 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 2 Mar 2021 13:24:52 +0900 Subject: [PATCH 135/777] Add CollectionUtils.indexOf indexOf() is based on the current any() implementation, but gives more flexibility as the caller can know the position of the found element. Bug: 174541037 Test: atest NetworkStaticLibTests Change-Id: I1d679b8369aeee359516bb5ca4275c744a606c3a --- .../android/net/module/util/CollectionUtils.java | 15 +++++++++++++-- .../net/module/util/CollectionUtilsTest.kt | 10 ++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index e5bb58d4ba..115f19d062 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -76,15 +76,26 @@ public final class CollectionUtils { return true; } + /** * @return True if any element satisfies the predicate, false otherwise. * Note that means this always returns false for empty collections. */ public static boolean any(@NonNull Collection elem, @NonNull Predicate predicate) { + return indexOf(elem, predicate) >= 0; + } + + /** + * @return The index of the first element that matches the predicate, or -1 if none. + */ + @Nullable + public static int indexOf(@NonNull Collection elem, @NonNull Predicate predicate) { + int idx = 0; for (final T e : elem) { - if (predicate.test(e)) return true; + if (predicate.test(e)) return idx; + idx++; } - return false; + return -1; } /** diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt index 00077420de..0886426577 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt @@ -20,6 +20,7 @@ import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import org.junit.Test import org.junit.runner.RunWith +import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue @@ -39,6 +40,15 @@ class CollectionUtilsTest { assertFalse(CollectionUtils.any(listOf("A")) { false }) } + @Test + fun testIndexOf() { + assertEquals(4, CollectionUtils.indexOf(listOf("A", "B", "C", "D", "E")) { it == "E" }) + assertEquals(0, CollectionUtils.indexOf(listOf("A", "B", "C", "D", "E")) { it == "A" }) + assertEquals(1, CollectionUtils.indexOf(listOf("AA", "BBB", "CCCC")) { it.length >= 3 }) + assertEquals(1, CollectionUtils.indexOf(listOf("AA", null, "CCCC")) { it == null }) + assertEquals(1, CollectionUtils.indexOf(listOf(null, "CCCC")) { it != null }) + } + @Test fun testAll() { assertFalse(CollectionUtils.all(listOf("A", "B", "C", "D", "E")) { it != "E" }) From 19fc513d5591e43282d479245f2b78ccf7ff957f Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 4 Feb 2021 16:57:19 +0900 Subject: [PATCH 136/777] Rename StringNetworkSpecifier to Ethernet To keep the tests passing on Q and R, add a CompatUtil class that will keep creating StringNetworkSpecifiers (now removed) instead. Bug: 179329291 Test: atest CtsNetTestCases (note the merged-in is an unrelated change, just used to avoid the branch) Merged-In: I14a7c8ad27ed998f8c905c0b24cd021710081d97 Change-Id: I14c1ac7cee0ec32353b38ebca4ae6c5cd2e25541 --- .../com/android/testutils/CompatUtil.kt | 53 +++++++++++++++++++ .../android/testutils/TestNetworkTracker.kt | 3 +- 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 staticlibs/devicetests/com/android/testutils/CompatUtil.kt diff --git a/staticlibs/devicetests/com/android/testutils/CompatUtil.kt b/staticlibs/devicetests/com/android/testutils/CompatUtil.kt new file mode 100644 index 0000000000..4bb90a80e5 --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/CompatUtil.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 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 com.android.testutils + +import android.net.NetworkSpecifier +import android.os.Build + +/** + * Test utility to create [NetworkSpecifier]s on different SDK versions. + */ +object CompatUtil { + @JvmStatic + fun makeTestNetworkSpecifier(ifName: String): NetworkSpecifier { + // Until R, there was no TestNetworkSpecifier, StringNetworkSpecifier was used instead + if (isDevSdkInRange(minExclusive = null, maxInclusive = Build.VERSION_CODES.R)) { + makeNetworkSpecifierInternal("android.net.StringNetworkSpecifier", ifName) + } + // TestNetworkSpecifier is not part of the SDK in some branches using this utility + // TODO: replace with a direct call to the constructor + return makeNetworkSpecifierInternal("android.net.TestNetworkSpecifier", ifName) + } + + @JvmStatic + fun makeEthernetNetworkSpecifier(ifName: String): NetworkSpecifier { + // Until R, there was no EthernetNetworkSpecifier, StringNetworkSpecifier was used instead + if (isDevSdkInRange(minExclusive = null, maxInclusive = Build.VERSION_CODES.R)) { + makeNetworkSpecifierInternal("android.net.StringNetworkSpecifier", ifName) + } + // EthernetNetworkSpecifier is not part of the SDK in some branches using this utility + // TODO: replace with a direct call to the constructor + return makeNetworkSpecifierInternal("android.net.EthernetNetworkSpecifier", ifName) + } + + private fun makeNetworkSpecifierInternal(clazz: String, specifier: String): NetworkSpecifier { + // StringNetworkSpecifier was removed after R (and was hidden API before that) + return Class.forName(clazz) + .getConstructor(String::class.java).newInstance(specifier) as NetworkSpecifier + } +} \ No newline at end of file diff --git a/staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt b/staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt index 4bd9ae8eae..5b978617aa 100644 --- a/staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt +++ b/staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt @@ -23,7 +23,6 @@ import android.net.LinkAddress import android.net.Network import android.net.NetworkCapabilities import android.net.NetworkRequest -import android.net.StringNetworkSpecifier import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.os.Binder @@ -68,7 +67,7 @@ class TestNetworkTracker internal constructor( // Test networks do not have NOT_VPN or TRUSTED capabilities by default .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) - .setNetworkSpecifier(StringNetworkSpecifier(iface.interfaceName)) + .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(iface.interfaceName)) .build() networkCallback = object : NetworkCallback() { override fun onAvailable(network: Network) { From 9164b775c1215306e592b76f6b2a789af885031d Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Sat, 30 Jan 2021 10:48:03 +0000 Subject: [PATCH 137/777] Check the ByteArray actual size before writing it to ByteBuffer. ByteArray is the unique type whose actual size might be different with the size delcared in the annotation, e.g, user initializes an object manually, or mutates the byte array after parsing from ByteBuffer. Therefore, checking the length of byte array is required before writing the array value to output bytes array or ByteBuffer. Bug: 163492391 Test: atest NetworkStaticLibTests Change-Id: I28936a2afbe60dd2dadac803d08062df153b2588 --- .../com/android/net/module/util/Struct.java | 42 +++++++++++------- .../android/net/module/util/StructTest.java | 44 +++++++++++++++++++ 2 files changed, 71 insertions(+), 15 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/Struct.java b/staticlibs/device/com/android/net/module/util/Struct.java index f11a5acea5..d95c303714 100644 --- a/staticlibs/device/com/android/net/module/util/Struct.java +++ b/staticlibs/device/com/android/net/module/util/Struct.java @@ -17,6 +17,7 @@ package com.android.net.module.util; import android.annotation.NonNull; +import android.annotation.Nullable; import android.net.MacAddress; import java.lang.annotation.ElementType; @@ -428,6 +429,15 @@ public class Struct { return value; } + @Nullable + private Object getFieldValue(@NonNull java.lang.reflect.Field field) { + try { + return field.get(this); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Cannot access field: " + field, e); + } + } + private static void putFieldValue(final ByteBuffer output, final FieldInfo fieldInfo, final Object value) throws BufferUnderflowException { switch (fieldInfo.annotation.type()) { @@ -484,6 +494,7 @@ public class Struct { output.put(bigIntegerToU64Bytes((BigInteger) value, output.order(), Type.UBE64)); break; case ByteArray: + checkByteArraySize((byte[]) value, fieldInfo); output.put((byte[]) value); break; case EUI48: @@ -595,12 +606,23 @@ public class Struct { return size; } + // Check whether the actual size of byte array matches the array size declared in + // annotation. For other annotation types, the actual length of field could be always + // deduced from annotation correctly. + private static void checkByteArraySize(@Nullable final byte[] array, + @NonNull final FieldInfo fieldInfo) { + Objects.requireNonNull(array, "null byte array for field " + fieldInfo.field.getName()); + int annotationArraySize = fieldInfo.annotation.arraysize(); + if (array.length == annotationArraySize) return; + throw new IllegalStateException("byte array actual length: " + + array.length + " doesn't match the declared array size: " + annotationArraySize); + } + private void writeToByteBufferInternal(final ByteBuffer output, final FieldInfo[] fieldInfos) { for (FieldInfo fi : fieldInfos) { + final Object value = getFieldValue(fi.field); try { - putFieldValue(output, fi, fi.field.get(this)); - } catch (IllegalAccessException e) { - throw new IllegalArgumentException("Fail to get the field value from instance", e); + putFieldValue(output, fi, value); } catch (BufferUnderflowException e) { throw new IllegalArgumentException("Fail to fill raw data to ByteBuffer", e); } @@ -673,12 +695,7 @@ public class Struct { final FieldInfo[] fieldInfos = getClassFieldInfo(this.getClass()); final Object[] values = new Object[fieldInfos.length]; for (int i = 0; i < fieldInfos.length; i++) { - final Object value; - try { - value = fieldInfos[i].field.get(this); - } catch (IllegalAccessException e) { - throw new IllegalStateException("Cannot access field: " + fieldInfos[i].field, e); - } + final Object value = getFieldValue(fieldInfos[i].field); // For byte array field, put the hash code generated based on the array content into // the Object array instead of the reference to byte array, which might change and cause // to get a different hash code even with the exact same elements. @@ -697,12 +714,7 @@ public class Struct { final FieldInfo[] fieldInfos = getClassFieldInfo(this.getClass()); for (int i = 0; i < fieldInfos.length; i++) { sb.append(fieldInfos[i].field.getName()).append(": "); - final Object value; - try { - value = fieldInfos[i].field.get(this); - } catch (IllegalAccessException e) { - throw new IllegalStateException("Cannot access field: " + fieldInfos[i].field, e); - } + final Object value = getFieldValue(fieldInfos[i].field); if (value == null) { sb.append("null"); } else if (fieldInfos[i].annotation.type() == Type.ByteArray) { diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java index b172e2142b..df74398fe1 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java @@ -1027,4 +1027,48 @@ public class StructTest { assertTrue(msg.equals(msg1)); assertEquals(msg.hashCode(), msg1.hashCode()); } + + static class InvalidByteArray extends Struct { + @Field(order = 0, type = Type.ByteArray, arraysize = 12) public byte[] bytes; + } + + @Test + public void testStructClass_WrongByteArraySize() { + final InvalidByteArray msg = doParsingMessageTest("20010db80003000400050006", + InvalidByteArray.class, ByteOrder.BIG_ENDIAN); + + // Actual byte array size doesn't match the size declared in the annotation. + msg.bytes = new byte[16]; + assertThrows(IllegalStateException.class, () -> msg.writeToBytes()); + + final ByteBuffer output = ByteBuffer.allocate(Struct.getSize(InvalidByteArray.class)); + output.order(ByteOrder.LITTLE_ENDIAN); + assertThrows(IllegalStateException.class, () -> msg.writeToByteBuffer(output)); + } + + @Test + public void testStructClass_NullByteArray() { + final InvalidByteArray msg = doParsingMessageTest("20010db80003000400050006", + InvalidByteArray.class, ByteOrder.BIG_ENDIAN); + + msg.bytes = null; + assertThrows(NullPointerException.class, () -> msg.writeToBytes()); + + final ByteBuffer output = ByteBuffer.allocate(Struct.getSize(InvalidByteArray.class)); + output.order(ByteOrder.LITTLE_ENDIAN); + assertThrows(NullPointerException.class, () -> msg.writeToByteBuffer(output)); + } + + @Test + public void testStructClass_ParsingByteArrayAfterInitialization() { + InvalidByteArray msg = new InvalidByteArray(); + msg.bytes = new byte[]{(byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03}; + + // Although bytes member has been initialized with the length different with + // annotation size, parsing from ByteBuffer will get bytes member have the + // reference to byte array with correct size. + msg = doParsingMessageTest("20010db80003000400050006", InvalidByteArray.class, + ByteOrder.BIG_ENDIAN); + assertArrayEquals(TEST_PREFIX64, msg.bytes); + } } From 148bdcb48b62d759d9e798f470d1e190a90b9477 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 3 Mar 2021 20:21:08 +0800 Subject: [PATCH 138/777] [FUI22.1] Add assert utilities for list Test: atest NetworkStaticLibTests Bug: 174123988 Change-Id: Id918227716367264042e6b674ce29c18e2d901e4 --- .../com/android/testutils/MiscAsserts.kt | 17 +++++++++++++++++ .../net/util/LinkPropertiesUtilsTest.java | 11 ++--------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt b/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt index 09126d7992..91fb1cd43c 100644 --- a/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt +++ b/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt @@ -32,10 +32,18 @@ fun assertEmpty(ts: Array) = ts.size.let { len -> assertEquals(0, len, "Expected empty array, but length was $len") } +fun assertEmpty(ts: List) = ts.size.let { len -> + assertEquals(0, len, "Expected empty list, but length was $len") +} + fun assertLength(expected: Int, got: Array) = got.size.let { len -> assertEquals(expected, len, "Expected array of length $expected, but was $len for $got") } +fun assertLength(expected: Int, got: List) = got.size.let { len -> + assertEquals(expected, len, "Expected list of length $expected, but was $len for $got") +} + // Bridge method to help write this in Java. If you're writing Kotlin, consider using // kotlin.test.assertFailsWith instead, as that method is reified and inlined. fun assertThrows(expected: Class, block: ThrowingRunnable): T { @@ -103,3 +111,12 @@ fun assertFieldCountEquals(count: Int, clazz: Class) { !Modifier.isStatic(it.modifiers) && !Modifier.isTransient(it.modifiers) }.size) } + +fun assertSameElements(expected: List, actual: List) { + val expectedSet: HashSet = HashSet(expected) + assertEquals(expectedSet.size.toLong(), expected.size.toLong(), + "expected list contains duplicates") + val actualSet: HashSet = HashSet(actual) + assertEquals(actualSet.size.toLong(), actual.size.toLong(), "actual list contains duplicates") + assertEquals(expectedSet, actualSet) +} diff --git a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java index e47c864350..45493bd623 100644 --- a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java @@ -16,6 +16,8 @@ package android.net.util; +import static com.android.testutils.MiscAsserts.assertSameElements; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -40,7 +42,6 @@ import org.junit.runner.RunWith; import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.function.Function; @@ -247,14 +248,6 @@ public final class LinkPropertiesUtilsTest { assertEquals(linkAddr2, results.added.get(0)); } - private void assertSameElements(List expected, List actual) { - HashSet expectedSet = new HashSet(expected); - assertEquals("expected list contains duplicates", expectedSet.size(), expected.size()); - HashSet actualSet = new HashSet(actual); - assertEquals("actual list contains duplicates", actualSet.size(), actual.size()); - assertEquals(expectedSet, actualSet); - } - private void assertCompareOrUpdateResult(CompareOrUpdateResult result, List expectedAdded, List expectedRemoved, List expectedUpdated) { From 794adf5f71f3ff11baf19e4d9fad37eb0a2cfcc8 Mon Sep 17 00:00:00 2001 From: lifr Date: Thu, 4 Mar 2021 14:11:29 +0800 Subject: [PATCH 139/777] [CS11]Remove the hidden API usage of BitUtils The connection service will become the main line module. It is difficult to include BitUtils in the module. and so Move the hidden API needed in BitUtils to NetworkCapabilitiesUtils. Bug: 170598012 Test: atest NetworkStaticLibTests Change-Id: I56286b2991ea9902f9ed78624e2a592138dd4315 --- .../module/util/NetworkCapabilitiesUtils.java | 27 +++++++++++++++++++ .../util/NetworkCapabilitiesUtilsTest.kt | 22 ++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 5a0200ffaf..3de78c61a9 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -78,4 +78,31 @@ public final class NetworkCapabilitiesUtils { } return transports[0]; } + + /** + * Unpacks long value into an array of bits. + */ + public static int[] unpackBits(long val) { + int size = Long.bitCount(val); + int[] result = new int[size]; + int index = 0; + int bitPos = 0; + while (val != 0) { + if ((val & 1) == 1) result[index++] = bitPos; + val = val >>> 1; + bitPos++; + } + return result; + } + + /** + * Packs array of bits into a long value. + */ + public static long packBits(int[] bits) { + long packed = 0; + for (int b : bits) { + packed |= (1L << b); + } + return packed; + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt index e94d132811..df2f45999d 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt @@ -26,11 +26,14 @@ import android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport +import com.android.net.module.util.NetworkCapabilitiesUtils.packBits +import com.android.net.module.util.NetworkCapabilitiesUtils.unpackBits import org.junit.Test import org.junit.runner.RunWith import java.lang.IllegalArgumentException import kotlin.test.assertEquals import kotlin.test.assertFailsWith +import kotlin.test.assertTrue @RunWith(AndroidJUnit4::class) @SmallTest @@ -58,4 +61,21 @@ class NetworkCapabilitiesUtilsTest { getDisplayTransport(intArrayOf()) } } -} \ No newline at end of file + + @Test + fun testBitPackingTestCase() { + runBitPackingTestCase(0, intArrayOf()) + runBitPackingTestCase(1, intArrayOf(0)) + runBitPackingTestCase(3, intArrayOf(0, 1)) + runBitPackingTestCase(4, intArrayOf(2)) + runBitPackingTestCase(63, intArrayOf(0, 1, 2, 3, 4, 5)) + runBitPackingTestCase(Long.MAX_VALUE.inv(), intArrayOf(63)) + runBitPackingTestCase(Long.MAX_VALUE.inv() + 1, intArrayOf(0, 63)) + runBitPackingTestCase(Long.MAX_VALUE.inv() + 2, intArrayOf(1, 63)) + } + + fun runBitPackingTestCase(packedBits: Long, bits: IntArray) { + assertEquals(packedBits, packBits(bits)) + assertTrue(bits contentEquals unpackBits(packedBits)) + } +} From 5fbc8d5dca52b9019843ebaee7aed69b09c3281a Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 24 Feb 2021 07:29:20 +0000 Subject: [PATCH 140/777] Address the comments left in the IPv6 utils change. This follow-up change updates EtherType name in the Ethernet header diagram, replaces "length" filed in the IPv6 header with "payloadLength", and also make ND options constructor as package private to encapsulate the constant params(e.g. ICMPv6 type/code). Bug: 168868607 Test: atest NetworkStackIntegrationTest Change-Id: Ia0500a7020fd9a85dce2a8c67c21b00b238a4e8d --- .../android/net/module/util/structs/EthernetHeader.java | 2 +- .../com/android/net/module/util/structs/Ipv6Header.java | 8 ++++---- .../com/android/net/module/util/structs/LlaOption.java | 8 +++++--- .../com/android/net/module/util/structs/MtuOption.java | 4 ++-- .../com/android/net/module/util/structs/NaHeader.java | 2 +- .../net/module/util/structs/PrefixInformationOption.java | 4 ++-- .../com/android/net/module/util/structs/RdnssOption.java | 5 +++-- 7 files changed, 18 insertions(+), 15 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java b/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java index d895cfaad7..92ef8a7e16 100644 --- a/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java +++ b/staticlibs/device/com/android/net/module/util/structs/EthernetHeader.java @@ -40,7 +40,7 @@ import com.android.net.module.util.Struct.Type; * +- -+ * | Address | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |1 0 0 0 0 1 1 0 1 1 0 1 1 1 0 1| + * | EtherType | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ public class EthernetHeader extends Struct { diff --git a/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java b/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java index 3ad81570e9..a14e064d10 100644 --- a/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java +++ b/staticlibs/device/com/android/net/module/util/structs/Ipv6Header.java @@ -53,7 +53,7 @@ public class Ipv6Header extends Struct { @Field(order = 0, type = Type.S32) public int vtf; @Field(order = 1, type = Type.U16) - public int length; + public int payloadLength; @Field(order = 2, type = Type.S8) public byte nextHeader; @Field(order = 3, type = Type.U8) @@ -63,10 +63,10 @@ public class Ipv6Header extends Struct { @Field(order = 5, type = Type.Ipv6Address) public Inet6Address dstIp; - public Ipv6Header(final int vtf, final int length, final byte nextHeader, final short hopLimit, - final Inet6Address srcIp, final Inet6Address dstIp) { + public Ipv6Header(final int vtf, final int payloadLength, final byte nextHeader, + final short hopLimit, final Inet6Address srcIp, final Inet6Address dstIp) { this.vtf = vtf; - this.length = length; + this.payloadLength = payloadLength; this.nextHeader = nextHeader; this.hopLimit = hopLimit; this.srcIp = srcIp; diff --git a/staticlibs/device/com/android/net/module/util/structs/LlaOption.java b/staticlibs/device/com/android/net/module/util/structs/LlaOption.java index 2cdeefb21c..fbaccabcca 100644 --- a/staticlibs/device/com/android/net/module/util/structs/LlaOption.java +++ b/staticlibs/device/com/android/net/module/util/structs/LlaOption.java @@ -36,14 +36,16 @@ import java.nio.ByteOrder; */ public class LlaOption extends Struct { @Field(order = 0, type = Type.S8) - // 1 for Source Link-layer Address; 2 for Target Link-layer Address. public final byte type; @Field(order = 1, type = Type.S8) public final byte length; // Length in 8-byte units @Field(order = 2, type = Type.EUI48) + // Link layer address length and format varies on different link layers, which is not + // guaranteed to be a 6-byte MAC address. However, Struct only supports 6-byte MAC + // addresses type(EUI-48) for now. public final MacAddress linkLayerAddress; - public LlaOption(final byte type, final byte length, final MacAddress linkLayerAddress) { + LlaOption(final byte type, final byte length, final MacAddress linkLayerAddress) { this.type = type; this.length = length; this.linkLayerAddress = linkLayerAddress; @@ -54,6 +56,6 @@ public class LlaOption extends Struct { */ public static ByteBuffer build(final byte type, final MacAddress linkLayerAddress) { final LlaOption option = new LlaOption(type, (byte) 1 /* option len */, linkLayerAddress); - return ByteBuffer.wrap(option.writeToBytes(ByteOrder.nativeOrder())); + return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN)); } } diff --git a/staticlibs/device/com/android/net/module/util/structs/MtuOption.java b/staticlibs/device/com/android/net/module/util/structs/MtuOption.java index a35b57631a..34bc21c140 100644 --- a/staticlibs/device/com/android/net/module/util/structs/MtuOption.java +++ b/staticlibs/device/com/android/net/module/util/structs/MtuOption.java @@ -46,7 +46,7 @@ public class MtuOption extends Struct { @Field(order = 3, type = Type.U32) public final long mtu; - public MtuOption(final byte type, final byte length, final short reserved, + MtuOption(final byte type, final byte length, final short reserved, final long mtu) { this.type = type; this.length = length; @@ -60,6 +60,6 @@ public class MtuOption extends Struct { public static ByteBuffer build(final long mtu) { final MtuOption option = new MtuOption((byte) ICMPV6_ND_OPTION_MTU, (byte) 1 /* option len */, (short) 0 /* reserved */, mtu); - return ByteBuffer.wrap(option.writeToBytes(ByteOrder.nativeOrder())); + return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN)); } } diff --git a/staticlibs/device/com/android/net/module/util/structs/NaHeader.java b/staticlibs/device/com/android/net/module/util/structs/NaHeader.java index 8101b06156..571d67b31a 100644 --- a/staticlibs/device/com/android/net/module/util/structs/NaHeader.java +++ b/staticlibs/device/com/android/net/module/util/structs/NaHeader.java @@ -23,7 +23,7 @@ import com.android.net.module.util.Struct.Type; import java.net.Inet6Address; /** - * ICMPv6 Neighbor Advertisement header, follow [Icmpv6Header], as per + * ICMPv6 Neighbor Advertisement header, follow {@link Icmpv6Header}, as per * https://tools.ietf.org/html/rfc4861. This does not contain any option. * * 0 1 2 3 diff --git a/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java b/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java index 7dc0192f87..1bdee295d8 100644 --- a/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java +++ b/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java @@ -70,7 +70,7 @@ public class PrefixInformationOption extends Struct { @Field(order = 7, type = Type.ByteArray, arraysize = 16) public final byte[] prefix; - public PrefixInformationOption(final byte type, final byte length, final byte prefixLen, + PrefixInformationOption(final byte type, final byte length, final byte prefixLen, final byte flags, final long validLifetime, final long preferredLifetime, final int reserved, @NonNull final byte[] prefix) { this.type = type; @@ -92,6 +92,6 @@ public class PrefixInformationOption extends Struct { (byte) ICMPV6_ND_OPTION_PIO, (byte) 4 /* option len */, (byte) prefix.getPrefixLength(), flags, validLifetime, preferredLifetime, (int) 0, prefix.getRawAddress()); - return ByteBuffer.wrap(option.writeToBytes(ByteOrder.nativeOrder())); + return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN)); } } diff --git a/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java b/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java index de55e66053..b7c2b0c11a 100644 --- a/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java +++ b/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java @@ -53,8 +53,7 @@ public class RdnssOption extends Struct { @Field(order = 3, type = Type.U32) public final long lifetime; - public RdnssOption(final byte type, final byte length, final short reserved, - final long lifetime) { + RdnssOption(final byte type, final byte length, final short reserved, final long lifetime) { this.type = type; this.length = length; this.reserved = reserved; @@ -79,6 +78,8 @@ public class RdnssOption extends Struct { /** * Build a RDNSS option from the required specified String parameters. + * + * @throws IllegalArgumentException if {@code servers} does not contain only numeric addresses. */ public static ByteBuffer build(final long lifetime, final String... servers) { final Inet6Address[] serverArray = new Inet6Address[servers.length]; From 5b4cfac12503bfc42ce3281b64a23ce5f910d764 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 4 Mar 2021 15:08:16 +0000 Subject: [PATCH 141/777] Add bit mask constants for the flags used in the ND packet. Bug: 168868607 Test: atest NetworkStackIntegrationTest Change-Id: I6e7ed431f175e911eeff71fdf3f1e651533d3364 --- .../net/module/util/NetworkStackConstants.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 5f62186366..499297c9b4 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -148,9 +148,18 @@ public final class NetworkStackConstants { public static final int ICMPV6_ND_OPTION_RDNSS = 25; public static final int ICMPV6_ND_OPTION_PREF64 = 38; - public static final int ICMPV6_RA_HEADER_LEN = 16; + public static final int NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER = 1 << 31; + public static final int NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED = 1 << 30; + public static final int NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE = 1 << 29; + + public static final byte ROUTER_ADVERTISEMENT_FLAG_MANAGED_ADDRESS = (byte) (1 << 7); + public static final byte ROUTER_ADVERTISEMENT_FLAG_OTHER = (byte) (1 << 6); + + public static final byte PIO_FLAG_ON_LINK = (byte) (1 << 7); + public static final byte PIO_FLAG_AUTONOMOUS = (byte) (1 << 6); + /** * UDP constants. * From 0c813cc91e02f4e66663c161ff99b6ecabb232f9 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 9 Mar 2021 20:08:38 +0800 Subject: [PATCH 142/777] [VCN04.1] Add assert tool for Set Test: TH Bug: 175662146 Change-Id: Ib7e2e61a987def59f8e8fc841d07f37ae894573d --- staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt b/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt index 91fb1cd43c..a8c6b3c734 100644 --- a/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt +++ b/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt @@ -32,8 +32,8 @@ fun assertEmpty(ts: Array) = ts.size.let { len -> assertEquals(0, len, "Expected empty array, but length was $len") } -fun assertEmpty(ts: List) = ts.size.let { len -> - assertEquals(0, len, "Expected empty list, but length was $len") +fun assertEmpty(ts: Collection) = ts.size.let { len -> + assertEquals(0, len, "Expected empty collection, but length was $len") } fun assertLength(expected: Int, got: Array) = got.size.let { len -> From f3413f79b85ef73141f6db8672e05e6295e9087d Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 4 Feb 2021 16:57:19 +0900 Subject: [PATCH 143/777] Rename StringNetworkSpecifier to Ethernet To keep the tests passing on Q and R, add a CompatUtil class that will keep creating StringNetworkSpecifiers (now removed) instead. Bug: 179329291 Test: atest CtsNetTestCases Ignore-AOSP-First: Must be merged manually downstream first Change-Id: I14c1ac7cee0ec32353b38ebca4ae6c5cd2e25541 --- .../com/android/testutils/CompatUtil.kt | 53 +++++++++++++++++++ .../android/testutils/TestNetworkTracker.kt | 3 +- 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 staticlibs/devicetests/com/android/testutils/CompatUtil.kt diff --git a/staticlibs/devicetests/com/android/testutils/CompatUtil.kt b/staticlibs/devicetests/com/android/testutils/CompatUtil.kt new file mode 100644 index 0000000000..4bb90a80e5 --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/CompatUtil.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 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 com.android.testutils + +import android.net.NetworkSpecifier +import android.os.Build + +/** + * Test utility to create [NetworkSpecifier]s on different SDK versions. + */ +object CompatUtil { + @JvmStatic + fun makeTestNetworkSpecifier(ifName: String): NetworkSpecifier { + // Until R, there was no TestNetworkSpecifier, StringNetworkSpecifier was used instead + if (isDevSdkInRange(minExclusive = null, maxInclusive = Build.VERSION_CODES.R)) { + makeNetworkSpecifierInternal("android.net.StringNetworkSpecifier", ifName) + } + // TestNetworkSpecifier is not part of the SDK in some branches using this utility + // TODO: replace with a direct call to the constructor + return makeNetworkSpecifierInternal("android.net.TestNetworkSpecifier", ifName) + } + + @JvmStatic + fun makeEthernetNetworkSpecifier(ifName: String): NetworkSpecifier { + // Until R, there was no EthernetNetworkSpecifier, StringNetworkSpecifier was used instead + if (isDevSdkInRange(minExclusive = null, maxInclusive = Build.VERSION_CODES.R)) { + makeNetworkSpecifierInternal("android.net.StringNetworkSpecifier", ifName) + } + // EthernetNetworkSpecifier is not part of the SDK in some branches using this utility + // TODO: replace with a direct call to the constructor + return makeNetworkSpecifierInternal("android.net.EthernetNetworkSpecifier", ifName) + } + + private fun makeNetworkSpecifierInternal(clazz: String, specifier: String): NetworkSpecifier { + // StringNetworkSpecifier was removed after R (and was hidden API before that) + return Class.forName(clazz) + .getConstructor(String::class.java).newInstance(specifier) as NetworkSpecifier + } +} \ No newline at end of file diff --git a/staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt b/staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt index 4bd9ae8eae..5b978617aa 100644 --- a/staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt +++ b/staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt @@ -23,7 +23,6 @@ import android.net.LinkAddress import android.net.Network import android.net.NetworkCapabilities import android.net.NetworkRequest -import android.net.StringNetworkSpecifier import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.os.Binder @@ -68,7 +67,7 @@ class TestNetworkTracker internal constructor( // Test networks do not have NOT_VPN or TRUSTED capabilities by default .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) - .setNetworkSpecifier(StringNetworkSpecifier(iface.interfaceName)) + .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(iface.interfaceName)) .build() networkCallback = object : NetworkCallback() { override fun onAvailable(network: Network) { From 59beee8742c297bd59a43fb8751f925f4e7ff22e Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 4 Mar 2021 17:27:32 +0900 Subject: [PATCH 144/777] Move LocationPermissionChecker to libs/net LocationPermissionChecker was written to be used by multiple connectivity modules, so it belongs in the frameworks/libs/net library. The file is moved as-is with minor modifications in the test to avoid usage of the privileged ActivityManager.getCurrentUser API. Bug: 181837977 Test: atest NetworkStaticLibTests Change-Id: I80cff14c06c3cab3e8f3bd1978c2951c4a3317c6 --- .../util/LocationPermissionChecker.java | 306 +++++++++++++++++ staticlibs/tests/unit/Android.bp | 2 +- .../util/LocationPermissionCheckerTest.java | 307 ++++++++++++++++++ 3 files changed, 614 insertions(+), 1 deletion(-) create mode 100644 staticlibs/framework/com/android/net/module/util/LocationPermissionChecker.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/LocationPermissionCheckerTest.java diff --git a/staticlibs/framework/com/android/net/module/util/LocationPermissionChecker.java b/staticlibs/framework/com/android/net/module/util/LocationPermissionChecker.java new file mode 100644 index 0000000000..e4ce9e8004 --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/LocationPermissionChecker.java @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import android.Manifest; +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.AppOpsManager; +import android.content.Context; +import android.content.pm.PackageManager; +import android.location.LocationManager; +import android.net.NetworkStack; +import android.os.Binder; +import android.os.Build; +import android.os.UserHandle; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + + +/** + * The methods used for location permission and location mode checking. + * + * @hide + */ +public class LocationPermissionChecker { + + private static final String TAG = "LocationPermissionChecker"; + + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"LOCATION_PERMISSION_CHECK_STATUS_"}, value = { + SUCCEEDED, + ERROR_LOCATION_MODE_OFF, + ERROR_LOCATION_PERMISSION_MISSING, + }) + public @interface LocationPermissionCheckStatus{} + + // The location permission check succeeded. + public static final int SUCCEEDED = 0; + // The location mode turns off for the caller. + public static final int ERROR_LOCATION_MODE_OFF = 1; + // The location permission isn't granted for the caller. + public static final int ERROR_LOCATION_PERMISSION_MISSING = 2; + + private final Context mContext; + private final AppOpsManager mAppOpsManager; + + public LocationPermissionChecker(Context context) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + throw new UnsupportedOperationException("This utility is not supported before R"); + } + + mContext = context; + mAppOpsManager = mContext.getSystemService(AppOpsManager.class); + } + + /** + * Check location permission granted by the caller. + * + * This API check if the location mode enabled for the caller and the caller has + * ACCESS_COARSE_LOCATION permission is targetSDK<29, otherwise, has ACCESS_FINE_LOCATION. + * + * @param pkgName package name of the application requesting access + * @param featureId The feature in the package + * @param uid The uid of the package + * @param message A message describing why the permission was checked. Only needed if this is + * not inside of a two-way binder call from the data receiver + * + * @return {@code true} returns if the caller has location permission and the location mode is + * enabled. + */ + public boolean checkLocationPermission(String pkgName, @Nullable String featureId, + int uid, @Nullable String message) { + return checkLocationPermissionInternal(pkgName, featureId, uid, message) == SUCCEEDED; + } + + /** + * Check location permission granted by the caller. + * + * This API check if the location mode enabled for the caller and the caller has + * ACCESS_COARSE_LOCATION permission is targetSDK<29, otherwise, has ACCESS_FINE_LOCATION. + * Compared with {@link #checkLocationPermission(String, String, int, String)}, this API returns + * the detail information about the checking result, including the reason why it's failed and + * logs the error for the caller. + * + * @param pkgName package name of the application requesting access + * @param featureId The feature in the package + * @param uid The uid of the package + * @param message A message describing why the permission was checked. Only needed if this is + * not inside of a two-way binder call from the data receiver + * + * @return {@link LocationPermissionCheckStatus} the result of the location permission check. + */ + public @LocationPermissionCheckStatus int checkLocationPermissionWithDetailInfo( + String pkgName, @Nullable String featureId, int uid, @Nullable String message) { + final int result = checkLocationPermissionInternal(pkgName, featureId, uid, message); + switch (result) { + case ERROR_LOCATION_MODE_OFF: + Log.e(TAG, "Location mode is disabled for the device"); + break; + case ERROR_LOCATION_PERMISSION_MISSING: + Log.e(TAG, "UID " + uid + " has no location permission"); + break; + } + return result; + } + + /** + * Enforce the caller has location permission. + * + * This API determines if the location mode enabled for the caller and the caller has + * ACCESS_COARSE_LOCATION permission is targetSDK<29, otherwise, has ACCESS_FINE_LOCATION. + * SecurityException is thrown if the caller has no permission or the location mode is disabled. + * + * @param pkgName package name of the application requesting access + * @param featureId The feature in the package + * @param uid The uid of the package + * @param message A message describing why the permission was checked. Only needed if this is + * not inside of a two-way binder call from the data receiver + */ + public void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid, + @Nullable String message) throws SecurityException { + final int result = checkLocationPermissionInternal(pkgName, featureId, uid, message); + + switch (result) { + case ERROR_LOCATION_MODE_OFF: + throw new SecurityException("Location mode is disabled for the device"); + case ERROR_LOCATION_PERMISSION_MISSING: + throw new SecurityException("UID " + uid + " has no location permission"); + } + } + + private int checkLocationPermissionInternal(String pkgName, @Nullable String featureId, + int uid, @Nullable String message) { + checkPackage(uid, pkgName); + + // Apps with NETWORK_SETTINGS, NETWORK_SETUP_WIZARD, NETWORK_STACK & MAINLINE_NETWORK_STACK + // are granted a bypass. + if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid) + || checkNetworkStackPermission(uid) || checkMainlineNetworkStackPermission(uid)) { + return SUCCEEDED; + } + + // Location mode must be enabled + if (!isLocationModeEnabled()) { + return ERROR_LOCATION_MODE_OFF; + } + + // LocationAccess by App: caller must have Coarse/Fine Location permission to have access to + // location information. + if (!checkCallersLocationPermission(pkgName, featureId, uid, + true /* coarseForTargetSdkLessThanQ */, message)) { + return ERROR_LOCATION_PERMISSION_MISSING; + } + return SUCCEEDED; + } + + /** + * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION or + * android.Manifest.permission.ACCESS_COARSE_LOCATION (depending on config/targetSDK level) + * and a corresponding app op is allowed for this package and uid. + * + * @param pkgName PackageName of the application requesting access + * @param featureId The feature in the package + * @param uid The uid of the package + * @param coarseForTargetSdkLessThanQ If true and the targetSDK < Q then will check for COARSE + * else (false or targetSDK >= Q) then will check for FINE + * @param message A message describing why the permission was checked. Only needed if this is + * not inside of a two-way binder call from the data receiver + */ + public boolean checkCallersLocationPermission(String pkgName, @Nullable String featureId, + int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message) { + + boolean isTargetSdkLessThanQ = isTargetSdkLessThan(pkgName, Build.VERSION_CODES.Q, uid); + + String permissionType = Manifest.permission.ACCESS_FINE_LOCATION; + if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) { + // Having FINE permission implies having COARSE permission (but not the reverse) + permissionType = Manifest.permission.ACCESS_COARSE_LOCATION; + } + if (getUidPermission(permissionType, uid) == PackageManager.PERMISSION_DENIED) { + return false; + } + + // Always checking FINE - even if will not enforce. This will record the request for FINE + // so that a location request by the app is surfaced to the user. + boolean isFineLocationAllowed = noteAppOpAllowed( + AppOpsManager.OPSTR_FINE_LOCATION, pkgName, featureId, uid, message); + if (isFineLocationAllowed) { + return true; + } + if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) { + return noteAppOpAllowed(AppOpsManager.OPSTR_COARSE_LOCATION, pkgName, featureId, uid, + message); + } + return false; + } + + /** + * Retrieves a handle to LocationManager (if not already done) and check if location is enabled. + */ + public boolean isLocationModeEnabled() { + final LocationManager LocationManager = mContext.getSystemService(LocationManager.class); + try { + return LocationManager.isLocationEnabledForUser(UserHandle.of( + getCurrentUser())); + } catch (Exception e) { + Log.e(TAG, "Failure to get location mode via API, falling back to settings", e); + return false; + } + } + + private boolean isTargetSdkLessThan(String packageName, int versionCode, int callingUid) { + final long ident = Binder.clearCallingIdentity(); + try { + if (mContext.getPackageManager().getApplicationInfoAsUser( + packageName, 0, + UserHandle.getUserHandleForUid(callingUid)).targetSdkVersion + < versionCode) { + return true; + } + } catch (PackageManager.NameNotFoundException e) { + // In case of exception, assume unknown app (more strict checking) + // Note: This case will never happen since checkPackage is + // called to verify validity before checking App's version. + } finally { + Binder.restoreCallingIdentity(ident); + } + return false; + } + + private boolean noteAppOpAllowed(String op, String pkgName, @Nullable String featureId, + int uid, @Nullable String message) { + return mAppOpsManager.noteOp(op, uid, pkgName, featureId, message) + == AppOpsManager.MODE_ALLOWED; + } + + private void checkPackage(int uid, String pkgName) + throws SecurityException { + if (pkgName == null) { + throw new SecurityException("Checking UID " + uid + " but Package Name is Null"); + } + mAppOpsManager.checkPackage(uid, pkgName); + } + + @VisibleForTesting + protected int getCurrentUser() { + return ActivityManager.getCurrentUser(); + } + + private int getUidPermission(String permissionType, int uid) { + // We don't care about pid, pass in -1 + return mContext.checkPermission(permissionType, -1, uid); + } + + /** + * Returns true if the |uid| holds NETWORK_SETTINGS permission. + */ + public boolean checkNetworkSettingsPermission(int uid) { + return getUidPermission(android.Manifest.permission.NETWORK_SETTINGS, uid) + == PackageManager.PERMISSION_GRANTED; + } + + /** + * Returns true if the |uid| holds NETWORK_SETUP_WIZARD permission. + */ + public boolean checkNetworkSetupWizardPermission(int uid) { + return getUidPermission(android.Manifest.permission.NETWORK_SETUP_WIZARD, uid) + == PackageManager.PERMISSION_GRANTED; + } + + /** + * Returns true if the |uid| holds NETWORK_STACK permission. + */ + public boolean checkNetworkStackPermission(int uid) { + return getUidPermission(android.Manifest.permission.NETWORK_STACK, uid) + == PackageManager.PERMISSION_GRANTED; + } + + /** + * Returns true if the |uid| holds MAINLINE_NETWORK_STACK permission. + */ + public boolean checkMainlineNetworkStackPermission(int uid) { + return getUidPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, uid) + == PackageManager.PERMISSION_GRANTED; + } + +} diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index 4ce4b0ea18..45a89b0b11 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -15,7 +15,7 @@ android_library { "androidx.test.rules", "mockito-target-extended-minus-junit4", "net-utils-device-common", - "net-tests-utils-host-device-common", + "net-tests-utils", ], libs: [ "android.test.runner", diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/LocationPermissionCheckerTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/LocationPermissionCheckerTest.java new file mode 100644 index 0000000000..78a21a6c22 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/LocationPermissionCheckerTest.java @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import static android.Manifest.permission.NETWORK_SETTINGS; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.Manifest; +import android.app.AppOpsManager; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.location.LocationManager; +import android.os.Binder; +import android.os.Build; +import android.os.Process; +import android.os.UserHandle; +import android.os.UserManager; + +import com.android.testutils.DevSdkIgnoreRule; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.util.HashMap; + +/** Unit tests for {@link LocationPermissionChecker}. */ +public class LocationPermissionCheckerTest { + @Rule + public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule( + Build.VERSION_CODES.Q /* ignoreClassUpTo */); + + // Mock objects for testing + @Mock private Context mMockContext; + @Mock private PackageManager mMockPkgMgr; + @Mock private ApplicationInfo mMockApplInfo; + @Mock private AppOpsManager mMockAppOps; + @Mock private UserManager mMockUserManager; + @Mock private LocationManager mLocationManager; + + private static final String TEST_PKG_NAME = "com.google.somePackage"; + private static final String TEST_FEATURE_ID = "com.google.someFeature"; + private static final int MANAGED_PROFILE_UID = 1100000; + private static final int OTHER_USER_UID = 1200000; + + private final String mInteractAcrossUsersFullPermission = + "android.permission.INTERACT_ACROSS_USERS_FULL"; + private final String mManifestStringCoarse = + Manifest.permission.ACCESS_COARSE_LOCATION; + private final String mManifestStringFine = + Manifest.permission.ACCESS_FINE_LOCATION; + + // Test variables + private int mWifiScanAllowApps; + private int mUid; + private int mCoarseLocationPermission; + private int mAllowCoarseLocationApps; + private int mFineLocationPermission; + private int mAllowFineLocationApps; + private int mNetworkSettingsPermission; + private int mCurrentUid; + private boolean mIsLocationEnabled; + private boolean mThrowSecurityException; + private Answer mReturnPermission; + private HashMap mPermissionsList = new HashMap(); + private LocationPermissionChecker mChecker; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + initTestVars(); + } + + private void setupMocks() throws Exception { + when(mMockPkgMgr.getApplicationInfoAsUser(eq(TEST_PKG_NAME), eq(0), any())) + .thenReturn(mMockApplInfo); + when(mMockContext.getPackageManager()).thenReturn(mMockPkgMgr); + when(mMockAppOps.noteOp(AppOpsManager.OPSTR_WIFI_SCAN, mUid, TEST_PKG_NAME, + TEST_FEATURE_ID, null)).thenReturn(mWifiScanAllowApps); + when(mMockAppOps.noteOp(eq(AppOpsManager.OPSTR_COARSE_LOCATION), eq(mUid), + eq(TEST_PKG_NAME), eq(TEST_FEATURE_ID), nullable(String.class))) + .thenReturn(mAllowCoarseLocationApps); + when(mMockAppOps.noteOp(eq(AppOpsManager.OPSTR_FINE_LOCATION), eq(mUid), + eq(TEST_PKG_NAME), eq(TEST_FEATURE_ID), nullable(String.class))) + .thenReturn(mAllowFineLocationApps); + if (mThrowSecurityException) { + doThrow(new SecurityException("Package " + TEST_PKG_NAME + " doesn't belong" + + " to application bound to user " + mUid)) + .when(mMockAppOps).checkPackage(mUid, TEST_PKG_NAME); + } + when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)) + .thenReturn(mMockAppOps); + when(mMockContext.getSystemService(Context.USER_SERVICE)) + .thenReturn(mMockUserManager); + when(mMockContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager); + } + + private void setupTestCase() throws Exception { + setupMocks(); + setupMockInterface(); + mChecker = new LocationPermissionChecker(mMockContext) { + @Override + protected int getCurrentUser() { + // Get the user ID of the process running the test rather than the foreground user + // id: ActivityManager.getCurrentUser() requires privileged permissions. + return UserHandle.getUserHandleForUid(Process.myUid()).getIdentifier(); + } + }; + } + + private void initTestVars() { + mPermissionsList.clear(); + mReturnPermission = createPermissionAnswer(); + mWifiScanAllowApps = AppOpsManager.MODE_ERRORED; + mUid = OTHER_USER_UID; + mThrowSecurityException = true; + mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.M; + mIsLocationEnabled = false; + mCurrentUid = Process.myUid(); + mCoarseLocationPermission = PackageManager.PERMISSION_DENIED; + mFineLocationPermission = PackageManager.PERMISSION_DENIED; + mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED; + mAllowFineLocationApps = AppOpsManager.MODE_ERRORED; + mNetworkSettingsPermission = PackageManager.PERMISSION_DENIED; + } + + private void setupMockInterface() { + Binder.restoreCallingIdentity((((long) mUid) << 32) | Binder.getCallingPid()); + doAnswer(mReturnPermission).when(mMockContext).checkPermission( + anyString(), anyInt(), anyInt()); + when(mMockUserManager.isSameProfileGroup(UserHandle.SYSTEM, + UserHandle.getUserHandleForUid(MANAGED_PROFILE_UID))) + .thenReturn(true); + when(mMockContext.checkPermission(mManifestStringCoarse, -1, mUid)) + .thenReturn(mCoarseLocationPermission); + when(mMockContext.checkPermission(mManifestStringFine, -1, mUid)) + .thenReturn(mFineLocationPermission); + when(mMockContext.checkPermission(NETWORK_SETTINGS, -1, mUid)) + .thenReturn(mNetworkSettingsPermission); + when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(mIsLocationEnabled); + } + + private Answer createPermissionAnswer() { + return new Answer() { + @Override + public Integer answer(InvocationOnMock invocation) { + int myUid = (int) invocation.getArguments()[1]; + String myPermission = (String) invocation.getArguments()[0]; + mPermissionsList.get(myPermission); + if (mPermissionsList.containsKey(myPermission)) { + int uid = mPermissionsList.get(myPermission); + if (myUid == uid) { + return PackageManager.PERMISSION_GRANTED; + } + } + return PackageManager.PERMISSION_DENIED; + } + }; + } + + @Test + public void testEnforceLocationPermission_HasAllPermissions_BeforeQ() throws Exception { + mIsLocationEnabled = true; + mThrowSecurityException = false; + mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + mUid = mCurrentUid; + setupTestCase(); + + final int result = + mChecker.checkLocationPermissionWithDetailInfo( + TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null); + assertEquals(LocationPermissionChecker.SUCCEEDED, result); + } + + @Test + public void testEnforceLocationPermission_HasAllPermissions_AfterQ() throws Exception { + mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.Q; + mIsLocationEnabled = true; + mThrowSecurityException = false; + mUid = mCurrentUid; + mFineLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowFineLocationApps = AppOpsManager.MODE_ALLOWED; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + setupTestCase(); + + final int result = + mChecker.checkLocationPermissionWithDetailInfo( + TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null); + assertEquals(LocationPermissionChecker.SUCCEEDED, result); + } + + @Test + public void testEnforceLocationPermission_PkgNameAndUidMismatch() throws Exception { + mThrowSecurityException = true; + mIsLocationEnabled = true; + mFineLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowFineLocationApps = AppOpsManager.MODE_ALLOWED; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + setupTestCase(); + + assertThrows(SecurityException.class, + () -> mChecker.checkLocationPermissionWithDetailInfo( + TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null)); + } + + @Test + public void testenforceCanAccessScanResults_NoCoarseLocationPermission() throws Exception { + mThrowSecurityException = false; + mIsLocationEnabled = true; + setupTestCase(); + + final int result = + mChecker.checkLocationPermissionWithDetailInfo( + TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null); + assertEquals(LocationPermissionChecker.ERROR_LOCATION_PERMISSION_MISSING, result); + } + + @Test + public void testenforceCanAccessScanResults_NoFineLocationPermission() throws Exception { + mThrowSecurityException = false; + mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.Q; + mIsLocationEnabled = true; + mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowFineLocationApps = AppOpsManager.MODE_ERRORED; + mUid = MANAGED_PROFILE_UID; + setupTestCase(); + + final int result = + mChecker.checkLocationPermissionWithDetailInfo( + TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null); + assertEquals(LocationPermissionChecker.ERROR_LOCATION_PERMISSION_MISSING, result); + verify(mMockAppOps, never()).noteOp(anyInt(), anyInt(), anyString()); + } + + @Test + public void testenforceCanAccessScanResults_LocationModeDisabled() throws Exception { + mThrowSecurityException = false; + mUid = MANAGED_PROFILE_UID; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + mPermissionsList.put(mInteractAcrossUsersFullPermission, mUid); + mIsLocationEnabled = false; + + setupTestCase(); + + final int result = + mChecker.checkLocationPermissionWithDetailInfo( + TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null); + assertEquals(LocationPermissionChecker.ERROR_LOCATION_MODE_OFF, result); + } + + @Test + public void testenforceCanAccessScanResults_LocationModeDisabledHasNetworkSettings() + throws Exception { + mThrowSecurityException = false; + mIsLocationEnabled = false; + mNetworkSettingsPermission = PackageManager.PERMISSION_GRANTED; + setupTestCase(); + + final int result = + mChecker.checkLocationPermissionWithDetailInfo( + TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null); + assertEquals(LocationPermissionChecker.SUCCEEDED, result); + } + + + private static void assertThrows(Class exceptionClass, Runnable r) { + try { + r.run(); + Assert.fail("Expected " + exceptionClass + " to be thrown."); + } catch (Exception exception) { + assertTrue(exceptionClass.isInstance(exception)); + } + } +} From d105ecf8f137f7a2411f2e19ad3f6904d025101f Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 12 Mar 2021 01:25:34 +0000 Subject: [PATCH 145/777] Fix CompatUtil on Q and R CompatUtil was missing return statements and falled back to S behavior even on Q and R. Bug: 179329291 Change-Id: I8efb8e56948383c29d476e0b090619bac156d372 Test: atest CtsNetTestCasesLatestSdk --- staticlibs/devicetests/com/android/testutils/CompatUtil.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/devicetests/com/android/testutils/CompatUtil.kt b/staticlibs/devicetests/com/android/testutils/CompatUtil.kt index 4bb90a80e5..ff8c668995 100644 --- a/staticlibs/devicetests/com/android/testutils/CompatUtil.kt +++ b/staticlibs/devicetests/com/android/testutils/CompatUtil.kt @@ -27,7 +27,7 @@ object CompatUtil { fun makeTestNetworkSpecifier(ifName: String): NetworkSpecifier { // Until R, there was no TestNetworkSpecifier, StringNetworkSpecifier was used instead if (isDevSdkInRange(minExclusive = null, maxInclusive = Build.VERSION_CODES.R)) { - makeNetworkSpecifierInternal("android.net.StringNetworkSpecifier", ifName) + return makeNetworkSpecifierInternal("android.net.StringNetworkSpecifier", ifName) } // TestNetworkSpecifier is not part of the SDK in some branches using this utility // TODO: replace with a direct call to the constructor @@ -38,7 +38,7 @@ object CompatUtil { fun makeEthernetNetworkSpecifier(ifName: String): NetworkSpecifier { // Until R, there was no EthernetNetworkSpecifier, StringNetworkSpecifier was used instead if (isDevSdkInRange(minExclusive = null, maxInclusive = Build.VERSION_CODES.R)) { - makeNetworkSpecifierInternal("android.net.StringNetworkSpecifier", ifName) + return makeNetworkSpecifierInternal("android.net.StringNetworkSpecifier", ifName) } // EthernetNetworkSpecifier is not part of the SDK in some branches using this utility // TODO: replace with a direct call to the constructor From e38b5c29dc303a97753c103120cc02bdd032658e Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 15 Mar 2021 23:11:41 +0900 Subject: [PATCH 146/777] Move TrackRecordTest to libs/net The corresponding class was moved to frameworks/libs/net, so the test needs to be in the frameworks/libs/net tests too. Bug: 182785371 Test: atest NetworkStaticLibTests Change-Id: I761544ec0b2513bf0e3115fd0eaecf47efacda62 --- .../net/module/util/TrackRecordTest.kt | 446 ++++++++++++++++++ 1 file changed, 446 insertions(+) create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/TrackRecordTest.kt diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/TrackRecordTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/TrackRecordTest.kt new file mode 100644 index 0000000000..9fb4d8caac --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/TrackRecordTest.kt @@ -0,0 +1,446 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util + +import com.android.testutils.ConcurrentInterpreter +import com.android.testutils.InterpretException +import com.android.testutils.InterpretMatcher +import com.android.testutils.SyntaxException +import com.android.testutils.__FILE__ +import com.android.testutils.__LINE__ +import com.android.testutils.intArg +import com.android.testutils.strArg +import com.android.testutils.timeArg +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import java.util.concurrent.CyclicBarrier +import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicInteger +import kotlin.system.measureTimeMillis +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertNotEquals +import kotlin.test.assertNull +import kotlin.test.assertTrue +import kotlin.test.fail + +val TEST_VALUES = listOf(4, 13, 52, 94, 41, 68, 11, 13, 51, 0, 91, 94, 33, 98, 14) +const val ABSENT_VALUE = 2 +// Caution in changing these : some tests rely on the fact that TEST_TIMEOUT > 2 * SHORT_TIMEOUT +// and LONG_TIMEOUT > 2 * TEST_TIMEOUT +const val SHORT_TIMEOUT = 40L // ms +const val TEST_TIMEOUT = 200L // ms +const val LONG_TIMEOUT = 5000L // ms + +@RunWith(JUnit4::class) +class TrackRecordTest { + @Test + fun testAddAndSizeAndGet() { + val repeats = 22 // arbitrary + val record = ArrayTrackRecord() + assertEquals(0, record.size) + repeat(repeats) { i -> record.add(i + 2) } + assertEquals(repeats, record.size) + record.add(2) + assertEquals(repeats + 1, record.size) + + assertEquals(11, record[9]) + assertEquals(11, record.getOrNull(9)) + assertEquals(2, record[record.size - 1]) + assertEquals(2, record.getOrNull(record.size - 1)) + + assertFailsWith { record[800] } + assertFailsWith { record[-1] } + assertFailsWith { record[repeats + 1] } + assertNull(record.getOrNull(800)) + assertNull(record.getOrNull(-1)) + assertNull(record.getOrNull(repeats + 1)) + assertNull(record.getOrNull(800) { true }) + assertNull(record.getOrNull(-1) { true }) + assertNull(record.getOrNull(repeats + 1) { true }) + } + + @Test + fun testIndexOf() { + val record = ArrayTrackRecord() + TEST_VALUES.forEach { record.add(it) } + with(record) { + assertEquals(9, indexOf(0)) + assertEquals(9, lastIndexOf(0)) + assertEquals(1, indexOf(13)) + assertEquals(7, lastIndexOf(13)) + assertEquals(3, indexOf(94)) + assertEquals(11, lastIndexOf(94)) + assertEquals(-1, indexOf(ABSENT_VALUE)) + assertEquals(-1, lastIndexOf(ABSENT_VALUE)) + } + } + + @Test + fun testContains() { + val record = ArrayTrackRecord() + TEST_VALUES.forEach { record.add(it) } + TEST_VALUES.forEach { assertTrue(record.contains(it)) } + assertFalse(record.contains(ABSENT_VALUE)) + assertTrue(record.containsAll(TEST_VALUES)) + assertTrue(record.containsAll(TEST_VALUES.sorted())) + assertTrue(record.containsAll(TEST_VALUES.sortedDescending())) + assertTrue(record.containsAll(TEST_VALUES.distinct())) + assertTrue(record.containsAll(TEST_VALUES.subList(0, TEST_VALUES.size / 2))) + assertTrue(record.containsAll(TEST_VALUES.subList(0, TEST_VALUES.size / 2).sorted())) + assertTrue(record.containsAll(listOf())) + assertFalse(record.containsAll(listOf(ABSENT_VALUE))) + assertFalse(record.containsAll(TEST_VALUES + listOf(ABSENT_VALUE))) + } + + @Test + fun testEmpty() { + val record = ArrayTrackRecord() + assertTrue(record.isEmpty()) + record.add(1) + assertFalse(record.isEmpty()) + } + + @Test + fun testIterate() { + val record = ArrayTrackRecord() + record.forEach { fail("Expected nothing to iterate") } + TEST_VALUES.forEach { record.add(it) } + // zip relies on the iterator (this calls extension function Iterable#zip(Iterable)) + record.zip(TEST_VALUES).forEach { assertEquals(it.first, it.second) } + // Also test reverse iteration (to test hasPrevious() and friends) + record.reversed().zip(TEST_VALUES.reversed()).forEach { assertEquals(it.first, it.second) } + } + + @Test + fun testIteratorIsSnapshot() { + val record = ArrayTrackRecord() + TEST_VALUES.forEach { record.add(it) } + val iterator = record.iterator() + val expectedSize = record.size + record.add(ABSENT_VALUE) + record.add(ABSENT_VALUE) + var measuredSize = 0 + iterator.forEach { + ++measuredSize + assertNotEquals(ABSENT_VALUE, it) + } + assertEquals(expectedSize, measuredSize) + } + + @Test + fun testSublist() { + val record = ArrayTrackRecord() + TEST_VALUES.forEach { record.add(it) } + assertEquals(record.subList(3, record.size - 3), + TEST_VALUES.subList(3, TEST_VALUES.size - 3)) + } + + fun testPollReturnsImmediately(record: TrackRecord) { + record.add(4) + val elapsed = measureTimeMillis { assertEquals(4, record.poll(LONG_TIMEOUT, 0)) } + // Should not have waited at all, in fact. + assertTrue(elapsed < LONG_TIMEOUT) + record.add(7) + record.add(9) + // Can poll multiple times for the same position, in whatever order + assertEquals(9, record.poll(0, 2)) + assertEquals(7, record.poll(Long.MAX_VALUE, 1)) + assertEquals(9, record.poll(0, 2)) + assertEquals(4, record.poll(0, 0)) + assertEquals(9, record.poll(0, 2) { it > 5 }) + assertEquals(7, record.poll(0, 0) { it > 5 }) + } + + @Test + fun testPollReturnsImmediately() { + testPollReturnsImmediately(ArrayTrackRecord()) + testPollReturnsImmediately(ArrayTrackRecord().newReadHead()) + } + + @Test + fun testPollTimesOut() { + val record = ArrayTrackRecord() + var delay = measureTimeMillis { assertNull(record.poll(SHORT_TIMEOUT, 0)) } + assertTrue(delay >= SHORT_TIMEOUT, "Delay $delay < $SHORT_TIMEOUT") + delay = measureTimeMillis { assertNull(record.poll(SHORT_TIMEOUT, 0) { it < 10 }) } + assertTrue(delay >= SHORT_TIMEOUT) + } + + @Test + fun testConcurrentPollDisallowed() { + val failures = AtomicInteger(0) + val readHead = ArrayTrackRecord().newReadHead() + val barrier = CyclicBarrier(2) + Thread { + barrier.await(LONG_TIMEOUT, TimeUnit.MILLISECONDS) // barrier 1 + try { + readHead.poll(LONG_TIMEOUT) + } catch (e: ConcurrentModificationException) { + failures.incrementAndGet() + // Unblock the other thread + readHead.add(0) + } + }.start() + barrier.await() // barrier 1 + try { + readHead.poll(LONG_TIMEOUT) + } catch (e: ConcurrentModificationException) { + failures.incrementAndGet() + // Unblock the other thread + readHead.add(0) + } + // One of the threads must have gotten an exception. + assertEquals(failures.get(), 1) + } + + @Test + fun testPollWakesUp() { + val record = ArrayTrackRecord() + val barrier = CyclicBarrier(2) + Thread { + barrier.await(LONG_TIMEOUT, TimeUnit.MILLISECONDS) // barrier 1 + barrier.await() // barrier 2 + Thread.sleep(SHORT_TIMEOUT * 2) + record.add(31) + }.start() + barrier.await() // barrier 1 + // Should find the element in more than SHORT_TIMEOUT but less than TEST_TIMEOUT + var delay = measureTimeMillis { + barrier.await() // barrier 2 + assertEquals(31, record.poll(TEST_TIMEOUT, 0)) + } + assertTrue(delay in SHORT_TIMEOUT..TEST_TIMEOUT) + // Polling for an element already added in anothe thread (pos 0) : should return immediately + delay = measureTimeMillis { assertEquals(31, record.poll(TEST_TIMEOUT, 0)) } + assertTrue(delay < TEST_TIMEOUT, "Delay $delay > $TEST_TIMEOUT") + // Waiting for an element that never comes + delay = measureTimeMillis { assertNull(record.poll(SHORT_TIMEOUT, 1)) } + assertTrue(delay >= SHORT_TIMEOUT, "Delay $delay < $SHORT_TIMEOUT") + // Polling for an element that doesn't match what is already there + delay = measureTimeMillis { assertNull(record.poll(SHORT_TIMEOUT, 0) { it < 10 }) } + assertTrue(delay >= SHORT_TIMEOUT) + } + + // Just make sure the interpreter actually throws an exception when the spec + // does not conform to the behavior. The interpreter is just a tool to test a + // tool used for a tool for test, let's not have hundreds of tests for it ; + // if it's broken one of the tests using it will break. + @Test + fun testInterpreter() { + val interpretLine = __LINE__ + 2 + try { + TRTInterpreter.interpretTestSpec(useReadHeads = true, spec = """ + add(4) | poll(1, 0) = 5 + """) + fail("This spec should have thrown") + } catch (e: InterpretException) { + assertTrue(e.cause is AssertionError) + assertEquals(interpretLine + 1, e.stackTrace[0].lineNumber) + assertTrue(e.stackTrace[0].fileName.contains(__FILE__)) + assertTrue(e.stackTrace[0].methodName.contains("testInterpreter")) + assertTrue(e.stackTrace[0].methodName.contains("thread1")) + } + } + + @Test + fun testMultipleAdds() { + TRTInterpreter.interpretTestSpec(useReadHeads = false, spec = """ + add(2) | | | + | add(4) | | + | | add(6) | + | | | add(8) + poll(0, 0) = 2 time 0..1 | poll(0, 0) = 2 | poll(0, 0) = 2 | poll(0, 0) = 2 + poll(0, 1) = 4 time 0..1 | poll(0, 1) = 4 | poll(0, 1) = 4 | poll(0, 1) = 4 + poll(0, 2) = 6 time 0..1 | poll(0, 2) = 6 | poll(0, 2) = 6 | poll(0, 2) = 6 + poll(0, 3) = 8 time 0..1 | poll(0, 3) = 8 | poll(0, 3) = 8 | poll(0, 3) = 8 + """) + } + + @Test + fun testConcurrentAdds() { + TRTInterpreter.interpretTestSpec(useReadHeads = false, spec = """ + add(2) | add(4) | add(6) | add(8) + add(1) | add(3) | add(5) | add(7) + poll(0, 1) is even | poll(0, 0) is even | poll(0, 3) is even | poll(0, 2) is even + poll(0, 5) is odd | poll(0, 4) is odd | poll(0, 7) is odd | poll(0, 6) is odd + """) + } + + @Test + fun testMultiplePoll() { + TRTInterpreter.interpretTestSpec(useReadHeads = false, spec = """ + add(4) | poll(1, 0) = 4 + | poll(0, 1) = null time 0..1 + | poll(1, 1) = null time 1..2 + sleep; add(7) | poll(2, 1) = 7 time 1..2 + sleep; add(18) | poll(2, 2) = 18 time 1..2 + """) + } + + @Test + fun testMultiplePollWithPredicate() { + TRTInterpreter.interpretTestSpec(useReadHeads = false, spec = """ + | poll(1, 0) = null | poll(1, 0) = null + add(6) | poll(1, 0) = 6 | + add(11) | poll(1, 0) { > 20 } = null | poll(1, 0) { = 11 } = 11 + | poll(1, 0) { > 8 } = 11 | + """) + } + + @Test + fun testMultipleReadHeads() { + TRTInterpreter.interpretTestSpec(useReadHeads = true, spec = """ + | poll() = null | poll() = null | poll() = null + add(5) | | poll() = 5 | + | poll() = 5 | | + add(8) | poll() = 8 | poll() = 8 | + | | | poll() = 5 + | | | poll() = 8 + | | | poll() = null + | | poll() = null | + """) + } + + @Test + fun testReadHeadPollWithPredicate() { + TRTInterpreter.interpretTestSpec(useReadHeads = true, spec = """ + add(5) | poll() { < 0 } = null + | poll() { > 5 } = null + add(10) | + | poll() { = 5 } = null // The "5" was skipped in the previous line + add(15) | poll() { > 8 } = 15 // The "10" was skipped in the previous line + | poll(1, 0) { > 8 } = 10 // 10 is the first element after pos 0 matching > 8 + """) + } + + @Test + fun testPollImmediatelyAdvancesReadhead() { + TRTInterpreter.interpretTestSpec(useReadHeads = true, spec = """ + add(1) | add(2) | add(3) | add(4) + mark = 0 | poll(0) { > 3 } = 4 | | + poll(0) { > 10 } = null | | | + mark = 4 | | | + poll() = null | | | + """) + } + + @Test + fun testParallelReadHeads() { + TRTInterpreter.interpretTestSpec(useReadHeads = true, spec = """ + mark = 0 | mark = 0 | mark = 0 | mark = 0 + add(2) | | | + | add(4) | | + | | add(6) | + | | | add(8) + poll() = 2 | poll() = 2 | poll() = 2 | poll() = 2 + poll() = 4 | poll() = 4 | poll() = 4 | poll() = 4 + poll() = 6 | poll() = 6 | poll() = 6 | mark = 2 + poll() = 8 | poll() = 8 | mark = 3 | poll() = 6 + mark = 4 | mark = 4 | poll() = 8 | poll() = 8 + """) + } + + @Test + fun testPeek() { + TRTInterpreter.interpretTestSpec(useReadHeads = true, spec = """ + add(2) | | | + | add(4) | | + | | add(6) | + | | | add(8) + peek() = 2 | poll() = 2 | poll() = 2 | peek() = 2 + peek() = 2 | peek() = 4 | poll() = 4 | peek() = 2 + peek() = 2 | peek() = 4 | peek() = 6 | poll() = 2 + peek() = 2 | mark = 1 | mark = 2 | poll() = 4 + mark = 0 | peek() = 4 | peek() = 6 | peek() = 6 + poll() = 2 | poll() = 4 | poll() = 6 | poll() = 6 + poll() = 4 | mark = 2 | poll() = 8 | peek() = 8 + peek() = 6 | peek() = 6 | peek() = null | mark = 3 + """) + } +} + +private object TRTInterpreter : ConcurrentInterpreter>(interpretTable) { + fun interpretTestSpec(spec: String, useReadHeads: Boolean) = if (useReadHeads) { + interpretTestSpec(spec, initial = ArrayTrackRecord(), + threadTransform = { (it as ArrayTrackRecord).newReadHead() }) + } else { + interpretTestSpec(spec, ArrayTrackRecord()) + } +} + +/* + * Quick ref of supported expressions : + * sleep(x) : sleeps for x time units and returns Unit ; sleep alone means sleep(1) + * add(x) : calls and returns TrackRecord#add. + * poll(time, pos) [{ predicate }] : calls and returns TrackRecord#poll(x time units, pos). + * Optionally, a predicate may be specified. + * poll() [{ predicate }] : calls and returns ReadHead#poll(1 time unit). Optionally, a predicate + * may be specified. + * EXPR = VALUE : asserts that EXPR equals VALUE. EXPR is interpreted. VALUE can either be the + * string "null" or an int. Returns Unit. + * EXPR time x..y : measures the time taken by EXPR and asserts it took at least x and at most + * y time units. + * predicate must be one of "= x", "< x" or "> x". + */ +private val interpretTable = listOf>>( + // Interpret "XXX is odd" : run XXX and assert its return value is odd ("even" works too) + Regex("(.*)\\s+is\\s+(even|odd)") to { i, t, r -> + i.interpret(r.strArg(1), t).also { + assertEquals((it as Int) % 2, if ("even" == r.strArg(2)) 0 else 1) + } + }, + // Interpret "add(XXX)" as TrackRecord#add(int) + Regex("""add\((\d+)\)""") to { i, t, r -> + t.add(r.intArg(1)) + }, + // Interpret "poll(x, y)" as TrackRecord#poll(timeout = x * INTERPRET_TIME_UNIT, pos = y) + // Accepts an optional {} argument for the predicate (see makePredicate for syntax) + Regex("""poll\((\d+),\s*(\d+)\)\s*(\{.*\})?""") to { i, t, r -> + t.poll(r.timeArg(1), r.intArg(2), makePredicate(r.strArg(3))) + }, + // ReadHead#poll. If this throws in the cast, the code is malformed and has passed "poll()" + // in a test that takes a TrackRecord that is not a ReadHead. It's technically possible to get + // the test code to not compile instead of throw, but it's vastly more complex and this will + // fail 100% at runtime any test that would not have compiled. + Regex("""poll\((\d+)?\)\s*(\{.*\})?""") to { i, t, r -> + (if (r.strArg(1).isEmpty()) i.interpretTimeUnit else r.timeArg(1)).let { time -> + (t as ArrayTrackRecord.ReadHead).poll(time, makePredicate(r.strArg(2))) + } + }, + // ReadHead#mark. The same remarks apply as with ReadHead#poll. + Regex("mark") to { i, t, _ -> (t as ArrayTrackRecord.ReadHead).mark }, + // ReadHead#peek. The same remarks apply as with ReadHead#poll. + Regex("peek\\(\\)") to { i, t, _ -> (t as ArrayTrackRecord.ReadHead).peek() } +) + +// Parses a { = x } or { < x } or { > x } string and returns the corresponding predicate +// Returns an always-true predicate for empty and null arguments +private fun makePredicate(spec: String?): (Int) -> Boolean { + if (spec.isNullOrEmpty()) return { true } + val match = Regex("""\{\s*([<>=])\s*(\d+)\s*\}""").matchEntire(spec) + ?: throw SyntaxException("Predicate \"${spec}\"") + val arg = match.intArg(2) + return when (match.strArg(1)) { + ">" -> { i -> i > arg } + "<" -> { i -> i < arg } + "=" -> { i -> i == arg } + else -> throw RuntimeException("How did \"${spec}\" match this regexp ?") + } +} From f4e9b9abcff01ac282f7c4df6d0e448cd452ed69 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 15 Mar 2021 23:19:58 +0900 Subject: [PATCH 147/777] Fix a bug in InetAddressUtils, and add a test. InetAddressUtils's parcelInetAddress and #unparcelInetAddress methods do not correctly parcel scoped IPv6 addresses. Fix this by using the same code that LinkProperties uses, and add a test. Bug: 182785371 Test: atest NetworkStaticLibTests Change-Id: Idc9fcbcf4b2b0746c19831fef68b0ddc206eb161 --- .../net/module/util/InetAddressUtils.java | 17 +++++ .../net/module/util/InetAddressUtilsTest.java | 70 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/InetAddressUtilsTest.java diff --git a/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java b/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java index 6300328e8d..31d0729709 100644 --- a/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java +++ b/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java @@ -18,6 +18,7 @@ package com.android.net.module.util; import android.os.Parcel; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; @@ -27,6 +28,8 @@ import java.net.UnknownHostException; */ public class InetAddressUtils { + private static final int INET6_ADDR_LENGTH = 16; + /** * Writes an InetAddress to a parcel. The address may be null. This is likely faster than * calling writeSerializable. @@ -35,6 +38,13 @@ public class InetAddressUtils { public static void parcelInetAddress(Parcel parcel, InetAddress address, int flags) { byte[] addressArray = (address != null) ? address.getAddress() : null; parcel.writeByteArray(addressArray); + if (address instanceof Inet6Address) { + final Inet6Address v6Address = (Inet6Address) address; + final boolean hasScopeId = v6Address.getScopeId() != 0; + parcel.writeBoolean(hasScopeId); + if (hasScopeId) parcel.writeInt(v6Address.getScopeId()); + } + } /** @@ -47,7 +57,14 @@ public class InetAddressUtils { if (addressArray == null) { return null; } + try { + if (addressArray.length == INET6_ADDR_LENGTH) { + final boolean hasScopeId = in.readBoolean(); + final int scopeId = hasScopeId ? in.readInt() : 0; + return Inet6Address.getByAddress(null /* host */, addressArray, scopeId); + } + return InetAddress.getByAddress(addressArray); } catch (UnknownHostException e) { return null; diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/InetAddressUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/InetAddressUtilsTest.java new file mode 100644 index 0000000000..2736c53ce8 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/InetAddressUtilsTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import static junit.framework.Assert.assertEquals; + +import android.os.Parcel; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet6Address; +import java.net.InetAddress; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class InetAddressUtilsTest { + + private InetAddress parcelUnparcelAddress(InetAddress addr) { + Parcel p = Parcel.obtain(); + InetAddressUtils.parcelInetAddress(p, addr, 0 /* flags */); + p.setDataPosition(0); + byte[] marshalled = p.marshall(); + p.recycle(); + p = Parcel.obtain(); + p.unmarshall(marshalled, 0, marshalled.length); + p.setDataPosition(0); + InetAddress out = InetAddressUtils.unparcelInetAddress(p); + p.recycle(); + return out; + } + + @Test + public void testParcelUnparcelIpv4Address() throws Exception { + InetAddress ipv4 = InetAddress.getByName("192.0.2.1"); + assertEquals(ipv4, parcelUnparcelAddress(ipv4)); + } + + @Test + public void testParcelUnparcelIpv6Address() throws Exception { + InetAddress ipv6 = InetAddress.getByName("2001:db8::1"); + assertEquals(ipv6, parcelUnparcelAddress(ipv6)); + } + + @Test + public void testParcelUnparcelScopedIpv6Address() throws Exception { + InetAddress ipv6 = InetAddress.getByName("fe80::1%42"); + assertEquals(42, ((Inet6Address) ipv6).getScopeId()); + Inet6Address out = (Inet6Address) parcelUnparcelAddress(ipv6); + assertEquals(ipv6, out); + assertEquals(42, out.getScopeId()); + } +} From fd52eafb59887ddb58395d3337cde6d87c0caf7a Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 16 Mar 2021 00:14:48 +0900 Subject: [PATCH 148/777] Add a simple test for Ipv6Utils. This will increase test coverage numbers for Tethering until TetheringPrivilegedTests can be put into coverage runs. Bug: 182785371 Test: atest NetworkStaticLibTests Change-Id: Id93e6190e76bfacfe17082848d40f161b3fcab6a --- .../net/module/util/Ipv6UtilsTest.java | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/Ipv6UtilsTest.java diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/Ipv6UtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/Ipv6UtilsTest.java new file mode 100644 index 0000000000..37278b3d7a --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/Ipv6UtilsTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import static org.junit.Assert.assertEquals; + +import android.net.InetAddresses; +import android.net.IpPrefix; +import android.net.MacAddress; +import android.system.OsConstants; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.net.module.util.structs.EthernetHeader; +import com.android.net.module.util.structs.Icmpv6Header; +import com.android.net.module.util.structs.Ipv6Header; +import com.android.net.module.util.structs.PrefixInformationOption; +import com.android.net.module.util.structs.RaHeader; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet6Address; +import java.nio.ByteBuffer; +import java.util.Arrays; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class Ipv6UtilsTest { + + private static final MacAddress MAC1 = MacAddress.fromString("11:22:33:44:55:66"); + private static final MacAddress MAC2 = MacAddress.fromString("aa:bb:cc:dd:ee:ff"); + private static final Inet6Address LINK_LOCAL = addr("fe80::1"); + private static final Inet6Address ROUTER_LINK_LOCAL = addr("fe80::cafe:d00d"); + private static final Inet6Address ALL_ROUTERS = + NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST; + private static final Inet6Address ALL_NODES = + NetworkStackConstants.IPV6_ADDR_ALL_NODES_MULTICAST; + + @Test + public void testBuildRsPacket() { + ByteBuffer b = Ipv6Utils.buildRsPacket(MAC1, MAC2, LINK_LOCAL, ALL_ROUTERS /* no opts */); + + EthernetHeader eth = Struct.parse(EthernetHeader.class, b); + assertEquals(MAC1, eth.srcMac); + assertEquals(MAC2, eth.dstMac); + + Ipv6Header ipv6 = Struct.parse(Ipv6Header.class, b); + assertEquals(255, ipv6.hopLimit); + assertEquals(OsConstants.IPPROTO_ICMPV6, ipv6.nextHeader); + assertEquals(LINK_LOCAL, ipv6.srcIp); + assertEquals(ALL_ROUTERS, ipv6.dstIp); + + Icmpv6Header icmpv6 = Struct.parse(Icmpv6Header.class, b); + assertEquals(NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION, icmpv6.type); + assertEquals(0, icmpv6.code); + } + + @Test + public void testBuildRaPacket() { + final byte pioFlags = + NetworkStackConstants.PIO_FLAG_AUTONOMOUS | NetworkStackConstants.PIO_FLAG_ON_LINK; + ByteBuffer pio1 = PrefixInformationOption.build(new IpPrefix("2001:db8:1::/64"), + pioFlags, 3600 /* validLifetime */, 1800 /* preferredLifetime */); + ByteBuffer pio2 = PrefixInformationOption.build(new IpPrefix("fdcd:a17f:6502:1::/64"), + pioFlags, 86400 /* validLifetime */, 86400 /* preferredLifetime */); + + ByteBuffer b = Ipv6Utils.buildRaPacket(MAC2, MAC1, ROUTER_LINK_LOCAL, ALL_NODES, + (byte) 0 /* flags */, 7200 /* lifetime */, + 30_000 /* reachableTime */, 750 /* retransTimer */, + pio1, pio2); + + EthernetHeader eth = Struct.parse(EthernetHeader.class, b); + assertEquals(MAC2, eth.srcMac); + assertEquals(MAC1, eth.dstMac); + + Ipv6Header ipv6 = Struct.parse(Ipv6Header.class, b); + assertEquals(255, ipv6.hopLimit); + assertEquals(OsConstants.IPPROTO_ICMPV6, ipv6.nextHeader); + assertEquals(ROUTER_LINK_LOCAL, ipv6.srcIp); + assertEquals(ALL_NODES, ipv6.dstIp); + + Icmpv6Header icmpv6 = Struct.parse(Icmpv6Header.class, b); + assertEquals(NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT, icmpv6.type); + assertEquals(0, icmpv6.code); + + RaHeader ra = Struct.parse(RaHeader.class, b); + assertEquals(0, ra.hopLimit); // Hop limit: unspecified. + assertEquals(0, ra.flags); + assertEquals(7200, ra.lifetime); + assertEquals(30_000, ra.reachableTime); + assertEquals(750, ra.retransTimer); + + PrefixInformationOption pio = Struct.parse(PrefixInformationOption.class, b); + assertPioEquals(pio, "2001:db8:1::/64", pioFlags, 3600, 1800); + pio = Struct.parse(PrefixInformationOption.class, b); + assertPioEquals(pio, "fdcd:a17f:6502:1::/64", pioFlags, 86400, 86400); + } + + private void assertPioEquals(PrefixInformationOption pio, String prefix, byte flags, + long valid, long preferred) { + assertEquals(NetworkStackConstants.ICMPV6_ND_OPTION_PIO, pio.type); + assertEquals(4, pio.length); + assertEquals(flags, pio.flags); + assertEquals(valid, pio.validLifetime); + assertEquals(preferred, pio.preferredLifetime); + IpPrefix expected = new IpPrefix(prefix); + IpPrefix actual = new IpPrefix(pio.prefix, pio.prefixLen); + assertEquals(expected, actual); + } + + private static Inet6Address addr(String addr) { + return (Inet6Address) InetAddresses.parseNumericAddress(addr); + } + + private byte[] slice(byte[] array, int length) { + return Arrays.copyOf(array, length); + } +} From c6e268ece05d4ed8bec6d92c87ab10dc37ea88a5 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 10 Mar 2021 18:15:55 +0800 Subject: [PATCH 149/777] Move some constants from TrafficStatsConstants to NetworkStackConstants Keep the constants are only used by framework in TrafficStatsConstants and move the others to NetworkStackConstants which is in libs/net. Bug: 182349970 Test: FrameworksNetTests NetworkStackTests TetheringTests Ignore-AOSP-First: this topic needs to be cherry-picked manually to AOSP to avoid automerging differences. Change-Id: I7b3a6ba6283a72cc3f2a727001f0f581dce5a7c0 --- .../module/util/NetworkStackConstants.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 499297c9b4..b7062e7656 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -186,6 +186,27 @@ public final class NetworkStackConstants { */ public static final int VENDOR_SPECIFIC_IE_ID = 0xdd; + + /** + * TrafficStats constants. + */ + // These tags are used by the network stack to do traffic for its own purposes. Traffic + // tagged with these will be counted toward the network stack and must stay inside the + // range defined by + // {@link android.net.TrafficStats#TAG_NETWORK_STACK_RANGE_START} and + // {@link android.net.TrafficStats#TAG_NETWORK_STACK_RANGE_END}. + public static final int TAG_SYSTEM_DHCP = 0xFFFFFE01; + public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFE02; + public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFE03; + + // These tags are used by the network stack to do traffic on behalf of apps. Traffic + // tagged with these will be counted toward the app on behalf of which the network + // stack is doing this traffic. These values must stay inside the range defined by + // {@link android.net.TrafficStats#TAG_NETWORK_STACK_IMPERSONATION_RANGE_START} and + // {@link android.net.TrafficStats#TAG_NETWORK_STACK_IMPERSONATION_RANGE_END}. + public static final int TAG_SYSTEM_PROBE = 0xFFFFFF81; + public static final int TAG_SYSTEM_DNS = 0xFFFFFF82; + // TODO: Move to Inet4AddressUtils // See aosp/1455936: NetworkStackConstants can't depend on it as it causes jarjar-related issues // for users of both the net-utils-device-common and net-utils-framework-common libraries. From c36f0b3f468dec16ab5daea243f775ba493d33d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Mon, 15 Mar 2021 20:17:07 -0700 Subject: [PATCH 150/777] add NsHeader class and implement buildNsPacket() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a near trivial copy of NaHeader & buildNaPacket() Test: builds Bug: 154669942 Signed-off-by: Maciej Żenczykowski Change-Id: I3b9b15e23317363bf9556b06ddecf8a2bf967c61 --- .../android/net/module/util/Ipv6Utils.java | 15 +++++ .../net/module/util/structs/NaHeader.java | 4 +- .../net/module/util/structs/NsHeader.java | 57 +++++++++++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 staticlibs/device/com/android/net/module/util/structs/NsHeader.java diff --git a/staticlibs/device/com/android/net/module/util/Ipv6Utils.java b/staticlibs/device/com/android/net/module/util/Ipv6Utils.java index 73c2431d76..ee43ae9965 100644 --- a/staticlibs/device/com/android/net/module/util/Ipv6Utils.java +++ b/staticlibs/device/com/android/net/module/util/Ipv6Utils.java @@ -21,6 +21,7 @@ import static android.system.OsConstants.IPPROTO_ICMPV6; import static com.android.net.module.util.IpUtils.icmpv6Checksum; import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION; @@ -30,6 +31,7 @@ import com.android.net.module.util.structs.EthernetHeader; import com.android.net.module.util.structs.Icmpv6Header; import com.android.net.module.util.structs.Ipv6Header; import com.android.net.module.util.structs.NaHeader; +import com.android.net.module.util.structs.NsHeader; import com.android.net.module.util.structs.RaHeader; import com.android.net.module.util.structs.RsHeader; @@ -122,6 +124,19 @@ public class Ipv6Utils { (byte) ICMPV6_NEIGHBOR_ADVERTISEMENT /* type */, (byte) 0 /* code */, payload); } + /** + * Build an ICMPv6 Neighbor Solicitation packet from the required specified parameters. + */ + public static ByteBuffer buildNsPacket(final MacAddress srcMac, final MacAddress dstMac, + final Inet6Address srcIp, final Inet6Address dstIp, + final Inet6Address target, final ByteBuffer... options) { + final NsHeader nsHeader = new NsHeader(target); + final ByteBuffer[] payload = buildIcmpv6Payload( + ByteBuffer.wrap(nsHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options); + return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, + (byte) ICMPV6_NEIGHBOR_SOLICITATION /* type */, (byte) 0 /* code */, payload); + } + /** * Build an ICMPv6 Router Solicitation packet from the required specified parameters. */ diff --git a/staticlibs/device/com/android/net/module/util/structs/NaHeader.java b/staticlibs/device/com/android/net/module/util/structs/NaHeader.java index 571d67b31a..90c078e8c6 100644 --- a/staticlibs/device/com/android/net/module/util/structs/NaHeader.java +++ b/staticlibs/device/com/android/net/module/util/structs/NaHeader.java @@ -26,8 +26,8 @@ import java.net.Inet6Address; * ICMPv6 Neighbor Advertisement header, follow {@link Icmpv6Header}, as per * https://tools.ietf.org/html/rfc4861. This does not contain any option. * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type | Code | Checksum | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ diff --git a/staticlibs/device/com/android/net/module/util/structs/NsHeader.java b/staticlibs/device/com/android/net/module/util/structs/NsHeader.java new file mode 100644 index 0000000000..6e0aa50868 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/NsHeader.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.Inet6Address; + +/** + * ICMPv6 Neighbor Solicitation header, follow {@link Icmpv6Header}, as per + * https://tools.ietf.org/html/rfc4861. This does not contain any option. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Target Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Options ... + * +-+-+-+-+-+-+-+-+-+-+-+- + */ +public class NsHeader extends Struct { + @Field(order = 0, type = Type.S32) + public int reserved; // 32 Reserved bits. + @Field(order = 1, type = Type.Ipv6Address) + public Inet6Address target; + + public NsHeader(final Inet6Address target) { + this.reserved = 0; + this.target = target; + } +} From aad6bc86145c80dd875b32eb86d4ebcccf04c3a4 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 16 Mar 2021 13:29:31 +0900 Subject: [PATCH 151/777] Fix LocationPermissionCheckerTest The mocking of services was incorrect for services queried by class name instead of service name. Fix getSystemService mocking to cover both methods. Bug: 181837977 Test: atest NetworkStaticLibTests Change-Id: Ifc9bc26e85b5152754941bbe33bccdefff62195a --- .../util/LocationPermissionCheckerTest.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/LocationPermissionCheckerTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/LocationPermissionCheckerTest.java index 78a21a6c22..3fb1e929fe 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/LocationPermissionCheckerTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/LocationPermissionCheckerTest.java @@ -119,11 +119,16 @@ public class LocationPermissionCheckerTest { + " to application bound to user " + mUid)) .when(mMockAppOps).checkPackage(mUid, TEST_PKG_NAME); } - when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)) - .thenReturn(mMockAppOps); - when(mMockContext.getSystemService(Context.USER_SERVICE)) - .thenReturn(mMockUserManager); - when(mMockContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager); + mockSystemService(Context.APP_OPS_SERVICE, AppOpsManager.class, mMockAppOps); + mockSystemService(Context.USER_SERVICE, UserManager.class, mMockUserManager); + mockSystemService(Context.LOCATION_SERVICE, LocationManager.class, mLocationManager); + } + + private void mockSystemService(String name, Class clazz, T service) { + when(mMockContext.getSystemService(name)).thenReturn(service); + when(mMockContext.getSystemServiceName(clazz)).thenReturn(name); + // Do not use mockito extended final method mocking + when(mMockContext.getSystemService(clazz)).thenCallRealMethod(); } private void setupTestCase() throws Exception { From f323faedfe081047b0ec46a48cc5ded1ae0d1767 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 16 Mar 2021 14:12:24 +0900 Subject: [PATCH 152/777] Move trimV4AddrZeros to libs/net The utility is @UnsupportedAppUsage, and also used by internal classes like WifiTrackerLib or Mms, so it needs to be in a shared location. Bug: 182859030 Test: atest NetworkStaticLibTests Change-Id: Ia2be2ef62ea1e7dfdff1f54a14d8f2e282d36fca --- .../net/module/util/Inet4AddressUtils.java | 26 +++++++++++++++++++ .../module/util/Inet4AddressUtilsTest.java | 13 ++++++++++ 2 files changed, 39 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/Inet4AddressUtils.java b/staticlibs/framework/com/android/net/module/util/Inet4AddressUtils.java index a1d34a0f3f..87f43d5182 100644 --- a/staticlibs/framework/com/android/net/module/util/Inet4AddressUtils.java +++ b/staticlibs/framework/com/android/net/module/util/Inet4AddressUtils.java @@ -163,4 +163,30 @@ public class Inet4AddressUtils { throws IllegalArgumentException { return intToInet4AddressHTH(prefixLengthToV4NetmaskIntHTH(prefixLength)); } + + /** + * Trim leading zeros from IPv4 address strings + * Non-v4 addresses and host names remain unchanged. + * For example, 192.168.000.010 -> 192.168.0.10 + * @param addr a string representing an ip address + * @return a string properly trimmed + */ + public static String trimAddressZeros(String addr) { + if (addr == null) return null; + String[] octets = addr.split("\\."); + if (octets.length != 4) return addr; + StringBuilder builder = new StringBuilder(16); + String result = null; + for (int i = 0; i < 4; i++) { + try { + if (octets[i].length() > 3) return addr; + builder.append(Integer.parseInt(octets[i])); + } catch (NumberFormatException e) { + return addr; + } + if (i < 3) builder.append('.'); + } + result = builder.toString(); + return result; + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/Inet4AddressUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/Inet4AddressUtilsTest.java index 5d5ed911f2..702bdaf8df 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/Inet4AddressUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/Inet4AddressUtilsTest.java @@ -26,9 +26,11 @@ import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTL import static com.android.net.module.util.Inet4AddressUtils.netmaskToPrefixLength; import static com.android.net.module.util.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH; import static com.android.net.module.util.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL; +import static com.android.net.module.util.Inet4AddressUtils.trimAddressZeros; import static junit.framework.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import android.net.InetAddresses; @@ -204,6 +206,17 @@ public class Inet4AddressUtilsTest { getPrefixMaskAsInet4Address(-1); } + @Test + public void testTrimAddressZeros() { + assertNull(trimAddressZeros(null)); + assertEquals("$invalid&", trimAddressZeros("$invalid&")); + assertEquals("example.com", trimAddressZeros("example.com")); + assertEquals("a.b.c.d", trimAddressZeros("a.b.c.d")); + + assertEquals("192.0.2.2", trimAddressZeros("192.000.02.2")); + assertEquals("192.0.2.2", trimAddressZeros("192.0.2.2")); + } + private Inet4Address ipv4Address(String addr) { return (Inet4Address) InetAddresses.parseNumericAddress(addr); } From 49390d5cfebb8fe786f471dd9ece7ecfdd954e5e Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 10 Mar 2021 18:15:55 +0800 Subject: [PATCH 153/777] Move some constants from TrafficStatsConstants to NetworkStackConstants Keep the constants are only used by framework in TrafficStatsConstants and move the others to NetworkStackConstants which is in libs/net. Bug: 182349970 Test: FrameworksNetTests NetworkStackTests TetheringTests Change-Id: I7b3a6ba6283a72cc3f2a727001f0f581dce5a7c0 Merged-In: I7b3a6ba6283a72cc3f2a727001f0f581dce5a7c0 --- .../module/util/NetworkStackConstants.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 499297c9b4..b7062e7656 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -186,6 +186,27 @@ public final class NetworkStackConstants { */ public static final int VENDOR_SPECIFIC_IE_ID = 0xdd; + + /** + * TrafficStats constants. + */ + // These tags are used by the network stack to do traffic for its own purposes. Traffic + // tagged with these will be counted toward the network stack and must stay inside the + // range defined by + // {@link android.net.TrafficStats#TAG_NETWORK_STACK_RANGE_START} and + // {@link android.net.TrafficStats#TAG_NETWORK_STACK_RANGE_END}. + public static final int TAG_SYSTEM_DHCP = 0xFFFFFE01; + public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFE02; + public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFE03; + + // These tags are used by the network stack to do traffic on behalf of apps. Traffic + // tagged with these will be counted toward the app on behalf of which the network + // stack is doing this traffic. These values must stay inside the range defined by + // {@link android.net.TrafficStats#TAG_NETWORK_STACK_IMPERSONATION_RANGE_START} and + // {@link android.net.TrafficStats#TAG_NETWORK_STACK_IMPERSONATION_RANGE_END}. + public static final int TAG_SYSTEM_PROBE = 0xFFFFFF81; + public static final int TAG_SYSTEM_DNS = 0xFFFFFF82; + // TODO: Move to Inet4AddressUtils // See aosp/1455936: NetworkStackConstants can't depend on it as it causes jarjar-related issues // for users of both the net-utils-device-common and net-utils-framework-common libraries. From 3454193ea97c1df8012b5cd9c47b875902750bc5 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 19 Mar 2021 23:02:29 +0800 Subject: [PATCH 154/777] Move deduceRestrictedCapability to libs/net and rename it NetworkCapabilities is included in framework-connectivity, so external module cannot have dependencies on its hidden API. Move the method to libs/net and rename it to inferRestrictedCapability so that external module can use it by inculding the library. Ignore-AOSP-First: to avoid merging conflict to internal Bug: 178777253 Test: FrameworksNetTests NetworkStaticLibTests Change-Id: I51244048e31699b562b1444d88511e3a3da845ec --- .../module/util/NetworkCapabilitiesUtils.java | 84 +++++++++++++++++++ .../util/NetworkCapabilitiesUtilsTest.kt | 46 ++++++++++ 2 files changed, 130 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 3de78c61a9..568a356113 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -16,6 +16,23 @@ package com.android.net.module.util; +import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE; +import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA; +import static android.net.NetworkCapabilities.NET_CAPABILITY_IA; +import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_MCX; +import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; +import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE; +import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL; +import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P; +import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP; import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; @@ -24,7 +41,9 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; import android.annotation.NonNull; +import android.net.NetworkCapabilities; +import com.android.internal.annotations.VisibleForTesting; /** * Utilities to examine {@link android.net.NetworkCapabilities}. @@ -54,6 +73,44 @@ public final class NetworkCapabilitiesUtils { // realistic as possible. }; + /** + * Capabilities that suggest that a network is restricted. + * See {@code NetworkCapabilities#maybeMarkCapabilitiesRestricted}, + * and {@code FORCE_RESTRICTED_CAPABILITIES}. + */ + @VisibleForTesting + static final long RESTRICTED_CAPABILITIES = + (1 << NET_CAPABILITY_CBS) + | (1 << NET_CAPABILITY_DUN) + | (1 << NET_CAPABILITY_EIMS) + | (1 << NET_CAPABILITY_FOTA) + | (1 << NET_CAPABILITY_IA) + | (1 << NET_CAPABILITY_IMS) + | (1 << NET_CAPABILITY_MCX) + | (1 << NET_CAPABILITY_RCS) + | (1 << NET_CAPABILITY_VEHICLE_INTERNAL) + | (1 << NET_CAPABILITY_XCAP) + | (1 << NET_CAPABILITY_ENTERPRISE); + + /** + * Capabilities that force network to be restricted. + * See {@code NetworkCapabilities#maybeMarkCapabilitiesRestricted}. + */ + private static final long FORCE_RESTRICTED_CAPABILITIES = + (1 << NET_CAPABILITY_OEM_PAID) + | (1 << NET_CAPABILITY_OEM_PRIVATE); + + /** + * Capabilities that suggest that a network is unrestricted. + * See {@code NetworkCapabilities#maybeMarkCapabilitiesRestricted}. + */ + @VisibleForTesting + static final long UNRESTRICTED_CAPABILITIES = + (1 << NET_CAPABILITY_INTERNET) + | (1 << NET_CAPABILITY_MMS) + | (1 << NET_CAPABILITY_SUPL) + | (1 << NET_CAPABILITY_WIFI_P2P); + /** * Get a transport that can be used to classify a network when displaying its info to users. * @@ -79,6 +136,33 @@ public final class NetworkCapabilitiesUtils { return transports[0]; } + + /** + * Infers that all the capabilities it provides are typically provided by restricted networks + * or not. + * + * @param nc the {@link NetworkCapabilities} to infer the restricted capabilities. + * + * @return {@code true} if the network should be restricted. + */ + public static boolean inferRestrictedCapability(NetworkCapabilities nc) { + final long capabilities = packBits(nc.getCapabilities()); + // Check if we have any capability that forces the network to be restricted. + final boolean forceRestrictedCapability = + (capabilities & FORCE_RESTRICTED_CAPABILITIES) != 0; + + // Verify there aren't any unrestricted capabilities. If there are we say + // the whole thing is unrestricted unless it is forced to be restricted. + final boolean hasUnrestrictedCapabilities = + (capabilities & UNRESTRICTED_CAPABILITIES) != 0; + + // Must have at least some restricted capabilities. + final boolean hasRestrictedCapabilities = (capabilities & RESTRICTED_CAPABILITIES) != 0; + + return forceRestrictedCapability + || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities); + } + /** * Unpacks long value into an array of bits. */ diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt index df2f45999d..5f15c6ac0c 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt @@ -16,6 +16,12 @@ package com.android.net.module.util +import android.net.NetworkCapabilities +import android.net.NetworkCapabilities.NET_CAPABILITY_CBS +import android.net.NetworkCapabilities.NET_CAPABILITY_EIMS +import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET +import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET +import android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH import android.net.NetworkCapabilities.TRANSPORT_CELLULAR import android.net.NetworkCapabilities.TRANSPORT_ETHERNET @@ -25,6 +31,8 @@ import android.net.NetworkCapabilities.TRANSPORT_WIFI import android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 +import com.android.net.module.util.NetworkCapabilitiesUtils.RESTRICTED_CAPABILITIES +import com.android.net.module.util.NetworkCapabilitiesUtils.UNRESTRICTED_CAPABILITIES import com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport import com.android.net.module.util.NetworkCapabilitiesUtils.packBits import com.android.net.module.util.NetworkCapabilitiesUtils.unpackBits @@ -33,6 +41,7 @@ import org.junit.runner.RunWith import java.lang.IllegalArgumentException import kotlin.test.assertEquals import kotlin.test.assertFailsWith +import kotlin.test.assertFalse import kotlin.test.assertTrue @RunWith(AndroidJUnit4::class) @@ -78,4 +87,41 @@ class NetworkCapabilitiesUtilsTest { assertEquals(packedBits, packBits(bits)) assertTrue(bits contentEquals unpackBits(packedBits)) } + + @Test + fun testInferRestrictedCapability() { + val nc = NetworkCapabilities() + // Default capabilities don't have restricted capability. + assertFalse(NetworkCapabilitiesUtils.inferRestrictedCapability(nc)) + // If there is a force restricted capability, then the network capabilities is restricted. + nc.addCapability(NET_CAPABILITY_OEM_PAID) + nc.addCapability(NET_CAPABILITY_INTERNET) + assertTrue(NetworkCapabilitiesUtils.inferRestrictedCapability(nc)) + // Except for the force restricted capability, if there is any unrestricted capability in + // capabilities, then the network capabilities is not restricted. + nc.removeCapability(NET_CAPABILITY_OEM_PAID) + nc.addCapability(NET_CAPABILITY_CBS) + assertFalse(NetworkCapabilitiesUtils.inferRestrictedCapability(nc)) + // Except for the force restricted capability, the network capabilities will only be treated + // as restricted when there is no any unrestricted capability. + nc.removeCapability(NET_CAPABILITY_INTERNET) + assertTrue(NetworkCapabilitiesUtils.inferRestrictedCapability(nc)) + } + + @Test + fun testRestrictedUnrestrictedCapabilities() { + // verify EIMS is restricted + assertEquals((1 shl NET_CAPABILITY_EIMS).toLong() and RESTRICTED_CAPABILITIES, + (1 shl NET_CAPABILITY_EIMS).toLong()) + + // verify CBS is also restricted + assertEquals((1 shl NET_CAPABILITY_CBS).toLong() and RESTRICTED_CAPABILITIES, + (1 shl NET_CAPABILITY_CBS).toLong()) + + // verify default is not restricted + assertEquals((1 shl NET_CAPABILITY_INTERNET).toLong() and RESTRICTED_CAPABILITIES, 0) + + // just to see + assertEquals(RESTRICTED_CAPABILITIES and UNRESTRICTED_CAPABILITIES, 0) + } } From 59d2bf3ad224154b839df15171b3a56ab9a0b6ca Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 12 Jan 2021 20:40:20 +0900 Subject: [PATCH 155/777] Remove unused methods Ignore-AOSP-First: mainline-prod in the critical path Test: FrameworksNetTests NetworkStackTests Bug: 167544279 Change-Id: If1b23e27d8fb2b3b484466245268eb6787e58818 --- .../device/android/net/NetworkFactory.java | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/staticlibs/device/android/net/NetworkFactory.java b/staticlibs/device/android/net/NetworkFactory.java index bcc60897b4..8f2d2fa163 100644 --- a/staticlibs/device/android/net/NetworkFactory.java +++ b/staticlibs/device/android/net/NetworkFactory.java @@ -244,12 +244,6 @@ public class NetworkFactory extends Handler { evalRequests(); } - /** @deprecated None of the implementors use the score, remove this method */ - @Deprecated - public boolean acceptRequest(NetworkRequest request, int score) { - return acceptRequest(request); - } - /** * Overridable function to provide complex filtering. * Called for every request every time a new NetworkRequest is seen @@ -284,7 +278,7 @@ public class NetworkFactory extends Handler { } if (shouldNeedNetworkFor(n)) { if (VDBG) log(" needNetworkFor"); - needNetworkFor(n.request, n.score); + needNetworkFor(n.request); n.requested = true; } else if (shouldReleaseNetworkFor(n)) { if (VDBG) log(" releaseNetworkFor"); @@ -307,7 +301,7 @@ public class NetworkFactory extends Handler { && n.request.canBeSatisfiedBy(mCapabilityFilter) // Finally if the concrete implementation of the factory rejects the request, then // don't track it. - && acceptRequest(n.request, n.score); + && acceptRequest(n.request); } private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) { @@ -321,7 +315,7 @@ public class NetworkFactory extends Handler { // - The concrete implementation of the factory rejects the request && ((n.score > mScore && n.providerId != mProvider.getProviderId()) || !n.request.canBeSatisfiedBy(mCapabilityFilter) - || !acceptRequest(n.request, n.score)); + || !acceptRequest(n.request)); } private void evalRequests() { @@ -363,12 +357,6 @@ public class NetworkFactory extends Handler { protected void startNetwork() { } protected void stopNetwork() { } - /** @deprecated none of the implementors use the score : migrate them */ - @Deprecated - protected void needNetworkFor(NetworkRequest networkRequest, int score) { - needNetworkFor(networkRequest); - } - // override to do fancier stuff protected void needNetworkFor(NetworkRequest networkRequest) { if (++mRefCount == 1) startNetwork(); From 740ab0f6450ed772e02bfe495367d32b27a554d6 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 21 Oct 2020 15:27:04 +0800 Subject: [PATCH 156/777] [SP28.1] Add onSetWarningAndLimit to test utilities Test: atest NetworkStatsServiceTest Bug: 149467454 Bug: 170699770 Bug: 170179169 Ignore-AOSP-First: avoid long automerger delay Change-Id: I4cc242e5fba895bb0756733bafc5be1f39b10ac0 --- .../TestableNetworkStatsProviderBinder.kt | 19 ++++++++++++------- .../TestableNetworkStatsProviderCbBinder.kt | 10 +++++----- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt index 02922d87ea..c19c9f9425 100644 --- a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt +++ b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt @@ -26,8 +26,12 @@ private const val DEFAULT_TIMEOUT_MS = 200L open class TestableNetworkStatsProviderBinder : INetworkStatsProvider.Stub() { sealed class CallbackType { data class OnRequestStatsUpdate(val token: Int) : CallbackType() - data class OnSetLimit(val iface: String?, val quotaBytes: Long) : CallbackType() data class OnSetAlert(val quotaBytes: Long) : CallbackType() + data class OnSetWarningAndLimit( + val iface: String, + val warningBytes: Long, + val limitBytes: Long + ) : CallbackType() } private val history = ArrayTrackRecord().ReadHead() @@ -36,20 +40,21 @@ open class TestableNetworkStatsProviderBinder : INetworkStatsProvider.Stub() { history.add(CallbackType.OnRequestStatsUpdate(token)) } - override fun onSetLimit(iface: String?, quotaBytes: Long) { - history.add(CallbackType.OnSetLimit(iface, quotaBytes)) - } - override fun onSetAlert(quotaBytes: Long) { history.add(CallbackType.OnSetAlert(quotaBytes)) } + override fun onSetWarningAndLimit(iface: String, warningBytes: Long, limitBytes: Long) { + history.add(CallbackType.OnSetWarningAndLimit(iface, warningBytes, limitBytes)) + } + fun expectOnRequestStatsUpdate(token: Int) { assertEquals(CallbackType.OnRequestStatsUpdate(token), history.poll(DEFAULT_TIMEOUT_MS)) } - fun expectOnSetLimit(iface: String?, quotaBytes: Long) { - assertEquals(CallbackType.OnSetLimit(iface, quotaBytes), history.poll(DEFAULT_TIMEOUT_MS)) + fun expectOnSetWarningAndLimit(iface: String, warningBytes: Long, limitBytes: Long) { + assertEquals(CallbackType.OnSetWarningAndLimit(iface, warningBytes, limitBytes), + history.poll(DEFAULT_TIMEOUT_MS)) } fun expectOnSetAlert(quotaBytes: Long) { diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt index 163473a362..f15fd3b517 100644 --- a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt +++ b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt @@ -32,7 +32,7 @@ open class TestableNetworkStatsProviderCbBinder : INetworkStatsProviderCallback. val ifaceStats: NetworkStats, val uidStats: NetworkStats ) : CallbackType() - object NotifyLimitReached : CallbackType() + object NotifyWarningOrLimitReached : CallbackType() object NotifyAlertReached : CallbackType() object Unregister : CallbackType() } @@ -43,8 +43,8 @@ open class TestableNetworkStatsProviderCbBinder : INetworkStatsProviderCallback. history.add(CallbackType.NotifyStatsUpdated(token, ifaceStats, uidStats)) } - override fun notifyLimitReached() { - history.add(CallbackType.NotifyLimitReached) + override fun notifyWarningOrLimitReached() { + history.add(CallbackType.NotifyWarningOrLimitReached) } override fun notifyAlertReached() { @@ -70,8 +70,8 @@ open class TestableNetworkStatsProviderCbBinder : INetworkStatsProviderCallback. assertNetworkStatsEquals(uidStats, event.uidStats) } - fun expectNotifyLimitReached() = - assertEquals(CallbackType.NotifyLimitReached, history.poll(DEFAULT_TIMEOUT_MS)) + fun expectNotifyWarningOrLimitReached() = + assertEquals(CallbackType.NotifyWarningOrLimitReached, history.poll(DEFAULT_TIMEOUT_MS)) fun expectNotifyAlertReached() = assertEquals(CallbackType.NotifyAlertReached, history.poll(DEFAULT_TIMEOUT_MS)) From 89cff640de24905c3b762bf97e3f63c0d4f28d28 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 24 Mar 2021 22:40:37 +0900 Subject: [PATCH 157/777] Add visibility to net-utils-framework-srcs Allow framework-connectivity to depend on net-utils-framework-srcs, and add @hide annotations to classes that were missing it. This allows depending on less classes than net-utils-device-common, and avoids transitive dependency on androidx.annotations used by net-utils-device-common (which itself depends on the public SDK). Bug: 183600168 Test: m Ignore-AOSP-First: needs manual cherry-picks Change-Id: I89a18bb46311800fd6807dad5785f12648f165d9 --- staticlibs/Android.bp | 5 ++++- .../com/android/net/module/util/CollectionUtils.java | 1 + .../com/android/net/module/util/ConnectivityUtils.java | 1 + .../android/net/module/util/NetworkCapabilitiesUtils.java | 1 + .../com/android/net/module/util/NetworkIdentityUtils.java | 1 + 5 files changed, 8 insertions(+), 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 03296e7304..a341b0fb9e 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -121,7 +121,10 @@ filegroup { name: "net-utils-framework-common-srcs", srcs: ["framework/**/*.java"], path: "framework", - visibility: ["//frameworks/base"], + visibility: [ + "//frameworks/base", + "//frameworks/base/packages/Connectivity/framework", + ], } java_library { diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index 2223443d9a..44d0a6e900 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -26,6 +26,7 @@ import java.util.function.Predicate; /** * Utilities for {@link Collection} and arrays. + * @hide */ public final class CollectionUtils { private CollectionUtils() {} diff --git a/staticlibs/framework/com/android/net/module/util/ConnectivityUtils.java b/staticlibs/framework/com/android/net/module/util/ConnectivityUtils.java index 382912bf8d..c135e46643 100644 --- a/staticlibs/framework/com/android/net/module/util/ConnectivityUtils.java +++ b/staticlibs/framework/com/android/net/module/util/ConnectivityUtils.java @@ -24,6 +24,7 @@ import java.net.InetAddress; /** * Various utilities used in connectivity code. + * @hide */ public final class ConnectivityUtils { private ConnectivityUtils() {} diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 568a356113..47b0fc86e8 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -47,6 +47,7 @@ import com.android.internal.annotations.VisibleForTesting; /** * Utilities to examine {@link android.net.NetworkCapabilities}. + * @hide */ public final class NetworkCapabilitiesUtils { // Transports considered to classify networks in UI, in order of which transport should be diff --git a/staticlibs/framework/com/android/net/module/util/NetworkIdentityUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkIdentityUtils.java index 94e60178fc..b641753c03 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkIdentityUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkIdentityUtils.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; /** * Utilities to examine {@link android.net.NetworkIdentity}. + * @hide */ public class NetworkIdentityUtils { /** From 444155895422c46c710326755875829afddd3972 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 25 Mar 2021 01:35:48 +0900 Subject: [PATCH 158/777] Make TestableNetworkCallback understand blocked reasons. This provides some support for tests that want to test the new onBlockedStatusChanged(Network, int) callback. This cannot be implemented entirely in TestableNetworkCallback, because in Kotlin, "override" is a mandatory keyword, but NetworkCallback (which TestableNetworkCallback inherits from) only has the new method in S, not R. The unit tests in the other CL in this topic provide an idea of how to do this. There may be more elegant ways to do it though. Bug: 165835257 Test: new ConnectivityServiceTest tests in this topic Change-Id: Ibdf36a6bc916bf247688c19bfd81f6b62d59bf03 --- .../testutils/TestableNetworkCallback.kt | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt index 043654f4bd..1b3d0f69e1 100644 --- a/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -25,6 +25,7 @@ import android.util.Log import com.android.net.module.util.ArrayTrackRecord import com.android.testutils.RecorderCallback.CallbackEntry.Available import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatus +import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatusInt import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged import com.android.testutils.RecorderCallback.CallbackEntry.Losing @@ -82,7 +83,10 @@ open class RecorderCallback private constructor( override val network: Network, val blocked: Boolean ) : CallbackEntry() - + data class BlockedStatusInt( + override val network: Network, + val blocked: Int + ) : CallbackEntry() // Convenience constants for expecting a type companion object { @JvmField @@ -103,6 +107,8 @@ open class RecorderCallback private constructor( val UNAVAILABLE = Unavailable::class @JvmField val BLOCKED_STATUS = BlockedStatus::class + @JvmField + val BLOCKED_STATUS_INT = BlockedStatusInt::class } } @@ -131,6 +137,9 @@ open class RecorderCallback private constructor( history.add(BlockedStatus(network, blocked)) } + // Cannot do: + // fun onBlockedStatusChanged(network: Network, blocked: Int) { + // because on S, that needs to be "override fun", and on R, that cannot be "override fun". override fun onNetworkSuspended(network: Network) { Log.d(TAG, "onNetworkSuspended $network $network") history.add(Suspended(network)) @@ -271,6 +280,27 @@ open class TestableNetworkCallback private constructor( validated: Boolean = true, blocked: Boolean = false, tmt: Long = defaultTimeoutMs + ) { + expectAvailableCallbacksCommon(net, suspended, validated, tmt) + expectBlockedStatusCallback(blocked, net, tmt) + } + + fun expectAvailableCallbacks( + net: Network, + suspended: Boolean, + validated: Boolean, + blockedStatus: Int, + tmt: Long + ) { + expectAvailableCallbacksCommon(net, suspended, validated, tmt) + expectBlockedStatusCallback(blockedStatus, net) + } + + private fun expectAvailableCallbacksCommon( + net: Network, + suspended: Boolean, + validated: Boolean, + tmt: Long ) { expectCallback(net, tmt) if (suspended) { @@ -278,7 +308,6 @@ open class TestableNetworkCallback private constructor( } expectCapabilitiesThat(net, tmt) { validated == it.hasCapability(NET_CAPABILITY_VALIDATED) } expectCallback(net, tmt) - expectBlockedStatusCallback(blocked, net) } // Backward compatibility for existing Java code. Use named arguments instead and remove all @@ -295,6 +324,12 @@ open class TestableNetworkCallback private constructor( } } + fun expectBlockedStatusCallback(blocked: Int, net: Network, tmt: Long = defaultTimeoutMs) { + expectCallback(net, tmt).also { + assertEquals(it.blocked, blocked, "Unexpected blocked status ${it.blocked}") + } + } + // Expects the available callbacks (where the onCapabilitiesChanged must contain the // VALIDATED capability), plus another onCapabilitiesChanged which is identical to the // one we just sent. @@ -314,6 +349,16 @@ open class TestableNetworkCallback private constructor( expectCapabilitiesThat(net, tmt) { it.hasCapability(NET_CAPABILITY_VALIDATED) } } + fun expectAvailableThenValidatedCallbacks( + net: Network, + blockedStatus: Int, + tmt: Long = defaultTimeoutMs + ) { + expectAvailableCallbacks(net, validated = false, suspended = false, + blockedStatus = blockedStatus, tmt = tmt) + expectCapabilitiesThat(net, tmt) { it.hasCapability(NET_CAPABILITY_VALIDATED) } + } + // Temporary Java compat measure : have MockNetworkAgent implement this so that all existing // calls with networkAgent can be routed through here without moving MockNetworkAgent. // TODO: clean this up, remove this method. From c8925dd6728e5e21b484361f3f455f61813da090 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 25 Mar 2021 12:07:27 +0800 Subject: [PATCH 159/777] Update new capabilities into restricted capabilities NET_CAPABILITY_VSIM and NET_CAPABILITY_BIP are new restricted capabiltity for carrier usage. Update them the RESTRICTED_CAPABILITIES. Bug: 130869457 Test: m Change-Id: I20e3cf34634cf0c106560fc4173fcfb91d85724e Ignore-AOSP-First: code conflict --- .../net/module/util/NetworkCapabilitiesUtils.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 568a356113..9e4a161ba5 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -16,6 +16,7 @@ package com.android.net.module.util; +import static android.net.NetworkCapabilities.NET_CAPABILITY_BIP; import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS; @@ -31,6 +32,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE; import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS; import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL; import static android.net.NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VSIM; import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P; import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP; import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; @@ -80,17 +82,19 @@ public final class NetworkCapabilitiesUtils { */ @VisibleForTesting static final long RESTRICTED_CAPABILITIES = - (1 << NET_CAPABILITY_CBS) + (1 << NET_CAPABILITY_BIP) + | (1 << NET_CAPABILITY_CBS) | (1 << NET_CAPABILITY_DUN) | (1 << NET_CAPABILITY_EIMS) + | (1 << NET_CAPABILITY_ENTERPRISE) | (1 << NET_CAPABILITY_FOTA) | (1 << NET_CAPABILITY_IA) | (1 << NET_CAPABILITY_IMS) | (1 << NET_CAPABILITY_MCX) | (1 << NET_CAPABILITY_RCS) | (1 << NET_CAPABILITY_VEHICLE_INTERNAL) - | (1 << NET_CAPABILITY_XCAP) - | (1 << NET_CAPABILITY_ENTERPRISE); + | (1 << NET_CAPABILITY_VSIM) + | (1 << NET_CAPABILITY_XCAP); /** * Capabilities that force network to be restricted. From d1fc0809d8ffbdef0799bfddec416d9bca4f8354 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 12 Jan 2021 15:23:38 +0900 Subject: [PATCH 160/777] [NS05] Implement NetworkScore in NetworkFactory Test: FrameworksNetTests FrameworksWifiTests NetworkStackTests Change-Id: I6ec7b49bef74b030687c16bce14c2522431018ab --- .../device/android/net/NetworkFactory.java | 253 +++++++++--------- 1 file changed, 133 insertions(+), 120 deletions(-) diff --git a/staticlibs/device/android/net/NetworkFactory.java b/staticlibs/device/android/net/NetworkFactory.java index 8f2d2fa163..68db57b509 100644 --- a/staticlibs/device/android/net/NetworkFactory.java +++ b/staticlibs/device/android/net/NetworkFactory.java @@ -17,7 +17,9 @@ package android.net; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; +import android.net.NetworkProvider.NetworkOfferCallback; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -29,6 +31,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.LinkedHashMap; import java.util.Map; +import java.util.concurrent.Executor; /** * A NetworkFactory is an entity that creates NetworkAgent objects. @@ -48,6 +51,14 @@ import java.util.Map; public class NetworkFactory extends Handler { private static final boolean DBG = true; private static final boolean VDBG = false; + + // A score that will win against everything, so that score filtering will let all requests + // through + // TODO : remove this and replace with an API to listen to all requests. + @NonNull + private static final NetworkScore INVINCIBLE_SCORE = + new NetworkScore.Builder().setLegacyInt(1000).build(); + /** * Pass a network request to the bearer. If the bearer believes it can * satisfy the request it should connect to the network and create a @@ -59,19 +70,9 @@ public class NetworkFactory extends Handler { * disregard any that it will never be able to service, for example * those requiring a different bearer. * msg.obj = NetworkRequest - * msg.arg1 = score - the score of the network currently satisfying this - * request. If this bearer knows in advance it cannot - * exceed this score it should not try to connect, holding the request - * for the future. - * Note that subsequent events may give a different (lower - * or higher) score for this request, transmitted to each - * NetworkFactory through additional CMD_REQUEST_NETWORK msgs - * with the same NetworkRequest but an updated score. - * Also, network conditions may change for this bearer - * allowing for a better score in the future. - * msg.arg2 = the ID of the NetworkProvider currently responsible for the - * NetworkAgent handling this request, or NetworkProvider.ID_NONE if none. */ + // TODO : this and CANCEL_REQUEST are only used by telephony tests. Replace it in the tests + // and remove them and the associated code. public static final int CMD_REQUEST_NETWORK = 1; /** @@ -82,7 +83,7 @@ public class NetworkFactory extends Handler { /** * Internally used to set our best-guess score. - * msg.arg1 = new score + * msg.obj = new score */ private static final int CMD_SET_SCORE = 3; @@ -93,28 +94,72 @@ public class NetworkFactory extends Handler { */ private static final int CMD_SET_FILTER = 4; + /** + * Internally used to send the network offer associated with this factory. + * No arguments, will read from members + */ + private static final int CMD_OFFER_NETWORK = 5; + + /** + * Internally used to send the request to listen to all requests. + * No arguments, will read from members + */ + private static final int CMD_LISTEN_TO_ALL_REQUESTS = 6; + private final Context mContext; private final String LOG_TAG; private final Map mNetworkRequests = new LinkedHashMap<>(); - private int mScore; - private NetworkCapabilities mCapabilityFilter; + @NonNull private NetworkScore mScore = new NetworkScore.Builder().setLegacyInt(0).build(); + @NonNull private NetworkCapabilities mCapabilityFilter; private int mRefCount = 0; private NetworkProvider mProvider = null; + private final NetworkOfferCallback mRequestCallback = new NetworkOfferCallback() { + @Override + public void onNetworkNeeded(@NonNull final NetworkRequest request) { + handleAddRequest(request); + } + + @Override + public void onNetworkUnneeded(@NonNull final NetworkRequest request) { + handleRemoveRequest(request); + } + }; + @NonNull private final Executor mExecutor = command -> post(command); + + // Ideally the filter argument would be non-null, but null has historically meant to see + // no requests and telephony passes null. public NetworkFactory(Looper looper, Context context, String logTag, - NetworkCapabilities filter) { + @Nullable final NetworkCapabilities filter) { super(looper); LOG_TAG = logTag; mContext = context; - mCapabilityFilter = filter; + if (null != filter) { + mCapabilityFilter = filter; + } else { + mCapabilityFilter = new NetworkCapabilities.Builder().clearAll().build(); + } } /* Registers this NetworkFactory with the system. May only be called once per factory. */ public void register() { + register(false); + } + + /** + * Registers this NetworkFactory with the system ignoring the score filter. This will let + * the factory always see all network requests matching its capabilities filter. + * May only be called once per factory. + */ + public void registerIgnoringScore() { + register(true); + } + + private void register(final boolean listenToAllRequests) { if (mProvider != null) { throw new IllegalStateException("A NetworkFactory must only be registered once"); } @@ -124,7 +169,7 @@ public class NetworkFactory extends Handler { @Override public void onNetworkRequested(@NonNull NetworkRequest request, int score, int servingProviderId) { - handleAddRequest(request, score, servingProviderId); + handleAddRequest(request); } @Override @@ -134,7 +179,19 @@ public class NetworkFactory extends Handler { }; ((ConnectivityManager) mContext.getSystemService( - Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); + Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); + + // The mScore and mCapabilityFilter members can only be accessed on the handler thread. + // TODO : offer a separate API to listen to all requests instead + if (listenToAllRequests) { + sendMessage(obtainMessage(CMD_LISTEN_TO_ALL_REQUESTS)); + } else { + sendMessage(obtainMessage(CMD_OFFER_NETWORK)); + } + } + + private void handleOfferNetwork(@NonNull final NetworkScore score) { + mProvider.registerNetworkOffer(score, mCapabilityFilter, mExecutor, mRequestCallback); } /** Unregisters this NetworkFactory. After this call, the object can no longer be used. */ @@ -156,7 +213,7 @@ public class NetworkFactory extends Handler { public void handleMessage(Message msg) { switch (msg.what) { case CMD_REQUEST_NETWORK: { - handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2); + handleAddRequest((NetworkRequest) msg.obj); break; } case CMD_CANCEL_REQUEST: { @@ -164,32 +221,36 @@ public class NetworkFactory extends Handler { break; } case CMD_SET_SCORE: { - handleSetScore(msg.arg1); + handleSetScore((NetworkScore) msg.obj); break; } case CMD_SET_FILTER: { handleSetFilter((NetworkCapabilities) msg.obj); break; } + case CMD_OFFER_NETWORK: { + handleOfferNetwork(mScore); + break; + } + case CMD_LISTEN_TO_ALL_REQUESTS: { + handleOfferNetwork(INVINCIBLE_SCORE); + break; + } } } private static class NetworkRequestInfo { - public final NetworkRequest request; - public int score; + @NonNull public final NetworkRequest request; public boolean requested; // do we have a request outstanding, limited by score - public int providerId; - NetworkRequestInfo(NetworkRequest request, int score, int providerId) { + NetworkRequestInfo(@NonNull final NetworkRequest request) { this.request = request; - this.score = score; this.requested = false; - this.providerId = providerId; } @Override public String toString() { - return "{" + request + ", score=" + score + ", requested=" + requested + "}"; + return "{" + request + ", requested=" + requested + "}"; } } @@ -198,35 +259,27 @@ public class NetworkFactory extends Handler { * @see #CMD_REQUEST_NETWORK * * @param request the request to handle. - * @param score the score of the NetworkAgent currently satisfying this request. - * @param servingProviderId the ID of the NetworkProvider that created the NetworkAgent - * currently satisfying this request. */ - @VisibleForTesting - protected void handleAddRequest(NetworkRequest request, int score, int servingProviderId) { + private void handleAddRequest(@NonNull final NetworkRequest request) { NetworkRequestInfo n = mNetworkRequests.get(request); if (n == null) { - if (DBG) { - log("got request " + request + " with score " + score - + " and providerId " + servingProviderId); - } - n = new NetworkRequestInfo(request, score, servingProviderId); + if (DBG) log("got request " + request); + n = new NetworkRequestInfo(request); mNetworkRequests.put(n.request, n); } else { if (VDBG) { - log("new score " + score + " for existing request " + request - + " and providerId " + servingProviderId); + log("handle existing request " + request); } - n.score = score; - n.providerId = servingProviderId; } if (VDBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); - evalRequest(n); + if (acceptRequest(request)) { + n.requested = true; + needNetworkFor(request); + } } - @VisibleForTesting - protected void handleRemoveRequest(NetworkRequest request) { + private void handleRemoveRequest(NetworkRequest request) { NetworkRequestInfo n = mNetworkRequests.get(request); if (n != null) { mNetworkRequests.remove(request); @@ -234,14 +287,21 @@ public class NetworkFactory extends Handler { } } - private void handleSetScore(int score) { + private void handleSetScore(@NonNull final NetworkScore score) { + if (mScore.equals(score)) return; mScore = score; - evalRequests(); + reevaluateAllRequests(); } - private void handleSetFilter(NetworkCapabilities netCap) { + private void handleSetFilter(@NonNull final NetworkCapabilities netCap) { + if (netCap.equals(mCapabilityFilter)) return; mCapabilityFilter = netCap; - evalRequests(); + reevaluateAllRequests(); + } + + protected final void reevaluateAllRequests() { + if (mProvider == null) return; + mProvider.registerNetworkOffer(mScore, mCapabilityFilter, mExecutor, mRequestCallback); } /** @@ -263,75 +323,9 @@ public class NetworkFactory extends Handler { * * @return {@code true} to accept the request. */ - public boolean acceptRequest(NetworkRequest request) { + public boolean acceptRequest(@NonNull final NetworkRequest request) { return true; } - - private void evalRequest(NetworkRequestInfo n) { - if (VDBG) { - log("evalRequest"); - log(" n.requests = " + n.requested); - log(" n.score = " + n.score); - log(" mScore = " + mScore); - log(" request.providerId = " + n.providerId); - log(" mProvider.id = " + mProvider.getProviderId()); - } - if (shouldNeedNetworkFor(n)) { - if (VDBG) log(" needNetworkFor"); - needNetworkFor(n.request); - n.requested = true; - } else if (shouldReleaseNetworkFor(n)) { - if (VDBG) log(" releaseNetworkFor"); - releaseNetworkFor(n.request); - n.requested = false; - } else { - if (VDBG) log(" done"); - } - } - - private boolean shouldNeedNetworkFor(NetworkRequestInfo n) { - // If this request is already tracked, it doesn't qualify for need - return !n.requested - // If the score of this request is higher or equal to that of this factory and some - // other factory is responsible for it, then this factory should not track the request - // because it has no hope of satisfying it. - && (n.score < mScore || n.providerId == mProvider.getProviderId()) - // If this factory can't satisfy the capability needs of this request, then it - // should not be tracked. - && n.request.canBeSatisfiedBy(mCapabilityFilter) - // Finally if the concrete implementation of the factory rejects the request, then - // don't track it. - && acceptRequest(n.request); - } - - private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) { - // Don't release a request that's not tracked. - return n.requested - // The request should be released if it can't be satisfied by this factory. That - // means either of the following conditions are met : - // - Its score is too high to be satisfied by this factory and it's not already - // assigned to the factory - // - This factory can't satisfy the capability needs of the request - // - The concrete implementation of the factory rejects the request - && ((n.score > mScore && n.providerId != mProvider.getProviderId()) - || !n.request.canBeSatisfiedBy(mCapabilityFilter) - || !acceptRequest(n.request)); - } - - private void evalRequests() { - for (NetworkRequestInfo n : mNetworkRequests.values()) { - evalRequest(n); - } - } - - /** - * Post a command, on this NetworkFactory Handler, to re-evaluate all - * outstanding requests. Can be called from a factory implementation. - */ - protected void reevaluateAllRequests() { - post(this::evalRequests); - } - /** * Can be called by a factory to release a request as unfulfillable: the request will be * removed, and the caller will get a @@ -358,16 +352,35 @@ public class NetworkFactory extends Handler { protected void stopNetwork() { } // override to do fancier stuff - protected void needNetworkFor(NetworkRequest networkRequest) { + protected void needNetworkFor(@NonNull final NetworkRequest networkRequest) { if (++mRefCount == 1) startNetwork(); } - protected void releaseNetworkFor(NetworkRequest networkRequest) { + protected void releaseNetworkFor(@NonNull final NetworkRequest networkRequest) { if (--mRefCount == 0) stopNetwork(); } - public void setScoreFilter(int score) { - sendMessage(obtainMessage(CMD_SET_SCORE, score, 0)); + /** + * @deprecated this method was never part of the API (system or public) and is only added + * for migration of existing clients. It will be removed before S ships. + */ + @Deprecated + public void setScoreFilter(final int score) { + setScoreFilter(new NetworkScore.Builder().setLegacyInt(score).build()); + } + + /** + * Set a score filter for this factory. + * + * This should include the transports the factory knows its networks will have, and + * an optimistic view of the attributes it may have. This does not commit the factory + * to being able to bring up such a network ; it only lets it avoid hearing about + * requests that it has no chance of fulfilling. + * + * @param score the filter + */ + public void setScoreFilter(@NonNull final NetworkScore score) { + sendMessage(obtainMessage(CMD_SET_SCORE, score)); } public void setCapabilityFilter(NetworkCapabilities netCap) { From 2b6477198de0c3c0e1b1e14f34e58edc2bdccf6a Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 29 Mar 2021 15:45:50 +0800 Subject: [PATCH 161/777] [SP28.2] Add shims to allow test utils built against different SDKs Test: build pass with or without aosp/1469125 in frameworks/base Test: atest NetworkStatsServiceTest TetheringTests Bug: 149467454 Change-Id: Ie3971ed3b18e0f1a54d4834e310bc6df82e5acdd --- .../NetworkStatsProviderCbStubCompat.java | 43 +++++++++++++++++++ .../NetworkStatsProviderStubCompat.java | 37 ++++++++++++++++ .../TestableNetworkStatsProviderBinder.kt | 3 +- .../TestableNetworkStatsProviderCbBinder.kt | 3 +- 4 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 staticlibs/devicetests/com/android/testutils/NetworkStatsProviderCbStubCompat.java create mode 100644 staticlibs/devicetests/com/android/testutils/NetworkStatsProviderStubCompat.java diff --git a/staticlibs/devicetests/com/android/testutils/NetworkStatsProviderCbStubCompat.java b/staticlibs/devicetests/com/android/testutils/NetworkStatsProviderCbStubCompat.java new file mode 100644 index 0000000000..e84a224f30 --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/NetworkStatsProviderCbStubCompat.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 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 com.android.testutils; + +import android.net.NetworkStats; +import android.net.netstats.provider.INetworkStatsProviderCallback; +import android.os.RemoteException; + +/** + * A shim class that allows {@link TestableNetworkStatsProviderCbBinder} to be built against + * different SDK versions. + */ +public class NetworkStatsProviderCbStubCompat extends INetworkStatsProviderCallback.Stub { + @Override + public void notifyStatsUpdated(int token, NetworkStats ifaceStats, NetworkStats uidStats) + throws RemoteException {} + + @Override + public void notifyAlertReached() throws RemoteException {} + + // Removed in S. + public void notifyLimitReached() throws RemoteException {} + + // Added in S. + public void notifyWarningOrLimitReached() throws RemoteException {} + + @Override + public void unregister() throws RemoteException {} +} diff --git a/staticlibs/devicetests/com/android/testutils/NetworkStatsProviderStubCompat.java b/staticlibs/devicetests/com/android/testutils/NetworkStatsProviderStubCompat.java new file mode 100644 index 0000000000..a77aa025ac --- /dev/null +++ b/staticlibs/devicetests/com/android/testutils/NetworkStatsProviderStubCompat.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 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 com.android.testutils; + +import android.net.netstats.provider.INetworkStatsProvider; + +/** + * A shim class that allows {@link TestableNetworkStatsProviderBinder} to be built against + * different SDK versions. + */ +public class NetworkStatsProviderStubCompat extends INetworkStatsProvider.Stub { + @Override + public void onRequestStatsUpdate(int token) {} + + // Removed and won't be called in S+. + public void onSetLimit(String iface, long quotaBytes) {} + + @Override + public void onSetAlert(long bytes) {} + + // Added in S. + public void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes) {} +} diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt index 02922d87ea..d71f6042c0 100644 --- a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt +++ b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt @@ -16,14 +16,13 @@ package com.android.testutils -import android.net.netstats.provider.INetworkStatsProvider import com.android.net.module.util.ArrayTrackRecord import kotlin.test.assertEquals import kotlin.test.fail private const val DEFAULT_TIMEOUT_MS = 200L -open class TestableNetworkStatsProviderBinder : INetworkStatsProvider.Stub() { +open class TestableNetworkStatsProviderBinder : NetworkStatsProviderStubCompat() { sealed class CallbackType { data class OnRequestStatsUpdate(val token: Int) : CallbackType() data class OnSetLimit(val iface: String?, val quotaBytes: Long) : CallbackType() diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt index 163473a362..ea6b1dc48a 100644 --- a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt +++ b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt @@ -17,7 +17,6 @@ package com.android.testutils import android.net.NetworkStats -import android.net.netstats.provider.INetworkStatsProviderCallback import com.android.net.module.util.ArrayTrackRecord import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -25,7 +24,7 @@ import kotlin.test.fail private const val DEFAULT_TIMEOUT_MS = 3000L -open class TestableNetworkStatsProviderCbBinder : INetworkStatsProviderCallback.Stub() { +open class TestableNetworkStatsProviderCbBinder : NetworkStatsProviderCbStubCompat() { sealed class CallbackType { data class NotifyStatsUpdated( val token: Int, From 3a6ab33439edbdfbb479e42008c75fbb75a25932 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 21 Oct 2020 15:27:04 +0800 Subject: [PATCH 162/777] [SP28.1] Add onSetWarningAndLimit to test utilities Test: atest NetworkStatsServiceTest Bug: 149467454 Bug: 170699770 Bug: 170179169 Merged-In: I4cc242e5fba895bb0756733bafc5be1f39b10ac0 Change-Id: I4cc242e5fba895bb0756733bafc5be1f39b10ac0 (cherry-picked from ag/13970092) --- .../TestableNetworkStatsProviderBinder.kt | 19 ++++++++++++------- .../TestableNetworkStatsProviderCbBinder.kt | 10 +++++----- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt index d71f6042c0..643346b2e6 100644 --- a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt +++ b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt @@ -25,8 +25,12 @@ private const val DEFAULT_TIMEOUT_MS = 200L open class TestableNetworkStatsProviderBinder : NetworkStatsProviderStubCompat() { sealed class CallbackType { data class OnRequestStatsUpdate(val token: Int) : CallbackType() - data class OnSetLimit(val iface: String?, val quotaBytes: Long) : CallbackType() data class OnSetAlert(val quotaBytes: Long) : CallbackType() + data class OnSetWarningAndLimit( + val iface: String, + val warningBytes: Long, + val limitBytes: Long + ) : CallbackType() } private val history = ArrayTrackRecord().ReadHead() @@ -35,20 +39,21 @@ open class TestableNetworkStatsProviderBinder : NetworkStatsProviderStubCompat() history.add(CallbackType.OnRequestStatsUpdate(token)) } - override fun onSetLimit(iface: String?, quotaBytes: Long) { - history.add(CallbackType.OnSetLimit(iface, quotaBytes)) - } - override fun onSetAlert(quotaBytes: Long) { history.add(CallbackType.OnSetAlert(quotaBytes)) } + override fun onSetWarningAndLimit(iface: String, warningBytes: Long, limitBytes: Long) { + history.add(CallbackType.OnSetWarningAndLimit(iface, warningBytes, limitBytes)) + } + fun expectOnRequestStatsUpdate(token: Int) { assertEquals(CallbackType.OnRequestStatsUpdate(token), history.poll(DEFAULT_TIMEOUT_MS)) } - fun expectOnSetLimit(iface: String?, quotaBytes: Long) { - assertEquals(CallbackType.OnSetLimit(iface, quotaBytes), history.poll(DEFAULT_TIMEOUT_MS)) + fun expectOnSetWarningAndLimit(iface: String, warningBytes: Long, limitBytes: Long) { + assertEquals(CallbackType.OnSetWarningAndLimit(iface, warningBytes, limitBytes), + history.poll(DEFAULT_TIMEOUT_MS)) } fun expectOnSetAlert(quotaBytes: Long) { diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt index ea6b1dc48a..f15f610b5a 100644 --- a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt +++ b/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt @@ -31,7 +31,7 @@ open class TestableNetworkStatsProviderCbBinder : NetworkStatsProviderCbStubComp val ifaceStats: NetworkStats, val uidStats: NetworkStats ) : CallbackType() - object NotifyLimitReached : CallbackType() + object NotifyWarningOrLimitReached : CallbackType() object NotifyAlertReached : CallbackType() object Unregister : CallbackType() } @@ -42,8 +42,8 @@ open class TestableNetworkStatsProviderCbBinder : NetworkStatsProviderCbStubComp history.add(CallbackType.NotifyStatsUpdated(token, ifaceStats, uidStats)) } - override fun notifyLimitReached() { - history.add(CallbackType.NotifyLimitReached) + override fun notifyWarningOrLimitReached() { + history.add(CallbackType.NotifyWarningOrLimitReached) } override fun notifyAlertReached() { @@ -69,8 +69,8 @@ open class TestableNetworkStatsProviderCbBinder : NetworkStatsProviderCbStubComp assertNetworkStatsEquals(uidStats, event.uidStats) } - fun expectNotifyLimitReached() = - assertEquals(CallbackType.NotifyLimitReached, history.poll(DEFAULT_TIMEOUT_MS)) + fun expectNotifyWarningOrLimitReached() = + assertEquals(CallbackType.NotifyWarningOrLimitReached, history.poll(DEFAULT_TIMEOUT_MS)) fun expectNotifyAlertReached() = assertEquals(CallbackType.NotifyAlertReached, history.poll(DEFAULT_TIMEOUT_MS)) From be2a07fce3b9182949e0522fefcfe5f1d9013a85 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 29 Mar 2021 17:09:13 +0900 Subject: [PATCH 163/777] Move net-test-utils to its own directory Having the test targets in a different directory allows setting visibility rules for tests only, which is necessary for access to targets that should not be used for device builds. Bug: 182859030 Test: m Change-Id: Iaf426cf339a97833acf80c941db692329c6e2dcb --- staticlibs/Android.bp | 39 +------------- staticlibs/testutils/Android.bp | 51 +++++++++++++++++++ .../com/android/testutils/ArpResponder.kt | 0 .../com/android/testutils/CompatUtil.kt | 0 .../testutils/ConcurrentInterpreter.kt | 0 .../com/android/testutils/DevSdkIgnoreRule.kt | 0 .../android/testutils/DevSdkIgnoreRunner.kt | 0 .../com/android/testutils/FakeDns.kt | 0 .../com/android/testutils/HandlerUtils.kt | 0 .../NetworkStatsProviderCbStubCompat.java | 0 .../NetworkStatsProviderStubCompat.java | 0 .../android/testutils/NetworkStatsUtils.kt | 0 .../com/android/testutils/PacketResponder.kt | 0 .../com/android/testutils/ParcelUtils.kt | 0 .../android/testutils/TapPacketReader.java | 0 .../android/testutils/TapPacketReaderRule.kt | 0 .../com/android/testutils/TestHttpServer.kt | 0 .../android/testutils/TestNetworkTracker.kt | 0 .../android/testutils/TestPermissionUtil.kt | 0 .../testutils/TestableNetworkCallback.kt | 0 .../testutils/TestableNetworkStatsProvider.kt | 0 .../TestableNetworkStatsProviderBinder.kt | 0 .../TestableNetworkStatsProviderCbBinder.kt | 0 .../android/net/module/util/TrackRecord.kt | 0 .../com/android/testutils/ConcurrentUtils.kt | 0 .../com/android/testutils/ExceptionUtils.java | 0 .../com/android/testutils/FileUtils.kt | 0 .../com/android/testutils/MiscAsserts.kt | 0 .../com/android/testutils/PacketFilter.kt | 0 .../com/android/testutils/SkipPresubmit.kt | 0 30 files changed, 52 insertions(+), 38 deletions(-) create mode 100644 staticlibs/testutils/Android.bp rename staticlibs/{ => testutils}/devicetests/com/android/testutils/ArpResponder.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/CompatUtil.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/ConcurrentInterpreter.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/DevSdkIgnoreRule.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/FakeDns.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/HandlerUtils.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/NetworkStatsProviderCbStubCompat.java (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/NetworkStatsProviderStubCompat.java (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/NetworkStatsUtils.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/PacketResponder.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/ParcelUtils.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/TapPacketReader.java (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/TapPacketReaderRule.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/TestHttpServer.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/TestNetworkTracker.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/TestPermissionUtil.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/TestableNetworkCallback.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt (100%) rename staticlibs/{ => testutils}/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt (100%) rename staticlibs/{ => testutils}/hostdevice/com/android/net/module/util/TrackRecord.kt (100%) rename staticlibs/{ => testutils}/hostdevice/com/android/testutils/ConcurrentUtils.kt (100%) rename staticlibs/{ => testutils}/hostdevice/com/android/testutils/ExceptionUtils.java (100%) rename staticlibs/{ => testutils}/hostdevice/com/android/testutils/FileUtils.kt (100%) rename staticlibs/{ => testutils}/hostdevice/com/android/testutils/MiscAsserts.kt (100%) rename staticlibs/{ => testutils}/hostdevice/com/android/testutils/PacketFilter.kt (100%) rename staticlibs/{ => testutils}/hostdevice/com/android/testutils/SkipPresubmit.kt (100%) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 03296e7304..74aafd30dd 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -59,6 +59,7 @@ java_library { "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", + "//frameworks/libs/net/common/testutils:__subpackages__", ], static_libs: [ "net-utils-framework-common", @@ -68,25 +69,6 @@ java_library { ], } -java_library { - // Consider using net-tests-utils instead if writing device code. - // That library has a lot more useful tools into it for users that - // work on Android and includes this lib. - name: "net-tests-utils-host-device-common", - srcs: [ - "hostdevice/**/*.java", - "hostdevice/**/*.kt", - ], - host_supported: true, - visibility: [ - "//frameworks/libs/net/common/tests:__subpackages__", - "//frameworks/libs/net/client-libs/tests:__subpackages__", - ], - static_libs: [ - "kotlin-test" - ] -} - java_defaults { name: "lib_mockito_extended", static_libs: [ @@ -98,25 +80,6 @@ java_defaults { ], } -java_library { - name: "net-tests-utils", - srcs: [ - "devicetests/**/*.java", - "devicetests/**/*.kt", - ], - defaults: ["lib_mockito_extended"], - libs: [ - "androidx.annotation_annotation", - ], - static_libs: [ - "androidx.test.ext.junit", - "kotlin-reflect", - "libnanohttpd", - "net-tests-utils-host-device-common", - "net-utils-device-common", - ], -} - filegroup { name: "net-utils-framework-common-srcs", srcs: ["framework/**/*.java"], diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp new file mode 100644 index 0000000000..bea5e5a317 --- /dev/null +++ b/staticlibs/testutils/Android.bp @@ -0,0 +1,51 @@ +// Copyright (C) 2021 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. + +java_library { + name: "net-tests-utils", + srcs: [ + "devicetests/**/*.java", + "devicetests/**/*.kt", + ], + defaults: ["lib_mockito_extended"], + libs: [ + "androidx.annotation_annotation", + ], + static_libs: [ + "androidx.test.ext.junit", + "kotlin-reflect", + "libnanohttpd", + "net-tests-utils-host-device-common", + "net-utils-device-common", + ], +} + +java_library { + // Consider using net-tests-utils instead if writing device code. + // That library has a lot more useful tools into it for users that + // work on Android and includes this lib. + name: "net-tests-utils-host-device-common", + srcs: [ + "hostdevice/**/*.java", + "hostdevice/**/*.kt", + ], + host_supported: true, + visibility: [ + "//frameworks/libs/net/common/tests:__subpackages__", + "//frameworks/libs/net/client-libs/tests:__subpackages__", + ], + static_libs: [ + "kotlin-test" + ] +} diff --git a/staticlibs/devicetests/com/android/testutils/ArpResponder.kt b/staticlibs/testutils/devicetests/com/android/testutils/ArpResponder.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/ArpResponder.kt rename to staticlibs/testutils/devicetests/com/android/testutils/ArpResponder.kt diff --git a/staticlibs/devicetests/com/android/testutils/CompatUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/CompatUtil.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/CompatUtil.kt rename to staticlibs/testutils/devicetests/com/android/testutils/CompatUtil.kt diff --git a/staticlibs/devicetests/com/android/testutils/ConcurrentInterpreter.kt b/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/ConcurrentInterpreter.kt rename to staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt diff --git a/staticlibs/devicetests/com/android/testutils/DevSdkIgnoreRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/DevSdkIgnoreRule.kt rename to staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt diff --git a/staticlibs/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt rename to staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt diff --git a/staticlibs/devicetests/com/android/testutils/FakeDns.kt b/staticlibs/testutils/devicetests/com/android/testutils/FakeDns.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/FakeDns.kt rename to staticlibs/testutils/devicetests/com/android/testutils/FakeDns.kt diff --git a/staticlibs/devicetests/com/android/testutils/HandlerUtils.kt b/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/HandlerUtils.kt rename to staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt diff --git a/staticlibs/devicetests/com/android/testutils/NetworkStatsProviderCbStubCompat.java b/staticlibs/testutils/devicetests/com/android/testutils/NetworkStatsProviderCbStubCompat.java similarity index 100% rename from staticlibs/devicetests/com/android/testutils/NetworkStatsProviderCbStubCompat.java rename to staticlibs/testutils/devicetests/com/android/testutils/NetworkStatsProviderCbStubCompat.java diff --git a/staticlibs/devicetests/com/android/testutils/NetworkStatsProviderStubCompat.java b/staticlibs/testutils/devicetests/com/android/testutils/NetworkStatsProviderStubCompat.java similarity index 100% rename from staticlibs/devicetests/com/android/testutils/NetworkStatsProviderStubCompat.java rename to staticlibs/testutils/devicetests/com/android/testutils/NetworkStatsProviderStubCompat.java diff --git a/staticlibs/devicetests/com/android/testutils/NetworkStatsUtils.kt b/staticlibs/testutils/devicetests/com/android/testutils/NetworkStatsUtils.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/NetworkStatsUtils.kt rename to staticlibs/testutils/devicetests/com/android/testutils/NetworkStatsUtils.kt diff --git a/staticlibs/devicetests/com/android/testutils/PacketResponder.kt b/staticlibs/testutils/devicetests/com/android/testutils/PacketResponder.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/PacketResponder.kt rename to staticlibs/testutils/devicetests/com/android/testutils/PacketResponder.kt diff --git a/staticlibs/devicetests/com/android/testutils/ParcelUtils.kt b/staticlibs/testutils/devicetests/com/android/testutils/ParcelUtils.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/ParcelUtils.kt rename to staticlibs/testutils/devicetests/com/android/testutils/ParcelUtils.kt diff --git a/staticlibs/devicetests/com/android/testutils/TapPacketReader.java b/staticlibs/testutils/devicetests/com/android/testutils/TapPacketReader.java similarity index 100% rename from staticlibs/devicetests/com/android/testutils/TapPacketReader.java rename to staticlibs/testutils/devicetests/com/android/testutils/TapPacketReader.java diff --git a/staticlibs/devicetests/com/android/testutils/TapPacketReaderRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/TapPacketReaderRule.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/TapPacketReaderRule.kt rename to staticlibs/testutils/devicetests/com/android/testutils/TapPacketReaderRule.kt diff --git a/staticlibs/devicetests/com/android/testutils/TestHttpServer.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/TestHttpServer.kt rename to staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt diff --git a/staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/TestNetworkTracker.kt rename to staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt diff --git a/staticlibs/devicetests/com/android/testutils/TestPermissionUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestPermissionUtil.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/TestPermissionUtil.kt rename to staticlibs/testutils/devicetests/com/android/testutils/TestPermissionUtil.kt diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/TestableNetworkCallback.kt rename to staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt rename to staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt rename to staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProviderBinder.kt diff --git a/staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt similarity index 100% rename from staticlibs/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt rename to staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt diff --git a/staticlibs/hostdevice/com/android/net/module/util/TrackRecord.kt b/staticlibs/testutils/hostdevice/com/android/net/module/util/TrackRecord.kt similarity index 100% rename from staticlibs/hostdevice/com/android/net/module/util/TrackRecord.kt rename to staticlibs/testutils/hostdevice/com/android/net/module/util/TrackRecord.kt diff --git a/staticlibs/hostdevice/com/android/testutils/ConcurrentUtils.kt b/staticlibs/testutils/hostdevice/com/android/testutils/ConcurrentUtils.kt similarity index 100% rename from staticlibs/hostdevice/com/android/testutils/ConcurrentUtils.kt rename to staticlibs/testutils/hostdevice/com/android/testutils/ConcurrentUtils.kt diff --git a/staticlibs/hostdevice/com/android/testutils/ExceptionUtils.java b/staticlibs/testutils/hostdevice/com/android/testutils/ExceptionUtils.java similarity index 100% rename from staticlibs/hostdevice/com/android/testutils/ExceptionUtils.java rename to staticlibs/testutils/hostdevice/com/android/testutils/ExceptionUtils.java diff --git a/staticlibs/hostdevice/com/android/testutils/FileUtils.kt b/staticlibs/testutils/hostdevice/com/android/testutils/FileUtils.kt similarity index 100% rename from staticlibs/hostdevice/com/android/testutils/FileUtils.kt rename to staticlibs/testutils/hostdevice/com/android/testutils/FileUtils.kt diff --git a/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt b/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt similarity index 100% rename from staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt rename to staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt diff --git a/staticlibs/hostdevice/com/android/testutils/PacketFilter.kt b/staticlibs/testutils/hostdevice/com/android/testutils/PacketFilter.kt similarity index 100% rename from staticlibs/hostdevice/com/android/testutils/PacketFilter.kt rename to staticlibs/testutils/hostdevice/com/android/testutils/PacketFilter.kt diff --git a/staticlibs/hostdevice/com/android/testutils/SkipPresubmit.kt b/staticlibs/testutils/hostdevice/com/android/testutils/SkipPresubmit.kt similarity index 100% rename from staticlibs/hostdevice/com/android/testutils/SkipPresubmit.kt rename to staticlibs/testutils/hostdevice/com/android/testutils/SkipPresubmit.kt From e998b8a75a4aa024fb5238c08e5b95272f8df7e0 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Mon, 29 Mar 2021 10:36:58 +0800 Subject: [PATCH 164/777] Break the reference for the new added API constant RESTRICTED_CAPABILITIES was moved from NetworkCapabilities to frameworks/libs/net. RESTRICTED_CAPABILITIES refers to some S added NET_CAPABILITIES_* definitions. Replace the constants definitions with local constants because this git will downstream to branches without this constants. Downstream will not be able to find the references in NetworkCapailities and cause breakage. Bug: 178777253 Bug: 130869457 Test: m Change-Id: I270593c12c1a7ff9f05d3bcd5f6d5647f89efb63 Ignore-AOSP-First: code conflict --- .../module/util/NetworkCapabilitiesUtils.java | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index e51c5f26d4..0d2ad01566 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -16,11 +16,9 @@ package com.android.net.module.util; -import static android.net.NetworkCapabilities.NET_CAPABILITY_BIP; import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS; -import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE; import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA; import static android.net.NetworkCapabilities.NET_CAPABILITY_IA; import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; @@ -28,11 +26,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MCX; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; -import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE; import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS; import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL; -import static android.net.NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL; -import static android.net.NetworkCapabilities.NET_CAPABILITY_VSIM; import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P; import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP; import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; @@ -76,6 +71,43 @@ public final class NetworkCapabilitiesUtils { // realistic as possible. }; + /** + * @See android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE + * TODO: Use API constant when all downstream branches are S-based + */ + public static final int NET_CAPABILITY_OEM_PRIVATE = 26; + + /** + * @See android.net.NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL + * TODO: Use API constant when all downstream branches are S-based + */ + public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; + + /** + * @See android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED + * TODO: Use API constant when all downstream branches are S-based + */ + public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; + + /** + * @See android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED + * TODO: Use API constant when all downstream branches are S-based + */ + public static final int NET_CAPABILITY_ENTERPRISE = 29; + + /** + * @See android.net.NetworkCapabilities.NET_CAPABILITY_VSIM + * TODO: Use API constant when all downstream branches are S-based + */ + public static final int NET_CAPABILITY_VSIM = 30; + + /** + * @See android.net.NetworkCapabilities.NET_CAPABILITY_BIP + * TODO: Use API constant when all downstream branches are S-based + */ + public static final int NET_CAPABILITY_BIP = 31; + + /** * Capabilities that suggest that a network is restricted. * See {@code NetworkCapabilities#maybeMarkCapabilitiesRestricted}, From 1c9edae84c4704ea703df91b32b4ad6348691417 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 30 Mar 2021 17:20:14 +0800 Subject: [PATCH 165/777] Reimplement inferRestrictedCapability without new exposed API Method inferRestrictedCapability() was moved from frameworks/base to libs/net and it is using an API NetworkCapabilities.getCapabilities() which is a new exposed API in S. However, the change of moving the method will downstream to the branches without the new exposed API. Thus, reimplement this method without new exposed API. Ignore-AOSP-First: code conflict Bug: 178777253 Bug: 130869457 Test: NetworkStaticLibTests Change-Id: Ib88fe2b831e968513f221443ed62a09c02150882 --- .../module/util/NetworkCapabilitiesUtils.java | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 0d2ad01566..60808eeb5d 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -90,7 +90,7 @@ public final class NetworkCapabilitiesUtils { public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; /** - * @See android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED + * @See android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE * TODO: Use API constant when all downstream branches are S-based */ public static final int NET_CAPABILITY_ENTERPRISE = 29; @@ -182,22 +182,30 @@ public final class NetworkCapabilitiesUtils { * * @return {@code true} if the network should be restricted. */ + // TODO: Use packBits(nc.getCapabilities()) to check more easily using bit masks. public static boolean inferRestrictedCapability(NetworkCapabilities nc) { - final long capabilities = packBits(nc.getCapabilities()); // Check if we have any capability that forces the network to be restricted. - final boolean forceRestrictedCapability = - (capabilities & FORCE_RESTRICTED_CAPABILITIES) != 0; + for (int capability : unpackBits(FORCE_RESTRICTED_CAPABILITIES)) { + if (nc.hasCapability(capability)) { + return true; + } + } // Verify there aren't any unrestricted capabilities. If there are we say // the whole thing is unrestricted unless it is forced to be restricted. - final boolean hasUnrestrictedCapabilities = - (capabilities & UNRESTRICTED_CAPABILITIES) != 0; + for (int capability : unpackBits(UNRESTRICTED_CAPABILITIES)) { + if (nc.hasCapability(capability)) { + return false; + } + } // Must have at least some restricted capabilities. - final boolean hasRestrictedCapabilities = (capabilities & RESTRICTED_CAPABILITIES) != 0; - - return forceRestrictedCapability - || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities); + for (int capability : unpackBits(RESTRICTED_CAPABILITIES)) { + if (nc.hasCapability(capability)) { + return true; + } + } + return false; } /** From 9802148967b31ccc4eef3ef33dbd3ce5cbfb2ca3 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Tue, 30 Mar 2021 22:55:10 -0700 Subject: [PATCH 166/777] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/libs/net Added SPDX-license-identifier-Apache-2.0 to: common/testutils/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: Ib947b1cd6eae235e77cd55d57673360c426e80f1 --- staticlibs/testutils/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index bea5e5a317..d4465dd717 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + java_library { name: "net-tests-utils", srcs: [ From d7830e3ddc52df20a05dc702409d8fa4e366ccf0 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 19 Mar 2021 23:02:29 +0800 Subject: [PATCH 167/777] Move deduceRestrictedCapability to libs/net and rename it NetworkCapabilities is included in framework-connectivity, so external module cannot have dependencies on its hidden API. Move the method to libs/net and rename it to inferRestrictedCapability so that external module can use it by inculding the library. Bug: 178777253 Test: FrameworksNetTests NetworkStaticLibTests (cherry-picked from ag/13930236) Merged-In: I51244048e31699b562b1444d88511e3a3da845ec Change-Id: I51244048e31699b562b1444d88511e3a3da845ec --- .../module/util/NetworkCapabilitiesUtils.java | 84 +++++++++++++++++++ .../util/NetworkCapabilitiesUtilsTest.kt | 46 ++++++++++ 2 files changed, 130 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 3de78c61a9..568a356113 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -16,6 +16,23 @@ package com.android.net.module.util; +import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE; +import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA; +import static android.net.NetworkCapabilities.NET_CAPABILITY_IA; +import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_MCX; +import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; +import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE; +import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL; +import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P; +import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP; import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; @@ -24,7 +41,9 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; import android.annotation.NonNull; +import android.net.NetworkCapabilities; +import com.android.internal.annotations.VisibleForTesting; /** * Utilities to examine {@link android.net.NetworkCapabilities}. @@ -54,6 +73,44 @@ public final class NetworkCapabilitiesUtils { // realistic as possible. }; + /** + * Capabilities that suggest that a network is restricted. + * See {@code NetworkCapabilities#maybeMarkCapabilitiesRestricted}, + * and {@code FORCE_RESTRICTED_CAPABILITIES}. + */ + @VisibleForTesting + static final long RESTRICTED_CAPABILITIES = + (1 << NET_CAPABILITY_CBS) + | (1 << NET_CAPABILITY_DUN) + | (1 << NET_CAPABILITY_EIMS) + | (1 << NET_CAPABILITY_FOTA) + | (1 << NET_CAPABILITY_IA) + | (1 << NET_CAPABILITY_IMS) + | (1 << NET_CAPABILITY_MCX) + | (1 << NET_CAPABILITY_RCS) + | (1 << NET_CAPABILITY_VEHICLE_INTERNAL) + | (1 << NET_CAPABILITY_XCAP) + | (1 << NET_CAPABILITY_ENTERPRISE); + + /** + * Capabilities that force network to be restricted. + * See {@code NetworkCapabilities#maybeMarkCapabilitiesRestricted}. + */ + private static final long FORCE_RESTRICTED_CAPABILITIES = + (1 << NET_CAPABILITY_OEM_PAID) + | (1 << NET_CAPABILITY_OEM_PRIVATE); + + /** + * Capabilities that suggest that a network is unrestricted. + * See {@code NetworkCapabilities#maybeMarkCapabilitiesRestricted}. + */ + @VisibleForTesting + static final long UNRESTRICTED_CAPABILITIES = + (1 << NET_CAPABILITY_INTERNET) + | (1 << NET_CAPABILITY_MMS) + | (1 << NET_CAPABILITY_SUPL) + | (1 << NET_CAPABILITY_WIFI_P2P); + /** * Get a transport that can be used to classify a network when displaying its info to users. * @@ -79,6 +136,33 @@ public final class NetworkCapabilitiesUtils { return transports[0]; } + + /** + * Infers that all the capabilities it provides are typically provided by restricted networks + * or not. + * + * @param nc the {@link NetworkCapabilities} to infer the restricted capabilities. + * + * @return {@code true} if the network should be restricted. + */ + public static boolean inferRestrictedCapability(NetworkCapabilities nc) { + final long capabilities = packBits(nc.getCapabilities()); + // Check if we have any capability that forces the network to be restricted. + final boolean forceRestrictedCapability = + (capabilities & FORCE_RESTRICTED_CAPABILITIES) != 0; + + // Verify there aren't any unrestricted capabilities. If there are we say + // the whole thing is unrestricted unless it is forced to be restricted. + final boolean hasUnrestrictedCapabilities = + (capabilities & UNRESTRICTED_CAPABILITIES) != 0; + + // Must have at least some restricted capabilities. + final boolean hasRestrictedCapabilities = (capabilities & RESTRICTED_CAPABILITIES) != 0; + + return forceRestrictedCapability + || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities); + } + /** * Unpacks long value into an array of bits. */ diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt index df2f45999d..5f15c6ac0c 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt @@ -16,6 +16,12 @@ package com.android.net.module.util +import android.net.NetworkCapabilities +import android.net.NetworkCapabilities.NET_CAPABILITY_CBS +import android.net.NetworkCapabilities.NET_CAPABILITY_EIMS +import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET +import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET +import android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH import android.net.NetworkCapabilities.TRANSPORT_CELLULAR import android.net.NetworkCapabilities.TRANSPORT_ETHERNET @@ -25,6 +31,8 @@ import android.net.NetworkCapabilities.TRANSPORT_WIFI import android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 +import com.android.net.module.util.NetworkCapabilitiesUtils.RESTRICTED_CAPABILITIES +import com.android.net.module.util.NetworkCapabilitiesUtils.UNRESTRICTED_CAPABILITIES import com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport import com.android.net.module.util.NetworkCapabilitiesUtils.packBits import com.android.net.module.util.NetworkCapabilitiesUtils.unpackBits @@ -33,6 +41,7 @@ import org.junit.runner.RunWith import java.lang.IllegalArgumentException import kotlin.test.assertEquals import kotlin.test.assertFailsWith +import kotlin.test.assertFalse import kotlin.test.assertTrue @RunWith(AndroidJUnit4::class) @@ -78,4 +87,41 @@ class NetworkCapabilitiesUtilsTest { assertEquals(packedBits, packBits(bits)) assertTrue(bits contentEquals unpackBits(packedBits)) } + + @Test + fun testInferRestrictedCapability() { + val nc = NetworkCapabilities() + // Default capabilities don't have restricted capability. + assertFalse(NetworkCapabilitiesUtils.inferRestrictedCapability(nc)) + // If there is a force restricted capability, then the network capabilities is restricted. + nc.addCapability(NET_CAPABILITY_OEM_PAID) + nc.addCapability(NET_CAPABILITY_INTERNET) + assertTrue(NetworkCapabilitiesUtils.inferRestrictedCapability(nc)) + // Except for the force restricted capability, if there is any unrestricted capability in + // capabilities, then the network capabilities is not restricted. + nc.removeCapability(NET_CAPABILITY_OEM_PAID) + nc.addCapability(NET_CAPABILITY_CBS) + assertFalse(NetworkCapabilitiesUtils.inferRestrictedCapability(nc)) + // Except for the force restricted capability, the network capabilities will only be treated + // as restricted when there is no any unrestricted capability. + nc.removeCapability(NET_CAPABILITY_INTERNET) + assertTrue(NetworkCapabilitiesUtils.inferRestrictedCapability(nc)) + } + + @Test + fun testRestrictedUnrestrictedCapabilities() { + // verify EIMS is restricted + assertEquals((1 shl NET_CAPABILITY_EIMS).toLong() and RESTRICTED_CAPABILITIES, + (1 shl NET_CAPABILITY_EIMS).toLong()) + + // verify CBS is also restricted + assertEquals((1 shl NET_CAPABILITY_CBS).toLong() and RESTRICTED_CAPABILITIES, + (1 shl NET_CAPABILITY_CBS).toLong()) + + // verify default is not restricted + assertEquals((1 shl NET_CAPABILITY_INTERNET).toLong() and RESTRICTED_CAPABILITIES, 0) + + // just to see + assertEquals(RESTRICTED_CAPABILITIES and UNRESTRICTED_CAPABILITIES, 0) + } } From 4f804964092fb206787b4e12d9484e9507fc6a3c Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 25 Mar 2021 12:07:27 +0800 Subject: [PATCH 168/777] Update new capabilities into restricted capabilities NET_CAPABILITY_VSIM and NET_CAPABILITY_BIP are new restricted capabiltity for carrier usage. Update them the RESTRICTED_CAPABILITIES. Bug: 130869457 Test: m Change-Id: I20e3cf34634cf0c106560fc4173fcfb91d85724e Merged-In: I20e3cf34634cf0c106560fc4173fcfb91d85724e --- .../net/module/util/NetworkCapabilitiesUtils.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 568a356113..9e4a161ba5 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -16,6 +16,7 @@ package com.android.net.module.util; +import static android.net.NetworkCapabilities.NET_CAPABILITY_BIP; import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS; @@ -31,6 +32,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE; import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS; import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL; import static android.net.NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VSIM; import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P; import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP; import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; @@ -80,17 +82,19 @@ public final class NetworkCapabilitiesUtils { */ @VisibleForTesting static final long RESTRICTED_CAPABILITIES = - (1 << NET_CAPABILITY_CBS) + (1 << NET_CAPABILITY_BIP) + | (1 << NET_CAPABILITY_CBS) | (1 << NET_CAPABILITY_DUN) | (1 << NET_CAPABILITY_EIMS) + | (1 << NET_CAPABILITY_ENTERPRISE) | (1 << NET_CAPABILITY_FOTA) | (1 << NET_CAPABILITY_IA) | (1 << NET_CAPABILITY_IMS) | (1 << NET_CAPABILITY_MCX) | (1 << NET_CAPABILITY_RCS) | (1 << NET_CAPABILITY_VEHICLE_INTERNAL) - | (1 << NET_CAPABILITY_XCAP) - | (1 << NET_CAPABILITY_ENTERPRISE); + | (1 << NET_CAPABILITY_VSIM) + | (1 << NET_CAPABILITY_XCAP); /** * Capabilities that force network to be restricted. From 43da8b835eb03ce749cc50cc59430a59dd509045 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Mon, 29 Mar 2021 10:36:58 +0800 Subject: [PATCH 169/777] Break the reference for the new added API constant RESTRICTED_CAPABILITIES was moved from NetworkCapabilities to frameworks/libs/net. RESTRICTED_CAPABILITIES refers to some S added NET_CAPABILITIES_* definitions. Replace the constants definitions with local constants because this git will downstream to branches without this constants. Downstream will not be able to find the references in NetworkCapailities and cause breakage. Bug: 178777253 Bug: 130869457 Test: m (cherry-picked from ag/14008231) Merged-In: I270593c12c1a7ff9f05d3bcd5f6d5647f89efb63 Change-Id: I270593c12c1a7ff9f05d3bcd5f6d5647f89efb63 --- .../module/util/NetworkCapabilitiesUtils.java | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 9e4a161ba5..28214cd8e7 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -16,11 +16,9 @@ package com.android.net.module.util; -import static android.net.NetworkCapabilities.NET_CAPABILITY_BIP; import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS; -import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE; import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA; import static android.net.NetworkCapabilities.NET_CAPABILITY_IA; import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; @@ -28,11 +26,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MCX; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; -import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE; import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS; import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL; -import static android.net.NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL; -import static android.net.NetworkCapabilities.NET_CAPABILITY_VSIM; import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P; import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP; import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; @@ -75,6 +70,43 @@ public final class NetworkCapabilitiesUtils { // realistic as possible. }; + /** + * @See android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE + * TODO: Use API constant when all downstream branches are S-based + */ + public static final int NET_CAPABILITY_OEM_PRIVATE = 26; + + /** + * @See android.net.NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL + * TODO: Use API constant when all downstream branches are S-based + */ + public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; + + /** + * @See android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED + * TODO: Use API constant when all downstream branches are S-based + */ + public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; + + /** + * @See android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED + * TODO: Use API constant when all downstream branches are S-based + */ + public static final int NET_CAPABILITY_ENTERPRISE = 29; + + /** + * @See android.net.NetworkCapabilities.NET_CAPABILITY_VSIM + * TODO: Use API constant when all downstream branches are S-based + */ + public static final int NET_CAPABILITY_VSIM = 30; + + /** + * @See android.net.NetworkCapabilities.NET_CAPABILITY_BIP + * TODO: Use API constant when all downstream branches are S-based + */ + public static final int NET_CAPABILITY_BIP = 31; + + /** * Capabilities that suggest that a network is restricted. * See {@code NetworkCapabilities#maybeMarkCapabilitiesRestricted}, From 8df2356e1cc71a2ad545a06475b560a56ddd639a Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 30 Mar 2021 17:20:14 +0800 Subject: [PATCH 170/777] Reimplement inferRestrictedCapability without new exposed API Method inferRestrictedCapability() was moved from frameworks/base to libs/net and it is using an API NetworkCapabilities.getCapabilities() which is a new exposed API in S. However, the change of moving the method will downstream to the branches without the new exposed API. Thus, reimplement this method without new exposed API. (cherry-picked from ag/14029492) Bug: 178777253 Bug: 130869457 Test: NetworkStaticLibTests Merged-In: Ib88fe2b831e968513f221443ed62a09c02150882 Change-Id: Ib88fe2b831e968513f221443ed62a09c02150882 --- .../module/util/NetworkCapabilitiesUtils.java | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 28214cd8e7..7bf8fc1254 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -89,7 +89,7 @@ public final class NetworkCapabilitiesUtils { public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; /** - * @See android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED + * @See android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE * TODO: Use API constant when all downstream branches are S-based */ public static final int NET_CAPABILITY_ENTERPRISE = 29; @@ -181,22 +181,30 @@ public final class NetworkCapabilitiesUtils { * * @return {@code true} if the network should be restricted. */ + // TODO: Use packBits(nc.getCapabilities()) to check more easily using bit masks. public static boolean inferRestrictedCapability(NetworkCapabilities nc) { - final long capabilities = packBits(nc.getCapabilities()); // Check if we have any capability that forces the network to be restricted. - final boolean forceRestrictedCapability = - (capabilities & FORCE_RESTRICTED_CAPABILITIES) != 0; + for (int capability : unpackBits(FORCE_RESTRICTED_CAPABILITIES)) { + if (nc.hasCapability(capability)) { + return true; + } + } // Verify there aren't any unrestricted capabilities. If there are we say // the whole thing is unrestricted unless it is forced to be restricted. - final boolean hasUnrestrictedCapabilities = - (capabilities & UNRESTRICTED_CAPABILITIES) != 0; + for (int capability : unpackBits(UNRESTRICTED_CAPABILITIES)) { + if (nc.hasCapability(capability)) { + return false; + } + } // Must have at least some restricted capabilities. - final boolean hasRestrictedCapabilities = (capabilities & RESTRICTED_CAPABILITIES) != 0; - - return forceRestrictedCapability - || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities); + for (int capability : unpackBits(RESTRICTED_CAPABILITIES)) { + if (nc.hasCapability(capability)) { + return true; + } + } + return false; } /** From 9b3d3cf60715739cacfc648d3306a7b969e4c0f5 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 31 Mar 2021 19:33:09 +0900 Subject: [PATCH 171/777] Add a filter function to CollectionUtils This is generally useful, and specifically useful in NetworkRanker Test: Used in NetworkRanker, ConnectivityServiceTest Change-Id: I896e7e5bcb2931ce43a5b88967bfd6fcd1de0ce2 --- .../net/module/util/CollectionUtils.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index 2223443d9a..f2afc7579f 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.util.SparseArray; +import java.util.ArrayList; import java.util.Collection; import java.util.Objects; import java.util.function.Predicate; @@ -148,4 +149,21 @@ public final class CollectionUtils { } return -1; } + + /** + * Returns a new collection of elements that match the passed predicate. + * @param source the elements to filter. + * @param test the predicate to test for. + * @return a new collection containing only the source elements that satisfy the predicate. + */ + @NonNull private static ArrayList filter(@NonNull final Collection source, + @NonNull final Predicate test) { + final ArrayList matches = new ArrayList<>(); + for (final T e : source) { + if (test.test(e)) { + matches.add(e); + } + } + return matches; + } } From 9d7cc739ba27e661fe36b579d2f6ed0a734f7f93 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Thu, 1 Apr 2021 10:02:22 +0800 Subject: [PATCH 172/777] Fix javadoc error Test: make doc-comment-check-docs Change-Id: If0451c2a32a9d7df1f5bb21cc688b9bdc3ce91fa --- .../net/module/util/NetworkCapabilitiesUtils.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 7bf8fc1254..4c7d675ef7 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -71,37 +71,37 @@ public final class NetworkCapabilitiesUtils { }; /** - * @See android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE + * See android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE * TODO: Use API constant when all downstream branches are S-based */ public static final int NET_CAPABILITY_OEM_PRIVATE = 26; /** - * @See android.net.NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL + * See android.net.NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL * TODO: Use API constant when all downstream branches are S-based */ public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; /** - * @See android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED + * See android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED * TODO: Use API constant when all downstream branches are S-based */ public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; /** - * @See android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE + * See android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE * TODO: Use API constant when all downstream branches are S-based */ public static final int NET_CAPABILITY_ENTERPRISE = 29; /** - * @See android.net.NetworkCapabilities.NET_CAPABILITY_VSIM + * See android.net.NetworkCapabilities.NET_CAPABILITY_VSIM * TODO: Use API constant when all downstream branches are S-based */ public static final int NET_CAPABILITY_VSIM = 30; /** - * @See android.net.NetworkCapabilities.NET_CAPABILITY_BIP + * See android.net.NetworkCapabilities.NET_CAPABILITY_BIP * TODO: Use API constant when all downstream branches are S-based */ public static final int NET_CAPABILITY_BIP = 31; From 5aacbafb889b6ad56343346f8c1ae69ed79c005d Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Wed, 31 Mar 2021 19:53:56 -0700 Subject: [PATCH 173/777] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/libs/net Added SPDX-license-identifier-Apache-2.0 to: common/testutils/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: If307a41f295d202c3cb8b733ed74af26d3358058 --- staticlibs/testutils/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index bea5e5a317..d4465dd717 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + java_library { name: "net-tests-utils", srcs: [ From 2202e614928ff83dc92bfa22f865573f4bf527fb Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 30 Mar 2021 07:56:39 +0000 Subject: [PATCH 174/777] Allow hidden connectivity APIs in net test utils The net test utils are used for unit tests exercising connectivity code, and need access to its hidden APIs. Bug: 182859030 Test: atest NetworkStaticLibTests Ignore-AOSP-First: needs manual cherry-picks Change-Id: I33273e5c1cc2731443f0fd745ce526473a704520 --- staticlibs/tests/unit/Android.bp | 1 + staticlibs/testutils/Android.bp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index 45a89b0b11..c9aad71035 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -10,6 +10,7 @@ android_library { name: "NetworkStaticLibTestsLib", srcs: ["src/**/*.java","src/**/*.kt"], min_sdk_version: "29", + defaults: ["framework-connectivity-test-defaults"], static_libs: [ "net-utils-framework-common", "androidx.test.rules", diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index d4465dd717..1a7b4375e0 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -22,7 +22,10 @@ java_library { "devicetests/**/*.java", "devicetests/**/*.kt", ], - defaults: ["lib_mockito_extended"], + defaults: [ + "framework-connectivity-test-defaults", + "lib_mockito_extended" + ], libs: [ "androidx.annotation_annotation", ], From c0d49afba21a894b65d4d93b84117c9a23ed507e Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 5 Apr 2021 16:33:26 +0900 Subject: [PATCH 175/777] Make a utility function public. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ...oops ? Test: m Change-Id: Ic8f4e7ef430a6fa49f8a477f9d48267b889b83ed --- .../framework/com/android/net/module/util/CollectionUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index f2afc7579f..4fce8f50e4 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -156,7 +156,7 @@ public final class CollectionUtils { * @param test the predicate to test for. * @return a new collection containing only the source elements that satisfy the predicate. */ - @NonNull private static ArrayList filter(@NonNull final Collection source, + @NonNull public static ArrayList filter(@NonNull final Collection source, @NonNull final Predicate test) { final ArrayList matches = new ArrayList<>(); for (final T e : source) { From 7cfcecc11b64737d85878d4fabfa03a6486bf690 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Tue, 6 Apr 2021 09:54:45 +0800 Subject: [PATCH 176/777] Define TRANSPORT_USB in NetworkCapabilitiesUtils temporarily The new API constant - TRANSPORT_USB didn't in mainline branch, so the user of TRANSPORT_USB will get build break when it is built in mainline branch. Define TRANSPORT_USB in NetworkCapabilitiesUtils temporarily is a workaround to fix this problem, and it should be removed once downstream branches are S-based. Bug: 184158327 Test: m Change-Id: I83560c75761e7008b457a66296364cb4ce24db50 Ignore-AOSP-First: This should be compiled with ag/14049950. --- .../net/module/util/NetworkCapabilitiesUtils.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 552ab21f13..122b4994a5 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -47,6 +47,12 @@ import com.android.internal.annotations.VisibleForTesting; * @hide */ public final class NetworkCapabilitiesUtils { + /** + * See android.net.NetworkCapabilities.TRANSPORT_USB + * TODO: Use API constant when all downstream branches are S-based + */ + public static final int TRANSPORT_USB = 8; + // Transports considered to classify networks in UI, in order of which transport should be // surfaced when there are multiple transports. Transports not in this list do not have // an ordering preference (in practice they will have a deterministic order based on the @@ -64,7 +70,8 @@ public final class NetworkCapabilitiesUtils { TRANSPORT_WIFI_AWARE, TRANSPORT_BLUETOOTH, TRANSPORT_WIFI, - TRANSPORT_ETHERNET + TRANSPORT_ETHERNET, + TRANSPORT_USB // Notably, TRANSPORT_TEST is not in this list as any network that has TRANSPORT_TEST and // one of the above transports should be counted as that transport, to keep tests as From 0d7d45cdefd90aaed1baff8d1fc1e7e7300beba9 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 9 Apr 2021 13:15:18 +0900 Subject: [PATCH 177/777] Add build ICMPv6 echo request packet helper function in Ipv6Utils. Bug: 168868607 Test: atest NetworkStaticLibTests Change-Id: Ibd3c8348996c8b55767956b03978a69593ec29e7 --- .../android/net/module/util/Ipv6Utils.java | 11 +++++++++++ .../net/module/util/Ipv6UtilsTest.java | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/Ipv6Utils.java b/staticlibs/device/com/android/net/module/util/Ipv6Utils.java index ee43ae9965..fe7c89bc05 100644 --- a/staticlibs/device/com/android/net/module/util/Ipv6Utils.java +++ b/staticlibs/device/com/android/net/module/util/Ipv6Utils.java @@ -20,6 +20,7 @@ import static android.system.OsConstants.IPPROTO_ICMPV6; import static com.android.net.module.util.IpUtils.icmpv6Checksum; import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT; @@ -148,4 +149,14 @@ public class Ipv6Utils { return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, (byte) ICMPV6_ROUTER_SOLICITATION /* type */, (byte) 0 /* code */, payload); } + + /** + * Build an ICMPv6 Echo Request packet from the required specified parameters. + */ + public static ByteBuffer buildEchoRequestPacket(final MacAddress srcMac, + final MacAddress dstMac, final Inet6Address srcIp, final Inet6Address dstIp) { + final ByteBuffer payload = ByteBuffer.allocate(4); // ID and Sequence number may be zero. + return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, + (byte) ICMPV6_ECHO_REQUEST_TYPE /* type */, (byte) 0 /* code */, payload); + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/Ipv6UtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/Ipv6UtilsTest.java index 37278b3d7a..03a1ec9f1a 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/Ipv6UtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/Ipv6UtilsTest.java @@ -112,6 +112,25 @@ public class Ipv6UtilsTest { assertPioEquals(pio, "fdcd:a17f:6502:1::/64", pioFlags, 86400, 86400); } + @Test + public void testBuildEchoRequestPacket() { + final ByteBuffer b = Ipv6Utils.buildEchoRequestPacket(MAC2, MAC1, LINK_LOCAL, ALL_NODES); + + EthernetHeader eth = Struct.parse(EthernetHeader.class, b); + assertEquals(MAC2, eth.srcMac); + assertEquals(MAC1, eth.dstMac); + + Ipv6Header ipv6 = Struct.parse(Ipv6Header.class, b); + assertEquals(255, ipv6.hopLimit); + assertEquals(OsConstants.IPPROTO_ICMPV6, ipv6.nextHeader); + assertEquals(LINK_LOCAL, ipv6.srcIp); + assertEquals(ALL_NODES, ipv6.dstIp); + + Icmpv6Header icmpv6 = Struct.parse(Icmpv6Header.class, b); + assertEquals(NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE, icmpv6.type); + assertEquals(0, icmpv6.code); + } + private void assertPioEquals(PrefixInformationOption pio, String prefix, byte flags, long valid, long preferred) { assertEquals(NetworkStackConstants.ICMPV6_ND_OPTION_PIO, pio.type); From 86fa055d4ada3f94c71bfb131c9932215047fa55 Mon Sep 17 00:00:00 2001 From: Pedro Loureiro Date: Thu, 25 Feb 2021 15:31:52 +0000 Subject: [PATCH 178/777] Add lint baseline to address NewApi errors We are enabling a new lint check where the min sdk != compile sdk. It has produced a lot of errors and adding the baseline file(s) allows us to continue work without introducing more problems. Bug: 150847901 Test: m lint-check Change-Id: I2c38dac481685470af8be115d867953325e75d94 --- staticlibs/tests/unit/lint-baseline.xml | 48 +++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 staticlibs/tests/unit/lint-baseline.xml diff --git a/staticlibs/tests/unit/lint-baseline.xml b/staticlibs/tests/unit/lint-baseline.xml new file mode 100644 index 0000000000..e3a6c1e184 --- /dev/null +++ b/staticlibs/tests/unit/lint-baseline.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + From d8bb125a4d3cf0da237e1a510fad3e9485f94d5d Mon Sep 17 00:00:00 2001 From: Pedro Loureiro Date: Thu, 25 Feb 2021 15:31:52 +0000 Subject: [PATCH 179/777] Add lint baseline to address NewApi errors We are enabling a new lint check where the min sdk != compile sdk. It has produced a lot of errors and adding the baseline file(s) allows us to continue work without introducing more problems. Bug: 150847901 Test: m lint-check Change-Id: I2c38dac481685470af8be115d867953325e75d94 Merged-In: I2c38dac481685470af8be115d867953325e75d94 --- staticlibs/lint-baseline.xml | 26 + staticlibs/tests/unit/lint-baseline.xml | 642 ++++++++++++++++++++++++ 2 files changed, 668 insertions(+) create mode 100644 staticlibs/lint-baseline.xml create mode 100644 staticlibs/tests/unit/lint-baseline.xml diff --git a/staticlibs/lint-baseline.xml b/staticlibs/lint-baseline.xml new file mode 100644 index 0000000000..4c54e9fc28 --- /dev/null +++ b/staticlibs/lint-baseline.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + diff --git a/staticlibs/tests/unit/lint-baseline.xml b/staticlibs/tests/unit/lint-baseline.xml new file mode 100644 index 0000000000..0990916f9f --- /dev/null +++ b/staticlibs/tests/unit/lint-baseline.xml @@ -0,0 +1,642 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From d641313cfcb54ce93b0c67c3094c99a1f7e85896 Mon Sep 17 00:00:00 2001 From: Pedro Loureiro Date: Thu, 25 Feb 2021 15:31:52 +0000 Subject: [PATCH 180/777] Add lint baseline to address NewApi errors We are enabling a new lint check where the min sdk != compile sdk. It has produced a lot of errors and adding the baseline file(s) allows us to continue work without introducing more problems. Bug: 150847901 Test: m lint-check Change-Id: I2c38dac481685470af8be115d867953325e75d94 Merged-In: I2c38dac481685470af8be115d867953325e75d94 --- .../client-libs/tests/unit/lint-baseline.xml | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 staticlibs/client-libs/tests/unit/lint-baseline.xml diff --git a/staticlibs/client-libs/tests/unit/lint-baseline.xml b/staticlibs/client-libs/tests/unit/lint-baseline.xml new file mode 100644 index 0000000000..713e3003d0 --- /dev/null +++ b/staticlibs/client-libs/tests/unit/lint-baseline.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + From 2522de86a3d0f8de869ada2f90992b6120ba13f4 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 19 Apr 2021 18:04:34 +0900 Subject: [PATCH 181/777] Support both R and S+ in NetworkFactory NetworkFactory needs to be backwards compatible as it is statically linked by the Wifi module, which needs to run on both R and S. To achieve this, maintain 2 separate implementations called NetworkFactoryImpl (S+) and NetworkFactoryLegacyImpl (R). NetworkFactory itself becomes a shim that delegates to one of these implementations depending on the device's SDK version. Ignore-AOSP-First: Merge in internal first to fix S-on-R test breakages. Bug: 183902758 Test: ClientModeImplTest OemWifiNetworkFactoryTest TelephonyNetworkFactoryTest UntrustedWifiNetworkFactoryTest WifiNetworkFactoryTest Change-Id: I6a08f39ad1633dd7c1582c362c97821e24ce6683 --- staticlibs/Android.bp | 19 +- .../device/android/net/NetworkFactory.java | 302 +++---------- .../android/net/NetworkFactoryImpl.java | 322 ++++++++++++++ .../android/net/NetworkFactoryLegacyImpl.java | 398 ++++++++++++++++++ .../android/net/NetworkFactoryShim.java | 71 ++++ staticlibs/jarjar-rules-shared.txt | 1 + 6 files changed, 854 insertions(+), 259 deletions(-) create mode 100644 staticlibs/device/android/net/NetworkFactoryImpl.java create mode 100644 staticlibs/device/android/net/NetworkFactoryLegacyImpl.java create mode 100644 staticlibs/device/android/net/NetworkFactoryShim.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index f52a4afed5..3dbc09f11a 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -34,9 +34,9 @@ package { java_library { name: "net-utils-device-common", srcs: [ - "device/**/*.java", + "device/com/android/net/module/util/**/*.java", // This library is used by system modules, for which the system health impact of Kotlin - // has not yet been evaluated. + // has not yet been evaluated. Annotations may need jarjar'ing. // "src_devicecommon/**/*.kt", ":framework-annotations", ], @@ -117,13 +117,15 @@ java_library { "//frameworks/libs/net/common/tests:__subpackages__", "//frameworks/libs/net/common/device", "//packages/modules/Wifi/framework/tests:__subpackages__", - ] + ], } - filegroup { name: "net-utils-services-common-srcs", srcs: [ "device/android/net/NetworkFactory.java", + "device/android/net/NetworkFactoryImpl.java", + "device/android/net/NetworkFactoryLegacyImpl.java", + "device/android/net/NetworkFactoryShim.java", ], visibility: [ "//frameworks/base/services/net", @@ -138,6 +140,9 @@ java_library { ], sdk_version: "system_current", min_sdk_version: "30", + static_libs: [ + "modules-utils-build_system", + ], visibility: [ "//frameworks/base/services/net", ], @@ -150,6 +155,9 @@ filegroup { srcs: [ // Any class here *must* have a corresponding jarjar rule in the telephony build rules. "device/android/net/NetworkFactory.java", + "device/android/net/NetworkFactoryImpl.java", + "device/android/net/NetworkFactoryLegacyImpl.java", + "device/android/net/NetworkFactoryShim.java", ], path: "device", visibility: [ @@ -178,6 +186,9 @@ filegroup { name: "net-utils-wifi-service-common-srcs", srcs: [ "device/android/net/NetworkFactory.java", + "device/android/net/NetworkFactoryImpl.java", + "device/android/net/NetworkFactoryLegacyImpl.java", + "device/android/net/NetworkFactoryShim.java", "framework/com/android/net/module/util/NetUtils.java", ], visibility: [ diff --git a/staticlibs/device/android/net/NetworkFactory.java b/staticlibs/device/android/net/NetworkFactory.java index 68db57b509..87f6dee6ec 100644 --- a/staticlibs/device/android/net/NetworkFactory.java +++ b/staticlibs/device/android/net/NetworkFactory.java @@ -16,11 +16,11 @@ package android.net; +import static com.android.modules.utils.build.SdkLevel.isAtLeastS; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; -import android.net.NetworkProvider.NetworkOfferCallback; -import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; @@ -29,9 +29,6 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.concurrent.Executor; /** * A NetworkFactory is an entity that creates NetworkAgent objects. @@ -46,108 +43,54 @@ import java.util.concurrent.Executor; * functions can be overridden. If the bearer needs more interaction, it can * override addNetworkRequest and removeNetworkRequest which will give it each * request that passes their current filters. + * + * This class is mostly a shim which delegates to one of two implementations depending + * on the SDK level of the device it's running on. + * * @hide **/ -public class NetworkFactory extends Handler { - private static final boolean DBG = true; - private static final boolean VDBG = false; +public class NetworkFactory { + static final boolean DBG = true; + static final boolean VDBG = false; - // A score that will win against everything, so that score filtering will let all requests - // through - // TODO : remove this and replace with an API to listen to all requests. - @NonNull - private static final NetworkScore INVINCIBLE_SCORE = - new NetworkScore.Builder().setLegacyInt(1000).build(); + final NetworkFactoryShim mImpl; - /** - * Pass a network request to the bearer. If the bearer believes it can - * satisfy the request it should connect to the network and create a - * NetworkAgent. Once the NetworkAgent is fully functional it will - * register itself with ConnectivityService using registerNetworkAgent. - * If the bearer cannot immediately satisfy the request (no network, - * user disabled the radio, lower-scored network) it should remember - * any NetworkRequests it may be able to satisfy in the future. It may - * disregard any that it will never be able to service, for example - * those requiring a different bearer. - * msg.obj = NetworkRequest - */ - // TODO : this and CANCEL_REQUEST are only used by telephony tests. Replace it in the tests - // and remove them and the associated code. - public static final int CMD_REQUEST_NETWORK = 1; - - /** - * Cancel a network request - * msg.obj = NetworkRequest - */ - public static final int CMD_CANCEL_REQUEST = 2; - - /** - * Internally used to set our best-guess score. - * msg.obj = new score - */ - private static final int CMD_SET_SCORE = 3; - - /** - * Internally used to set our current filter for coarse bandwidth changes with - * technology changes. - * msg.obj = new filter - */ - private static final int CMD_SET_FILTER = 4; - - /** - * Internally used to send the network offer associated with this factory. - * No arguments, will read from members - */ - private static final int CMD_OFFER_NETWORK = 5; - - /** - * Internally used to send the request to listen to all requests. - * No arguments, will read from members - */ - private static final int CMD_LISTEN_TO_ALL_REQUESTS = 6; - - private final Context mContext; private final String LOG_TAG; - private final Map mNetworkRequests = - new LinkedHashMap<>(); - - @NonNull private NetworkScore mScore = new NetworkScore.Builder().setLegacyInt(0).build(); - @NonNull private NetworkCapabilities mCapabilityFilter; - - private int mRefCount = 0; - private NetworkProvider mProvider = null; - - private final NetworkOfferCallback mRequestCallback = new NetworkOfferCallback() { - @Override - public void onNetworkNeeded(@NonNull final NetworkRequest request) { - handleAddRequest(request); - } - - @Override - public void onNetworkUnneeded(@NonNull final NetworkRequest request) { - handleRemoveRequest(request); - } - }; - @NonNull private final Executor mExecutor = command -> post(command); - // Ideally the filter argument would be non-null, but null has historically meant to see // no requests and telephony passes null. public NetworkFactory(Looper looper, Context context, String logTag, @Nullable final NetworkCapabilities filter) { - super(looper); LOG_TAG = logTag; - mContext = context; - if (null != filter) { - mCapabilityFilter = filter; + if (isAtLeastS()) { + mImpl = new NetworkFactoryImpl(this, looper, context, filter); } else { - mCapabilityFilter = new NetworkCapabilities.Builder().clearAll().build(); + mImpl = new NetworkFactoryLegacyImpl(this, looper, context, filter); } } + // TODO : these two constants and the method are only used by telephony tests. Replace it in + // the tests and remove them and the associated code. + public static final int CMD_REQUEST_NETWORK = 1; + public static final int CMD_CANCEL_REQUEST = 2; + /** Like Handler#obtainMessage */ + @VisibleForTesting + public Message obtainMessage(final int what, final int arg1, final int arg2, + final @Nullable Object obj) { + return mImpl.obtainMessage(what, arg1, arg2, obj); + } + + // Called by BluetoothNetworkFactory + public final Looper getLooper() { + return mImpl.getLooper(); + } + + // Refcount for simple mode requests + private int mRefCount = 0; + /* Registers this NetworkFactory with the system. May only be called once per factory. */ public void register() { - register(false); + mImpl.register(LOG_TAG); } /** @@ -156,152 +99,16 @@ public class NetworkFactory extends Handler { * May only be called once per factory. */ public void registerIgnoringScore() { - register(true); - } - - private void register(final boolean listenToAllRequests) { - if (mProvider != null) { - throw new IllegalStateException("A NetworkFactory must only be registered once"); - } - if (DBG) log("Registering NetworkFactory"); - - mProvider = new NetworkProvider(mContext, NetworkFactory.this.getLooper(), LOG_TAG) { - @Override - public void onNetworkRequested(@NonNull NetworkRequest request, int score, - int servingProviderId) { - handleAddRequest(request); - } - - @Override - public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { - handleRemoveRequest(request); - } - }; - - ((ConnectivityManager) mContext.getSystemService( - Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); - - // The mScore and mCapabilityFilter members can only be accessed on the handler thread. - // TODO : offer a separate API to listen to all requests instead - if (listenToAllRequests) { - sendMessage(obtainMessage(CMD_LISTEN_TO_ALL_REQUESTS)); - } else { - sendMessage(obtainMessage(CMD_OFFER_NETWORK)); - } - } - - private void handleOfferNetwork(@NonNull final NetworkScore score) { - mProvider.registerNetworkOffer(score, mCapabilityFilter, mExecutor, mRequestCallback); + mImpl.registerIgnoringScore(LOG_TAG); } /** Unregisters this NetworkFactory. After this call, the object can no longer be used. */ public void terminate() { - if (mProvider == null) { - throw new IllegalStateException("This NetworkFactory was never registered"); - } - if (DBG) log("Unregistering NetworkFactory"); - - ((ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) - .unregisterNetworkProvider(mProvider); - - // Remove all pending messages, since this object cannot be reused. Any message currently - // being processed will continue to run. - removeCallbacksAndMessages(null); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case CMD_REQUEST_NETWORK: { - handleAddRequest((NetworkRequest) msg.obj); - break; - } - case CMD_CANCEL_REQUEST: { - handleRemoveRequest((NetworkRequest) msg.obj); - break; - } - case CMD_SET_SCORE: { - handleSetScore((NetworkScore) msg.obj); - break; - } - case CMD_SET_FILTER: { - handleSetFilter((NetworkCapabilities) msg.obj); - break; - } - case CMD_OFFER_NETWORK: { - handleOfferNetwork(mScore); - break; - } - case CMD_LISTEN_TO_ALL_REQUESTS: { - handleOfferNetwork(INVINCIBLE_SCORE); - break; - } - } - } - - private static class NetworkRequestInfo { - @NonNull public final NetworkRequest request; - public boolean requested; // do we have a request outstanding, limited by score - - NetworkRequestInfo(@NonNull final NetworkRequest request) { - this.request = request; - this.requested = false; - } - - @Override - public String toString() { - return "{" + request + ", requested=" + requested + "}"; - } - } - - /** - * Add a NetworkRequest that the bearer may want to attempt to satisfy. - * @see #CMD_REQUEST_NETWORK - * - * @param request the request to handle. - */ - private void handleAddRequest(@NonNull final NetworkRequest request) { - NetworkRequestInfo n = mNetworkRequests.get(request); - if (n == null) { - if (DBG) log("got request " + request); - n = new NetworkRequestInfo(request); - mNetworkRequests.put(n.request, n); - } else { - if (VDBG) { - log("handle existing request " + request); - } - } - if (VDBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); - - if (acceptRequest(request)) { - n.requested = true; - needNetworkFor(request); - } - } - - private void handleRemoveRequest(NetworkRequest request) { - NetworkRequestInfo n = mNetworkRequests.get(request); - if (n != null) { - mNetworkRequests.remove(request); - if (n.requested) releaseNetworkFor(n.request); - } - } - - private void handleSetScore(@NonNull final NetworkScore score) { - if (mScore.equals(score)) return; - mScore = score; - reevaluateAllRequests(); - } - - private void handleSetFilter(@NonNull final NetworkCapabilities netCap) { - if (netCap.equals(mCapabilityFilter)) return; - mCapabilityFilter = netCap; - reevaluateAllRequests(); + mImpl.terminate(); } protected final void reevaluateAllRequests() { - if (mProvider == null) return; - mProvider.registerNetworkOffer(mScore, mCapabilityFilter, mExecutor, mRequestCallback); + mImpl.reevaluateAllRequests(); } /** @@ -326,6 +133,7 @@ public class NetworkFactory extends Handler { public boolean acceptRequest(@NonNull final NetworkRequest request) { return true; } + /** * Can be called by a factory to release a request as unfulfillable: the request will be * removed, and the caller will get a @@ -336,15 +144,7 @@ public class NetworkFactory extends Handler { * is able to fulfill this request! */ protected void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) { - post(() -> { - if (DBG) log("releaseRequestAsUnfulfillableByAnyFactory: " + r); - final NetworkProvider provider = mProvider; - if (provider == null) { - Log.e(LOG_TAG, "Ignoring attempt to release unregistered request as unfulfillable"); - return; - } - provider.declareNetworkRequestUnfulfillable(r); - }); + mImpl.releaseRequestAsUnfulfillableByAnyFactory(r); } // override to do simple mode (request independent) @@ -362,11 +162,11 @@ public class NetworkFactory extends Handler { /** * @deprecated this method was never part of the API (system or public) and is only added - * for migration of existing clients. It will be removed before S ships. + * for migration of existing clients. */ @Deprecated public void setScoreFilter(final int score) { - setScoreFilter(new NetworkScore.Builder().setLegacyInt(score).build()); + mImpl.setScoreFilter(score); } /** @@ -380,25 +180,24 @@ public class NetworkFactory extends Handler { * @param score the filter */ public void setScoreFilter(@NonNull final NetworkScore score) { - sendMessage(obtainMessage(CMD_SET_SCORE, score)); + mImpl.setScoreFilter(score); } public void setCapabilityFilter(NetworkCapabilities netCap) { - sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); + mImpl.setCapabilityFilter(netCap); } @VisibleForTesting protected int getRequestCount() { - return mNetworkRequests.size(); + return mImpl.getRequestCount(); } - /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ public int getSerialNumber() { - return mProvider.getProviderId(); + return mImpl.getSerialNumber(); } public NetworkProvider getProvider() { - return mProvider; + return mImpl.getProvider(); } protected void log(String s) { @@ -406,18 +205,11 @@ public class NetworkFactory extends Handler { } public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - writer.println(toString()); - for (NetworkRequestInfo n : mNetworkRequests.values()) { - writer.println(" " + n); - } + mImpl.dump(fd, writer, args); } @Override public String toString() { - return "{" + LOG_TAG + " - providerId=" - + mProvider.getProviderId() + ", ScoreFilter=" - + mScore + ", Filter=" + mCapabilityFilter + ", requests=" - + mNetworkRequests.size() + ", refCount=" + mRefCount - + "}"; + return "{" + LOG_TAG + " " + mImpl.toString() + "}"; } } diff --git a/staticlibs/device/android/net/NetworkFactoryImpl.java b/staticlibs/device/android/net/NetworkFactoryImpl.java new file mode 100644 index 0000000000..a3373512bb --- /dev/null +++ b/staticlibs/device/android/net/NetworkFactoryImpl.java @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2021 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 android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.net.NetworkProvider.NetworkOfferCallback; +import android.os.Looper; +import android.os.Message; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.Executor; + +/** + * A NetworkFactory is an entity that creates NetworkAgent objects. + * The bearers register with ConnectivityService using {@link #register} and + * their factory will start receiving scored NetworkRequests. NetworkRequests + * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by + * overridden function. All of these can be dynamic - changing NetworkCapabilities + * or score forces re-evaluation of all current requests. + * + * If any requests pass the filter some overrideable functions will be called. + * If the bearer only cares about very simple start/stopNetwork callbacks, those + * functions can be overridden. If the bearer needs more interaction, it can + * override addNetworkRequest and removeNetworkRequest which will give it each + * request that passes their current filters. + * @hide + **/ +// TODO(b/187083878): factor out common code between this and NetworkFactoryLegacyImpl +class NetworkFactoryImpl extends NetworkFactoryLegacyImpl { + private static final boolean DBG = NetworkFactory.DBG; + private static final boolean VDBG = NetworkFactory.VDBG; + + // A score that will win against everything, so that score filtering will let all requests + // through + // TODO : remove this and replace with an API to listen to all requests. + @NonNull + private static final NetworkScore INVINCIBLE_SCORE = + new NetworkScore.Builder().setLegacyInt(1000).build(); + + // TODO(b/187082970): Replace CMD_* with Handler.post(() -> { ... }) since all the CMDs do is to + // run the tasks asynchronously on the Handler thread. + + /** + * Pass a network request to the bearer. If the bearer believes it can + * satisfy the request it should connect to the network and create a + * NetworkAgent. Once the NetworkAgent is fully functional it will + * register itself with ConnectivityService using registerNetworkAgent. + * If the bearer cannot immediately satisfy the request (no network, + * user disabled the radio, lower-scored network) it should remember + * any NetworkRequests it may be able to satisfy in the future. It may + * disregard any that it will never be able to service, for example + * those requiring a different bearer. + * msg.obj = NetworkRequest + */ + // TODO : this and CANCEL_REQUEST are only used by telephony tests. Replace it in the tests + // and remove them and the associated code. + private static final int CMD_REQUEST_NETWORK = NetworkFactory.CMD_REQUEST_NETWORK; + + /** + * Cancel a network request + * msg.obj = NetworkRequest + */ + private static final int CMD_CANCEL_REQUEST = NetworkFactory.CMD_CANCEL_REQUEST; + + /** + * Internally used to set our best-guess score. + * msg.obj = new score + */ + private static final int CMD_SET_SCORE = 3; + + /** + * Internally used to set our current filter for coarse bandwidth changes with + * technology changes. + * msg.obj = new filter + */ + private static final int CMD_SET_FILTER = 4; + + /** + * Internally used to send the network offer associated with this factory. + * No arguments, will read from members + */ + private static final int CMD_OFFER_NETWORK = 5; + + /** + * Internally used to send the request to listen to all requests. + * No arguments, will read from members + */ + private static final int CMD_LISTEN_TO_ALL_REQUESTS = 6; + + private final Map mNetworkRequests = + new LinkedHashMap<>(); + + @NonNull private NetworkScore mScore = new NetworkScore.Builder().setLegacyInt(0).build(); + + private final NetworkOfferCallback mRequestCallback = new NetworkOfferCallback() { + @Override + public void onNetworkNeeded(@NonNull final NetworkRequest request) { + handleAddRequest(request); + } + + @Override + public void onNetworkUnneeded(@NonNull final NetworkRequest request) { + handleRemoveRequest(request); + } + }; + @NonNull private final Executor mExecutor = command -> post(command); + + + // Ideally the filter argument would be non-null, but null has historically meant to see + // no requests and telephony passes null. + NetworkFactoryImpl(NetworkFactory parent, Looper looper, Context context, + @Nullable final NetworkCapabilities filter) { + super(parent, looper, context, + null != filter ? filter : new NetworkCapabilities.Builder().clearAll().build()); + } + + /* Registers this NetworkFactory with the system. May only be called once per factory. */ + @Override public void register(final String logTag) { + register(logTag, false); + } + + /** + * Registers this NetworkFactory with the system ignoring the score filter. This will let + * the factory always see all network requests matching its capabilities filter. + * May only be called once per factory. + */ + @Override public void registerIgnoringScore(final String logTag) { + register(logTag, true); + } + + private void register(final String logTag, final boolean listenToAllRequests) { + if (mProvider != null) { + throw new IllegalStateException("A NetworkFactory must only be registered once"); + } + if (DBG) mParent.log("Registering NetworkFactory"); + + mProvider = new NetworkProvider(mContext, NetworkFactoryImpl.this.getLooper(), logTag) { + @Override + public void onNetworkRequested(@NonNull NetworkRequest request, int score, + int servingProviderId) { + handleAddRequest(request); + } + + @Override + public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { + handleRemoveRequest(request); + } + }; + + ((ConnectivityManager) mContext.getSystemService( + Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); + + // The mScore and mCapabilityFilter members can only be accessed on the handler thread. + // TODO : offer a separate API to listen to all requests instead + if (listenToAllRequests) { + sendMessage(obtainMessage(CMD_LISTEN_TO_ALL_REQUESTS)); + } else { + sendMessage(obtainMessage(CMD_OFFER_NETWORK)); + } + } + + private void handleOfferNetwork(@NonNull final NetworkScore score) { + mProvider.registerNetworkOffer(score, mCapabilityFilter, mExecutor, mRequestCallback); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case CMD_REQUEST_NETWORK: { + handleAddRequest((NetworkRequest) msg.obj); + break; + } + case CMD_CANCEL_REQUEST: { + handleRemoveRequest((NetworkRequest) msg.obj); + break; + } + case CMD_SET_SCORE: { + handleSetScore((NetworkScore) msg.obj); + break; + } + case CMD_SET_FILTER: { + handleSetFilter((NetworkCapabilities) msg.obj); + break; + } + case CMD_OFFER_NETWORK: { + handleOfferNetwork(mScore); + break; + } + case CMD_LISTEN_TO_ALL_REQUESTS: { + handleOfferNetwork(INVINCIBLE_SCORE); + break; + } + } + } + + private static class NetworkRequestInfo { + @NonNull public final NetworkRequest request; + public boolean requested; // do we have a request outstanding, limited by score + + NetworkRequestInfo(@NonNull final NetworkRequest request) { + this.request = request; + this.requested = false; + } + + @Override + public String toString() { + return "{" + request + ", requested=" + requested + "}"; + } + } + + /** + * Add a NetworkRequest that the bearer may want to attempt to satisfy. + * @see #CMD_REQUEST_NETWORK + * + * @param request the request to handle. + */ + private void handleAddRequest(@NonNull final NetworkRequest request) { + NetworkRequestInfo n = mNetworkRequests.get(request); + if (n == null) { + if (DBG) mParent.log("got request " + request); + n = new NetworkRequestInfo(request); + mNetworkRequests.put(n.request, n); + } else { + if (VDBG) mParent.log("handle existing request " + request); + } + if (VDBG) mParent.log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); + + if (mParent.acceptRequest(request)) { + n.requested = true; + mParent.needNetworkFor(request); + } + } + + private void handleRemoveRequest(NetworkRequest request) { + NetworkRequestInfo n = mNetworkRequests.get(request); + if (n != null) { + mNetworkRequests.remove(request); + if (n.requested) mParent.releaseNetworkFor(n.request); + } + } + + private void handleSetScore(@NonNull final NetworkScore score) { + if (mScore.equals(score)) return; + mScore = score; + mParent.reevaluateAllRequests(); + } + + private void handleSetFilter(@NonNull final NetworkCapabilities netCap) { + if (netCap.equals(mCapabilityFilter)) return; + mCapabilityFilter = netCap; + mParent.reevaluateAllRequests(); + } + + @Override public final void reevaluateAllRequests() { + if (mProvider == null) return; + mProvider.registerNetworkOffer(mScore, mCapabilityFilter, mExecutor, mRequestCallback); + } + + /** + * @deprecated this method was never part of the API (system or public) and is only added + * for migration of existing clients. + */ + @Deprecated + public void setScoreFilter(final int score) { + setScoreFilter(new NetworkScore.Builder().setLegacyInt(score).build()); + } + + /** + * Set a score filter for this factory. + * + * This should include the transports the factory knows its networks will have, and + * an optimistic view of the attributes it may have. This does not commit the factory + * to being able to bring up such a network ; it only lets it avoid hearing about + * requests that it has no chance of fulfilling. + * + * @param score the filter + */ + @Override public void setScoreFilter(@NonNull final NetworkScore score) { + sendMessage(obtainMessage(CMD_SET_SCORE, score)); + } + + @Override public void setCapabilityFilter(NetworkCapabilities netCap) { + sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); + } + + @Override public int getRequestCount() { + return mNetworkRequests.size(); + } + + @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + writer.println(toString()); + for (NetworkRequestInfo n : mNetworkRequests.values()) { + writer.println(" " + n); + } + } + + @Override public String toString() { + return "providerId=" + + mProvider.getProviderId() + ", ScoreFilter=" + + mScore + ", Filter=" + mCapabilityFilter + ", requests=" + + mNetworkRequests.size(); + } +} diff --git a/staticlibs/device/android/net/NetworkFactoryLegacyImpl.java b/staticlibs/device/android/net/NetworkFactoryLegacyImpl.java new file mode 100644 index 0000000000..6dd0adb0c9 --- /dev/null +++ b/staticlibs/device/android/net/NetworkFactoryLegacyImpl.java @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2021 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 android.annotation.NonNull; +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * A NetworkFactory is an entity that creates NetworkAgent objects. + * The bearers register with ConnectivityService using {@link #register} and + * their factory will start receiving scored NetworkRequests. NetworkRequests + * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by + * overridden function. All of these can be dynamic - changing NetworkCapabilities + * or score forces re-evaluation of all current requests. + * + * If any requests pass the filter some overrideable functions will be called. + * If the bearer only cares about very simple start/stopNetwork callbacks, those + * functions can be overridden. If the bearer needs more interaction, it can + * override addNetworkRequest and removeNetworkRequest which will give it each + * request that passes their current filters. + * @hide + **/ +// TODO(b/187083878): factor out common code between this and NetworkFactoryImpl +class NetworkFactoryLegacyImpl extends Handler + implements NetworkFactoryShim { + private static final boolean DBG = NetworkFactory.DBG; + private static final boolean VDBG = NetworkFactory.VDBG; + + // TODO(b/187082970): Replace CMD_* with Handler.post(() -> { ... }) since all the CMDs do is to + // run the tasks asynchronously on the Handler thread. + + /** + * Pass a network request to the bearer. If the bearer believes it can + * satisfy the request it should connect to the network and create a + * NetworkAgent. Once the NetworkAgent is fully functional it will + * register itself with ConnectivityService using registerNetworkAgent. + * If the bearer cannot immediately satisfy the request (no network, + * user disabled the radio, lower-scored network) it should remember + * any NetworkRequests it may be able to satisfy in the future. It may + * disregard any that it will never be able to service, for example + * those requiring a different bearer. + * msg.obj = NetworkRequest + * msg.arg1 = score - the score of the network currently satisfying this + * request. If this bearer knows in advance it cannot + * exceed this score it should not try to connect, holding the request + * for the future. + * Note that subsequent events may give a different (lower + * or higher) score for this request, transmitted to each + * NetworkFactory through additional CMD_REQUEST_NETWORK msgs + * with the same NetworkRequest but an updated score. + * Also, network conditions may change for this bearer + * allowing for a better score in the future. + * msg.arg2 = the ID of the NetworkProvider currently responsible for the + * NetworkAgent handling this request, or NetworkProvider.ID_NONE if none. + */ + public static final int CMD_REQUEST_NETWORK = 1; + + /** + * Cancel a network request + * msg.obj = NetworkRequest + */ + public static final int CMD_CANCEL_REQUEST = 2; + + /** + * Internally used to set our best-guess score. + * msg.arg1 = new score + */ + private static final int CMD_SET_SCORE = 3; + + /** + * Internally used to set our current filter for coarse bandwidth changes with + * technology changes. + * msg.obj = new filter + */ + private static final int CMD_SET_FILTER = 4; + + final Context mContext; + final NetworkFactory mParent; + + private final Map mNetworkRequests = + new LinkedHashMap<>(); + + private int mScore; + NetworkCapabilities mCapabilityFilter; + + NetworkProvider mProvider = null; + + NetworkFactoryLegacyImpl(NetworkFactory parent, Looper looper, Context context, + NetworkCapabilities filter) { + super(looper); + mParent = parent; + mContext = context; + mCapabilityFilter = filter; + } + + /* Registers this NetworkFactory with the system. May only be called once per factory. */ + @Override public void register(final String logTag) { + if (mProvider != null) { + throw new IllegalStateException("A NetworkFactory must only be registered once"); + } + if (DBG) mParent.log("Registering NetworkFactory"); + + mProvider = new NetworkProvider(mContext, NetworkFactoryLegacyImpl.this.getLooper(), + logTag) { + @Override + public void onNetworkRequested(@NonNull NetworkRequest request, int score, + int servingProviderId) { + handleAddRequest(request, score, servingProviderId); + } + + @Override + public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { + handleRemoveRequest(request); + } + }; + + ((ConnectivityManager) mContext.getSystemService( + Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); + } + + /** Unregisters this NetworkFactory. After this call, the object can no longer be used. */ + @Override public void terminate() { + if (mProvider == null) { + throw new IllegalStateException("This NetworkFactory was never registered"); + } + if (DBG) mParent.log("Unregistering NetworkFactory"); + + ((ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) + .unregisterNetworkProvider(mProvider); + + // Remove all pending messages, since this object cannot be reused. Any message currently + // being processed will continue to run. + removeCallbacksAndMessages(null); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case CMD_REQUEST_NETWORK: { + handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2); + break; + } + case CMD_CANCEL_REQUEST: { + handleRemoveRequest((NetworkRequest) msg.obj); + break; + } + case CMD_SET_SCORE: { + handleSetScore(msg.arg1); + break; + } + case CMD_SET_FILTER: { + handleSetFilter((NetworkCapabilities) msg.obj); + break; + } + } + } + + private static class NetworkRequestInfo { + public final NetworkRequest request; + public int score; + public boolean requested; // do we have a request outstanding, limited by score + public int providerId; + + NetworkRequestInfo(NetworkRequest request, int score, int providerId) { + this.request = request; + this.score = score; + this.requested = false; + this.providerId = providerId; + } + + @Override + public String toString() { + return "{" + request + ", score=" + score + ", requested=" + requested + "}"; + } + } + + /** + * Add a NetworkRequest that the bearer may want to attempt to satisfy. + * @see #CMD_REQUEST_NETWORK + * + * @param request the request to handle. + * @param score the score of the NetworkAgent currently satisfying this request. + * @param servingProviderId the ID of the NetworkProvider that created the NetworkAgent + * currently satisfying this request. + */ + @VisibleForTesting + protected void handleAddRequest(NetworkRequest request, int score, int servingProviderId) { + NetworkRequestInfo n = mNetworkRequests.get(request); + if (n == null) { + if (DBG) { + mParent.log("got request " + request + " with score " + score + + " and providerId " + servingProviderId); + } + n = new NetworkRequestInfo(request, score, servingProviderId); + mNetworkRequests.put(n.request, n); + } else { + if (VDBG) { + mParent.log("new score " + score + " for existing request " + request + + " and providerId " + servingProviderId); + } + n.score = score; + n.providerId = servingProviderId; + } + if (VDBG) mParent.log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); + + evalRequest(n); + } + + private void handleRemoveRequest(NetworkRequest request) { + NetworkRequestInfo n = mNetworkRequests.get(request); + if (n != null) { + mNetworkRequests.remove(request); + if (n.requested) mParent.releaseNetworkFor(n.request); + } + } + + private void handleSetScore(int score) { + mScore = score; + evalRequests(); + } + + private void handleSetFilter(NetworkCapabilities netCap) { + mCapabilityFilter = netCap; + evalRequests(); + } + + /** + * Overridable function to provide complex filtering. + * Called for every request every time a new NetworkRequest is seen + * and whenever the filterScore or filterNetworkCapabilities change. + * + * acceptRequest can be overridden to provide complex filter behavior + * for the incoming requests + * + * For output, this class will call {@link NetworkFactory#needNetworkFor} and + * {@link NetworkFactory#releaseNetworkFor} for every request that passes the filters. + * If you don't need to see every request, you can leave the base + * implementations of those two functions and instead override + * {@link NetworkFactory#startNetwork} and {@link NetworkFactory#stopNetwork}. + * + * If you want to see every score fluctuation on every request, set + * your score filter to a very high number and watch {@link NetworkFactory#needNetworkFor}. + * + * @return {@code true} to accept the request. + */ + public boolean acceptRequest(NetworkRequest request) { + return mParent.acceptRequest(request); + } + + private void evalRequest(NetworkRequestInfo n) { + if (VDBG) { + mParent.log("evalRequest"); + mParent.log(" n.requests = " + n.requested); + mParent.log(" n.score = " + n.score); + mParent.log(" mScore = " + mScore); + mParent.log(" request.providerId = " + n.providerId); + mParent.log(" mProvider.id = " + mProvider.getProviderId()); + } + if (shouldNeedNetworkFor(n)) { + if (VDBG) mParent.log(" needNetworkFor"); + mParent.needNetworkFor(n.request); + n.requested = true; + } else if (shouldReleaseNetworkFor(n)) { + if (VDBG) mParent.log(" releaseNetworkFor"); + mParent.releaseNetworkFor(n.request); + n.requested = false; + } else { + if (VDBG) mParent.log(" done"); + } + } + + private boolean shouldNeedNetworkFor(NetworkRequestInfo n) { + // If this request is already tracked, it doesn't qualify for need + return !n.requested + // If the score of this request is higher or equal to that of this factory and some + // other factory is responsible for it, then this factory should not track the request + // because it has no hope of satisfying it. + && (n.score < mScore || n.providerId == mProvider.getProviderId()) + // If this factory can't satisfy the capability needs of this request, then it + // should not be tracked. + && n.request.canBeSatisfiedBy(mCapabilityFilter) + // Finally if the concrete implementation of the factory rejects the request, then + // don't track it. + && acceptRequest(n.request); + } + + private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) { + // Don't release a request that's not tracked. + return n.requested + // The request should be released if it can't be satisfied by this factory. That + // means either of the following conditions are met : + // - Its score is too high to be satisfied by this factory and it's not already + // assigned to the factory + // - This factory can't satisfy the capability needs of the request + // - The concrete implementation of the factory rejects the request + && ((n.score > mScore && n.providerId != mProvider.getProviderId()) + || !n.request.canBeSatisfiedBy(mCapabilityFilter) + || !acceptRequest(n.request)); + } + + private void evalRequests() { + for (NetworkRequestInfo n : mNetworkRequests.values()) { + evalRequest(n); + } + } + + /** + * Post a command, on this NetworkFactory Handler, to re-evaluate all + * outstanding requests. Can be called from a factory implementation. + */ + @Override public void reevaluateAllRequests() { + post(this::evalRequests); + } + + /** + * Can be called by a factory to release a request as unfulfillable: the request will be + * removed, and the caller will get a + * {@link ConnectivityManager.NetworkCallback#onUnavailable()} callback after this function + * returns. + * + * Note: this should only be called by factory which KNOWS that it is the ONLY factory which + * is able to fulfill this request! + */ + @Override public void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) { + post(() -> { + if (DBG) mParent.log("releaseRequestAsUnfulfillableByAnyFactory: " + r); + final NetworkProvider provider = mProvider; + if (provider == null) { + mParent.log("Ignoring attempt to release unregistered request as unfulfillable"); + return; + } + provider.declareNetworkRequestUnfulfillable(r); + }); + } + + @Override public void setScoreFilter(int score) { + sendMessage(obtainMessage(CMD_SET_SCORE, score, 0)); + } + + @Override public void setScoreFilter(@NonNull final NetworkScore score) { + setScoreFilter(score.getLegacyInt()); + } + + @Override public void setCapabilityFilter(NetworkCapabilities netCap) { + sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); + } + + @Override public int getRequestCount() { + return mNetworkRequests.size(); + } + + /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ + @Override public int getSerialNumber() { + return mProvider.getProviderId(); + } + + @Override public NetworkProvider getProvider() { + return mProvider; + } + + @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + writer.println(toString()); + for (NetworkRequestInfo n : mNetworkRequests.values()) { + writer.println(" " + n); + } + } + + @Override public String toString() { + return "providerId=" + + mProvider.getProviderId() + ", ScoreFilter=" + + mScore + ", Filter=" + mCapabilityFilter + ", requests=" + + mNetworkRequests.size(); + } +} diff --git a/staticlibs/device/android/net/NetworkFactoryShim.java b/staticlibs/device/android/net/NetworkFactoryShim.java new file mode 100644 index 0000000000..dfbb5ec104 --- /dev/null +++ b/staticlibs/device/android/net/NetworkFactoryShim.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2021 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 android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Looper; +import android.os.Message; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +/** + * Extract an interface for multiple implementation of {@link NetworkFactory}, depending on the SDK + * version. + * + * Known implementations: + * - {@link NetworkFactoryImpl}: For Android S+ + * - {@link NetworkFactoryLegacyImpl}: For Android R- + * + * @hide + */ +interface NetworkFactoryShim { + void register(String logTag); + + default void registerIgnoringScore(String logTag) { + throw new UnsupportedOperationException(); + } + + void terminate(); + + void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r); + + void reevaluateAllRequests(); + + void setScoreFilter(int score); + + void setScoreFilter(@NonNull NetworkScore score); + + void setCapabilityFilter(NetworkCapabilities netCap); + + int getRequestCount(); + + int getSerialNumber(); + + NetworkProvider getProvider(); + + void dump(FileDescriptor fd, PrintWriter writer, String[] args); + + // All impls inherit Handler + @VisibleForTesting + Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj); + + Looper getLooper(); +} diff --git a/staticlibs/jarjar-rules-shared.txt b/staticlibs/jarjar-rules-shared.txt index a7fda7c0ac..e26999dd0f 100644 --- a/staticlibs/jarjar-rules-shared.txt +++ b/staticlibs/jarjar-rules-shared.txt @@ -1,2 +1,3 @@ rule android.annotation.** com.android.net.module.annotation.@1 rule com.android.internal.annotations.** com.android.net.module.annotation.@1 +rule com.android.modules.utils.build.** com.android.net.module.util.build.$1 From 88dfe23949c7b224b92beb6b45ee02ef5ed8fbb6 Mon Sep 17 00:00:00 2001 From: Orion Hodson Date: Wed, 12 May 2021 09:40:08 +0100 Subject: [PATCH 182/777] Move to renamed NDK symbol AFileDescriptor_getFd Bug: 185256332 Test: TH Change-Id: I77f7551a97d015fe5cc54c053020504f5fb93ab7 --- staticlibs/native/netjniutils/netjniutils.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/staticlibs/native/netjniutils/netjniutils.cpp b/staticlibs/native/netjniutils/netjniutils.cpp index 8ed72b087c..210c6c3a29 100644 --- a/staticlibs/native/netjniutils/netjniutils.cpp +++ b/staticlibs/native/netjniutils/netjniutils.cpp @@ -74,19 +74,19 @@ int GetNativeFileDescriptorWithNdk(JNIEnv* env, jobject javaFd) { // Since Android S, there is an NDK API to get a file descriptor present in libnativehelper.so. // libnativehelper is loaded into all processes by the zygote since the zygote uses it // to load the Android Runtime and is also a public library (because of the NDK API). - typedef int (*ndkGetFD_t)(JNIEnv*, jobject); - static const ndkGetFD_t ndkGetFD = []() -> ndkGetFD_t { + typedef int (*ndkGetFd_t)(JNIEnv*, jobject); + static const ndkGetFd_t ndkGetFd = []() -> ndkGetFd_t { void* handle = dlopen("libnativehelper.so", RTLD_NOLOAD | RTLD_NODELETE); - auto ndkGetFD = reinterpret_cast(dlsym(handle, "AFileDescriptor_getFD")); - if (ndkGetFD == nullptr) { + auto ndkGetFd = reinterpret_cast(dlsym(handle, "AFileDescriptor_getFd")); + if (ndkGetFd == nullptr) { __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, - "Failed to dlsym(AFileDescriptor_getFD): %s", dlerror()); + "Failed to dlsym(AFileDescriptor_getFd): %s", dlerror()); dlclose(handle); } - return ndkGetFD; + return ndkGetFd; }(); - return javaFd != nullptr ? ndkGetFD(env, javaFd) : -1; + return javaFd != nullptr ? ndkGetFd(env, javaFd) : -1; } } // namespace From 059eb44e9f91a17e051a1ef9c75f727b54d7b39e Mon Sep 17 00:00:00 2001 From: Orion Hodson Date: Wed, 12 May 2021 10:01:13 +0100 Subject: [PATCH 183/777] Move to renamed NDK symbol AFileDescriptor_getFd Ignore-AOSP-First: automerger issue from aosp http://b/187941100#comment11 Bug: 185256332 Test: TH Change-Id: I77f7551a97d015fe5cc54c053020504f5fb93ab7 --- staticlibs/native/netjniutils/netjniutils.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/staticlibs/native/netjniutils/netjniutils.cpp b/staticlibs/native/netjniutils/netjniutils.cpp index 8ed72b087c..210c6c3a29 100644 --- a/staticlibs/native/netjniutils/netjniutils.cpp +++ b/staticlibs/native/netjniutils/netjniutils.cpp @@ -74,19 +74,19 @@ int GetNativeFileDescriptorWithNdk(JNIEnv* env, jobject javaFd) { // Since Android S, there is an NDK API to get a file descriptor present in libnativehelper.so. // libnativehelper is loaded into all processes by the zygote since the zygote uses it // to load the Android Runtime and is also a public library (because of the NDK API). - typedef int (*ndkGetFD_t)(JNIEnv*, jobject); - static const ndkGetFD_t ndkGetFD = []() -> ndkGetFD_t { + typedef int (*ndkGetFd_t)(JNIEnv*, jobject); + static const ndkGetFd_t ndkGetFd = []() -> ndkGetFd_t { void* handle = dlopen("libnativehelper.so", RTLD_NOLOAD | RTLD_NODELETE); - auto ndkGetFD = reinterpret_cast(dlsym(handle, "AFileDescriptor_getFD")); - if (ndkGetFD == nullptr) { + auto ndkGetFd = reinterpret_cast(dlsym(handle, "AFileDescriptor_getFd")); + if (ndkGetFd == nullptr) { __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, - "Failed to dlsym(AFileDescriptor_getFD): %s", dlerror()); + "Failed to dlsym(AFileDescriptor_getFd): %s", dlerror()); dlclose(handle); } - return ndkGetFD; + return ndkGetFd; }(); - return javaFd != nullptr ? ndkGetFD(env, javaFd) : -1; + return javaFd != nullptr ? ndkGetFd(env, javaFd) : -1; } } // namespace From ae563e11ffd6b5f7de5c1146874db0f6eda4bdaf Mon Sep 17 00:00:00 2001 From: Orion Hodson Date: Wed, 12 May 2021 10:01:13 +0100 Subject: [PATCH 184/777] Move to renamed NDK symbol AFileDescriptor_getFd Ignore-AOSP-First: automerger issue from aosp http://b/187941100#comment11 Bug: 185256332 Test: TH (cherry picked from commit 51af2868d2e673ccb6a2c82270ba50e72ec92fb5) Change-Id: I77f7551a97d015fe5cc54c053020504f5fb93ab7 Merged-In: I77f7551a97d015fe5cc54c053020504f5fb93ab7 --- staticlibs/native/netjniutils/netjniutils.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/staticlibs/native/netjniutils/netjniutils.cpp b/staticlibs/native/netjniutils/netjniutils.cpp index 8ed72b087c..210c6c3a29 100644 --- a/staticlibs/native/netjniutils/netjniutils.cpp +++ b/staticlibs/native/netjniutils/netjniutils.cpp @@ -74,19 +74,19 @@ int GetNativeFileDescriptorWithNdk(JNIEnv* env, jobject javaFd) { // Since Android S, there is an NDK API to get a file descriptor present in libnativehelper.so. // libnativehelper is loaded into all processes by the zygote since the zygote uses it // to load the Android Runtime and is also a public library (because of the NDK API). - typedef int (*ndkGetFD_t)(JNIEnv*, jobject); - static const ndkGetFD_t ndkGetFD = []() -> ndkGetFD_t { + typedef int (*ndkGetFd_t)(JNIEnv*, jobject); + static const ndkGetFd_t ndkGetFd = []() -> ndkGetFd_t { void* handle = dlopen("libnativehelper.so", RTLD_NOLOAD | RTLD_NODELETE); - auto ndkGetFD = reinterpret_cast(dlsym(handle, "AFileDescriptor_getFD")); - if (ndkGetFD == nullptr) { + auto ndkGetFd = reinterpret_cast(dlsym(handle, "AFileDescriptor_getFd")); + if (ndkGetFd == nullptr) { __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, - "Failed to dlsym(AFileDescriptor_getFD): %s", dlerror()); + "Failed to dlsym(AFileDescriptor_getFd): %s", dlerror()); dlclose(handle); } - return ndkGetFD; + return ndkGetFd; }(); - return javaFd != nullptr ? ndkGetFD(env, javaFd) : -1; + return javaFd != nullptr ? ndkGetFd(env, javaFd) : -1; } } // namespace From 4a73a9f08fca3f63770912314744ce0ef041028c Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 4 Mar 2021 21:48:17 +0800 Subject: [PATCH 185/777] [FUI26.1] Generalize assertSameElements Test: atest NetworkStaticLibTests Bug: 174123988 Change-Id: I72a33a3c6ba849666e9f892745be3175aeb34b0e --- .../hostdevice/com/android/testutils/MiscAsserts.kt | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt b/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt index a8c6b3c734..efd9402d8f 100644 --- a/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt +++ b/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt @@ -112,11 +112,10 @@ fun assertFieldCountEquals(count: Int, clazz: Class) { }.size) } -fun assertSameElements(expected: List, actual: List) { - val expectedSet: HashSet = HashSet(expected) - assertEquals(expectedSet.size.toLong(), expected.size.toLong(), - "expected list contains duplicates") - val actualSet: HashSet = HashSet(actual) - assertEquals(actualSet.size.toLong(), actual.size.toLong(), "actual list contains duplicates") +fun assertSameElements(expected: List, actual: List) { + val expectedSet: HashSet = HashSet(expected) + assertEquals(expectedSet.size, expected.size, "expected list contains duplicates") + val actualSet: HashSet = HashSet(actual) + assertEquals(actualSet.size, actual.size, "actual list contains duplicates") assertEquals(expectedSet, actualSet) -} +} \ No newline at end of file From 3468c1fc8b81f661d7db30e3ec5918d8d0b0a2cc Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 13 May 2021 10:29:52 +0800 Subject: [PATCH 186/777] Replace clearAll with withoutDefaultCapabilities Update the method to clearer naming as the feedback from API review. Bug: 184735772 Test: m Change-Id: Id0b1df83926352969049a50b3f1af111a4ac603c Ignore-AOSP-First: Parts of the topic are only available in internal --- staticlibs/device/android/net/NetworkFactoryImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/staticlibs/device/android/net/NetworkFactoryImpl.java b/staticlibs/device/android/net/NetworkFactoryImpl.java index a3373512bb..439ea1421a 100644 --- a/staticlibs/device/android/net/NetworkFactoryImpl.java +++ b/staticlibs/device/android/net/NetworkFactoryImpl.java @@ -130,7 +130,8 @@ class NetworkFactoryImpl extends NetworkFactoryLegacyImpl { NetworkFactoryImpl(NetworkFactory parent, Looper looper, Context context, @Nullable final NetworkCapabilities filter) { super(parent, looper, context, - null != filter ? filter : new NetworkCapabilities.Builder().clearAll().build()); + null != filter ? filter : + NetworkCapabilities.Builder.withoutDefaultCapabilities().build()); } /* Registers this NetworkFactory with the system. May only be called once per factory. */ From b4bb7d11d958f61ca19e74935927e78e48beff41 Mon Sep 17 00:00:00 2001 From: Orion Hodson Date: Wed, 12 May 2021 10:01:13 +0100 Subject: [PATCH 187/777] Move to renamed NDK symbol AFileDescriptor_getFd Ignore-AOSP-First: automerger issue from aosp http://b/187941100#comment11 Bug: 185256332 Test: TH (cherry picked from commit 51af2868d2e673ccb6a2c82270ba50e72ec92fb5) Change-Id: I77f7551a97d015fe5cc54c053020504f5fb93ab7 Merged-In: I77f7551a97d015fe5cc54c053020504f5fb93ab7 --- staticlibs/native/netjniutils/netjniutils.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/staticlibs/native/netjniutils/netjniutils.cpp b/staticlibs/native/netjniutils/netjniutils.cpp index 8ed72b087c..210c6c3a29 100644 --- a/staticlibs/native/netjniutils/netjniutils.cpp +++ b/staticlibs/native/netjniutils/netjniutils.cpp @@ -74,19 +74,19 @@ int GetNativeFileDescriptorWithNdk(JNIEnv* env, jobject javaFd) { // Since Android S, there is an NDK API to get a file descriptor present in libnativehelper.so. // libnativehelper is loaded into all processes by the zygote since the zygote uses it // to load the Android Runtime and is also a public library (because of the NDK API). - typedef int (*ndkGetFD_t)(JNIEnv*, jobject); - static const ndkGetFD_t ndkGetFD = []() -> ndkGetFD_t { + typedef int (*ndkGetFd_t)(JNIEnv*, jobject); + static const ndkGetFd_t ndkGetFd = []() -> ndkGetFd_t { void* handle = dlopen("libnativehelper.so", RTLD_NOLOAD | RTLD_NODELETE); - auto ndkGetFD = reinterpret_cast(dlsym(handle, "AFileDescriptor_getFD")); - if (ndkGetFD == nullptr) { + auto ndkGetFd = reinterpret_cast(dlsym(handle, "AFileDescriptor_getFd")); + if (ndkGetFd == nullptr) { __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, - "Failed to dlsym(AFileDescriptor_getFD): %s", dlerror()); + "Failed to dlsym(AFileDescriptor_getFd): %s", dlerror()); dlclose(handle); } - return ndkGetFD; + return ndkGetFd; }(); - return javaFd != nullptr ? ndkGetFD(env, javaFd) : -1; + return javaFd != nullptr ? ndkGetFd(env, javaFd) : -1; } } // namespace From c4719cd17a8495b670aef9d067c397ce84c34bfc Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 12 May 2021 23:09:07 +0800 Subject: [PATCH 188/777] Add isFeatureEnabled by checking with apex module version A variable of #isFeatureEnabled which check apex module version instead of apk version. Bug: 187946226 Test: NetworkStaticLibTests Change-Id: I4cfc0a68f6ecb7eb9e127b3445b261e0108f6481 --- .../net/module/util/DeviceConfigUtils.java | 83 ++++++++++++++++++- .../module/util/DeviceConfigUtilsTest.java | 52 +++++++++++- 2 files changed, 128 insertions(+), 7 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index 5d03dfd279..77b7835b9e 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -17,6 +17,7 @@ package com.android.net.module.util; import android.content.Context; +import android.content.pm.ModuleInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.provider.DeviceConfig; @@ -38,6 +39,7 @@ public final class DeviceConfigUtils { @VisibleForTesting public static void resetPackageVersionCacheForTest() { sPackageVersion = -1; + sModuleVersion = -1; } private static volatile long sPackageVersion = -1; @@ -155,17 +157,90 @@ public final class DeviceConfigUtils { public static boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, @NonNull String name, boolean defaultEnabled) { try { - final int propertyVersion = getDeviceConfigPropertyInt(namespace, name, - 0 /* default value */); final long packageVersion = getPackageVersion(context); - return (propertyVersion == 0 && defaultEnabled) - || (propertyVersion != 0 && packageVersion >= (long) propertyVersion); + return isFeatureEnabled(context, packageVersion, namespace, name, defaultEnabled); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Could not find the package name", e); return false; } } + /** + * Check whether or not one specific experimental feature for a particular namespace from + * {@link DeviceConfig} is enabled by comparing module package version + * with current version of property. If this property version is valid, the corresponding + * experimental feature would be enabled, otherwise disabled. + * + * This is useful to ensure that if a module install is rolled back, flags are not left fully + * rolled out on a version where they have not been well tested. + * @param context The global context information about an app environment. + * @param namespace The namespace containing the property to look up. + * @param name The name of the property to look up. + * @param moduleName The mainline module name which is released as apex. + * @param defaultEnabled The value to return if the property does not exist or its value is + * null. + * @return true if this feature is enabled, or false if disabled. + */ + public static boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, + @NonNull String name, @NonNull String moduleName, boolean defaultEnabled) { + try { + final long packageVersion = getModuleVersion(context, moduleName); + return isFeatureEnabled(context, packageVersion, namespace, name, defaultEnabled); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Could not find the module name", e); + return false; + } + } + + private static boolean maybeUseFixedPackageVersion(@NonNull Context context) { + final String packageName = context.getPackageName(); + if (packageName == null) return false; + + return packageName.equals("com.android.networkstack.tethering") + || packageName.equals("com.android.networkstack.tethering.inprocess"); + } + + private static boolean isFeatureEnabled(@NonNull Context context, long packageVersion, + @NonNull String namespace, String name, boolean defaultEnabled) + throws PackageManager.NameNotFoundException { + final int propertyVersion = getDeviceConfigPropertyInt(namespace, name, + 0 /* default value */); + return (propertyVersion == 0 && defaultEnabled) + || (propertyVersion != 0 && packageVersion >= (long) propertyVersion); + } + + private static volatile long sModuleVersion = -1; + @VisibleForTesting public static long FIXED_PACKAGE_VERSION = 10; + private static long getModuleVersion(@NonNull Context context, @NonNull String moduleName) + throws PackageManager.NameNotFoundException { + if (sModuleVersion >= 0) return sModuleVersion; + + final PackageManager packageManager = context.getPackageManager(); + ModuleInfo module; + try { + module = packageManager.getModuleInfo( + moduleName, PackageManager.MODULE_APEX_NAME); + } catch (PackageManager.NameNotFoundException e) { + // The error may happen if mainline module meta data is not installed e.g. there are + // no meta data configuration in AOSP build. To be able to enable a feature in AOSP + // by setting a flag via ADB for example. set a small non-zero fixed number for + // comparing. + if (maybeUseFixedPackageVersion(context)) { + sModuleVersion = FIXED_PACKAGE_VERSION; + return FIXED_PACKAGE_VERSION; + } else { + throw e; + } + } + String modulePackageName = module.getPackageName(); + if (modulePackageName == null) throw new PackageManager.NameNotFoundException(moduleName); + final long version = packageManager.getPackageInfo(modulePackageName, + PackageManager.MATCH_APEX).getLongVersionCode(); + sModuleVersion = version; + + return version; + } + /** * Gets boolean config from resources. */ diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java index 57316b2f42..c65f79340a 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -18,6 +18,7 @@ package com.android.net.module.util; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; +import static com.android.net.module.util.DeviceConfigUtils.FIXED_PACKAGE_VERSION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -30,6 +31,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; +import android.content.pm.ModuleInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -64,10 +66,13 @@ public class DeviceConfigUtilsTest { private static final int TEST_MIN_FLAG_VALUE = 100; private static final long TEST_PACKAGE_VERSION = 290000000; private static final String TEST_PACKAGE_NAME = "test.package.name"; + private static final String TETHERING_AOSP_PACKAGE_NAME = "com.android.networkstack.tethering"; + private static final String TEST_APEX_NAME = "test.apex.name"; private MockitoSession mSession; @Mock private Context mContext; @Mock private PackageManager mPm; + @Mock private ModuleInfo mMi; @Mock private PackageInfo mPi; @Mock private Resources mResources; @@ -81,6 +86,8 @@ public class DeviceConfigUtilsTest { doReturn(mPm).when(mContext).getPackageManager(); doReturn(TEST_PACKAGE_NAME).when(mContext).getPackageName(); + doReturn(mMi).when(mPm).getModuleInfo(eq(TEST_APEX_NAME), anyInt()); + doReturn(TEST_PACKAGE_NAME).when(mMi).getPackageName(); doReturn(pi).when(mPm).getPackageInfo(anyString(), anyInt()); doReturn(mResources).when(mContext).getResources(); } @@ -193,23 +200,54 @@ public class DeviceConfigUtilsTest { eq(TEST_EXPERIMENT_FLAG))); assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); } @Test - public void testFeatureIsNotEnabled() { + public void testFeatureDefaultEnabled() { doReturn(null).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); + assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, true /* defaultEnabled */)); } @Test public void testFeatureIsEnabledWithException() throws Exception { - doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), - eq(TEST_EXPERIMENT_FLAG))); doThrow(NameNotFoundException.class).when(mPm).getPackageInfo(anyString(), anyInt()); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); + assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + doThrow(NameNotFoundException.class).when(mPm).getModuleInfo(anyString(), anyInt()); + assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + } + + + @Test + public void testFeatureIsEnabledUsingFixedVersion() throws Exception { + doReturn(TETHERING_AOSP_PACKAGE_NAME).when(mContext).getPackageName(); + doThrow(NameNotFoundException.class).when(mPm).getModuleInfo(anyString(), anyInt()); + + doReturn(Long.toString(FIXED_PACKAGE_VERSION)).when(() -> DeviceConfig.getProperty( + eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + + doReturn(Long.toString(FIXED_PACKAGE_VERSION + 1)).when(() -> DeviceConfig.getProperty( + eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); + assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + + doReturn(Long.toString(FIXED_PACKAGE_VERSION - 1)).when(() -> DeviceConfig.getProperty( + eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); } @Test @@ -225,6 +263,14 @@ public class DeviceConfigUtilsTest { verify(mContext, times(1)).getPackageManager(); verify(mContext, times(1)).getPackageName(); verify(mPm, times(1)).getPackageInfo(anyString(), anyInt()); + + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + + // Module info is only queried once + verify(mPm, times(1)).getModuleInfo(anyString(), anyInt()); } @Test From 426e1a1c4c1dd2c13a521770be103d53661c3123 Mon Sep 17 00:00:00 2001 From: Mark Chien Date: Tue, 18 May 2021 03:37:13 +0000 Subject: [PATCH 189/777] Add isFeatureEnabled by checking with apex module version A variable of #isFeatureEnabled which check apex module version instead of apk version. Bug: 187946226 Test: NetworkStaticLibTests Original change: https://android-review.googlesource.com/c/platform/frameworks/libs/net/+/1705174 Ignore-AOSP-First: manual cherry-pick from AOSP build automerge is broken Change-Id: I68659e43d7fdf40678ceb9df2ff10d480a5d08e0 --- .../net/module/util/DeviceConfigUtils.java | 83 ++++++++++++++++++- .../module/util/DeviceConfigUtilsTest.java | 52 +++++++++++- 2 files changed, 128 insertions(+), 7 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index 5d03dfd279..77b7835b9e 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -17,6 +17,7 @@ package com.android.net.module.util; import android.content.Context; +import android.content.pm.ModuleInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.provider.DeviceConfig; @@ -38,6 +39,7 @@ public final class DeviceConfigUtils { @VisibleForTesting public static void resetPackageVersionCacheForTest() { sPackageVersion = -1; + sModuleVersion = -1; } private static volatile long sPackageVersion = -1; @@ -155,17 +157,90 @@ public final class DeviceConfigUtils { public static boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, @NonNull String name, boolean defaultEnabled) { try { - final int propertyVersion = getDeviceConfigPropertyInt(namespace, name, - 0 /* default value */); final long packageVersion = getPackageVersion(context); - return (propertyVersion == 0 && defaultEnabled) - || (propertyVersion != 0 && packageVersion >= (long) propertyVersion); + return isFeatureEnabled(context, packageVersion, namespace, name, defaultEnabled); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Could not find the package name", e); return false; } } + /** + * Check whether or not one specific experimental feature for a particular namespace from + * {@link DeviceConfig} is enabled by comparing module package version + * with current version of property. If this property version is valid, the corresponding + * experimental feature would be enabled, otherwise disabled. + * + * This is useful to ensure that if a module install is rolled back, flags are not left fully + * rolled out on a version where they have not been well tested. + * @param context The global context information about an app environment. + * @param namespace The namespace containing the property to look up. + * @param name The name of the property to look up. + * @param moduleName The mainline module name which is released as apex. + * @param defaultEnabled The value to return if the property does not exist or its value is + * null. + * @return true if this feature is enabled, or false if disabled. + */ + public static boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, + @NonNull String name, @NonNull String moduleName, boolean defaultEnabled) { + try { + final long packageVersion = getModuleVersion(context, moduleName); + return isFeatureEnabled(context, packageVersion, namespace, name, defaultEnabled); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Could not find the module name", e); + return false; + } + } + + private static boolean maybeUseFixedPackageVersion(@NonNull Context context) { + final String packageName = context.getPackageName(); + if (packageName == null) return false; + + return packageName.equals("com.android.networkstack.tethering") + || packageName.equals("com.android.networkstack.tethering.inprocess"); + } + + private static boolean isFeatureEnabled(@NonNull Context context, long packageVersion, + @NonNull String namespace, String name, boolean defaultEnabled) + throws PackageManager.NameNotFoundException { + final int propertyVersion = getDeviceConfigPropertyInt(namespace, name, + 0 /* default value */); + return (propertyVersion == 0 && defaultEnabled) + || (propertyVersion != 0 && packageVersion >= (long) propertyVersion); + } + + private static volatile long sModuleVersion = -1; + @VisibleForTesting public static long FIXED_PACKAGE_VERSION = 10; + private static long getModuleVersion(@NonNull Context context, @NonNull String moduleName) + throws PackageManager.NameNotFoundException { + if (sModuleVersion >= 0) return sModuleVersion; + + final PackageManager packageManager = context.getPackageManager(); + ModuleInfo module; + try { + module = packageManager.getModuleInfo( + moduleName, PackageManager.MODULE_APEX_NAME); + } catch (PackageManager.NameNotFoundException e) { + // The error may happen if mainline module meta data is not installed e.g. there are + // no meta data configuration in AOSP build. To be able to enable a feature in AOSP + // by setting a flag via ADB for example. set a small non-zero fixed number for + // comparing. + if (maybeUseFixedPackageVersion(context)) { + sModuleVersion = FIXED_PACKAGE_VERSION; + return FIXED_PACKAGE_VERSION; + } else { + throw e; + } + } + String modulePackageName = module.getPackageName(); + if (modulePackageName == null) throw new PackageManager.NameNotFoundException(moduleName); + final long version = packageManager.getPackageInfo(modulePackageName, + PackageManager.MATCH_APEX).getLongVersionCode(); + sModuleVersion = version; + + return version; + } + /** * Gets boolean config from resources. */ diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java index 57316b2f42..c65f79340a 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -18,6 +18,7 @@ package com.android.net.module.util; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; +import static com.android.net.module.util.DeviceConfigUtils.FIXED_PACKAGE_VERSION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -30,6 +31,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; +import android.content.pm.ModuleInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -64,10 +66,13 @@ public class DeviceConfigUtilsTest { private static final int TEST_MIN_FLAG_VALUE = 100; private static final long TEST_PACKAGE_VERSION = 290000000; private static final String TEST_PACKAGE_NAME = "test.package.name"; + private static final String TETHERING_AOSP_PACKAGE_NAME = "com.android.networkstack.tethering"; + private static final String TEST_APEX_NAME = "test.apex.name"; private MockitoSession mSession; @Mock private Context mContext; @Mock private PackageManager mPm; + @Mock private ModuleInfo mMi; @Mock private PackageInfo mPi; @Mock private Resources mResources; @@ -81,6 +86,8 @@ public class DeviceConfigUtilsTest { doReturn(mPm).when(mContext).getPackageManager(); doReturn(TEST_PACKAGE_NAME).when(mContext).getPackageName(); + doReturn(mMi).when(mPm).getModuleInfo(eq(TEST_APEX_NAME), anyInt()); + doReturn(TEST_PACKAGE_NAME).when(mMi).getPackageName(); doReturn(pi).when(mPm).getPackageInfo(anyString(), anyInt()); doReturn(mResources).when(mContext).getResources(); } @@ -193,23 +200,54 @@ public class DeviceConfigUtilsTest { eq(TEST_EXPERIMENT_FLAG))); assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); } @Test - public void testFeatureIsNotEnabled() { + public void testFeatureDefaultEnabled() { doReturn(null).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); + assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, true /* defaultEnabled */)); } @Test public void testFeatureIsEnabledWithException() throws Exception { - doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), - eq(TEST_EXPERIMENT_FLAG))); doThrow(NameNotFoundException.class).when(mPm).getPackageInfo(anyString(), anyInt()); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); + assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + doThrow(NameNotFoundException.class).when(mPm).getModuleInfo(anyString(), anyInt()); + assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + } + + + @Test + public void testFeatureIsEnabledUsingFixedVersion() throws Exception { + doReturn(TETHERING_AOSP_PACKAGE_NAME).when(mContext).getPackageName(); + doThrow(NameNotFoundException.class).when(mPm).getModuleInfo(anyString(), anyInt()); + + doReturn(Long.toString(FIXED_PACKAGE_VERSION)).when(() -> DeviceConfig.getProperty( + eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + + doReturn(Long.toString(FIXED_PACKAGE_VERSION + 1)).when(() -> DeviceConfig.getProperty( + eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); + assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + + doReturn(Long.toString(FIXED_PACKAGE_VERSION - 1)).when(() -> DeviceConfig.getProperty( + eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); } @Test @@ -225,6 +263,14 @@ public class DeviceConfigUtilsTest { verify(mContext, times(1)).getPackageManager(); verify(mContext, times(1)).getPackageName(); verify(mPm, times(1)).getPackageInfo(anyString(), anyInt()); + + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + + // Module info is only queried once + verify(mPm, times(1)).getModuleInfo(anyString(), anyInt()); } @Test From 3f427fbef65032ebc3bca93ec7222c7b3351c0e0 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Mon, 17 May 2021 18:51:01 +0000 Subject: [PATCH 190/777] Add visibility for packages/modules/Connectivity BUG: 186628461 Test: TH Change-Id: I579cfbae1645643a876883cc586e66a1084e3389 --- staticlibs/Android.bp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 3dbc09f11a..1371c8ccf3 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -49,13 +49,12 @@ java_library { ], visibility: [ "//frameworks/base/packages/Tethering", - "//packages/modules/Connectivity/Tethering", + "//packages/modules/Connectivity:__subpackages__", + "//packages/modules/Connectivity/framework:__subpackages__", "//frameworks/opt/net/ike", "//frameworks/opt/net/wifi/service", "//packages/modules/Wifi/service", "//frameworks/opt/net/telephony", - "//frameworks/base/packages/Connectivity:__subpackages__", - "//packages/modules/Connectivity:__subpackages__", "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", @@ -86,6 +85,7 @@ filegroup { path: "framework", visibility: [ "//frameworks/base", + "//packages/modules/Connectivity:__subpackages__", "//frameworks/base/packages/Connectivity/framework", ], } From 48ad2d6975f465061d0a7233dc68005d5b79c347 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Mon, 17 May 2021 18:51:01 +0000 Subject: [PATCH 191/777] Add visibility for packages/modules/Connectivity BUG: 186628461 Test: TH Change-Id: I579cfbae1645643a876883cc586e66a1084e3389 --- staticlibs/client-libs/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/client-libs/Android.bp b/staticlibs/client-libs/Android.bp index 9cedd29f4f..8c79d2a10e 100644 --- a/staticlibs/client-libs/Android.bp +++ b/staticlibs/client-libs/Android.bp @@ -12,7 +12,7 @@ java_library { "com.android.tethering" ], visibility: [ - "//packages/modules/Connectivity/Tethering", + "//packages/modules/Connectivity:__subpackages__", "//frameworks/base/services:__subpackages__", "//frameworks/base/packages:__subpackages__", "//frameworks/libs/net/client-libs/tests:__subpackages__", From a9fb0c88e3372bf1bc22ede44f34801600bfef33 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Sat, 22 May 2021 13:16:30 +0000 Subject: [PATCH 192/777] Add visibility for packages/modules/Connectivity Also cleanup previous locations from visibility rules. BUG: 186628461 Test: TH Merged-In: I579cfbae1645643a876883cc586e66a1084e3389 Change-Id: Id48980dede159e48c049f85bc34a84004a72a7e3 --- staticlibs/Android.bp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 3dbc09f11a..1371c8ccf3 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -49,13 +49,12 @@ java_library { ], visibility: [ "//frameworks/base/packages/Tethering", - "//packages/modules/Connectivity/Tethering", + "//packages/modules/Connectivity:__subpackages__", + "//packages/modules/Connectivity/framework:__subpackages__", "//frameworks/opt/net/ike", "//frameworks/opt/net/wifi/service", "//packages/modules/Wifi/service", "//frameworks/opt/net/telephony", - "//frameworks/base/packages/Connectivity:__subpackages__", - "//packages/modules/Connectivity:__subpackages__", "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", @@ -86,6 +85,7 @@ filegroup { path: "framework", visibility: [ "//frameworks/base", + "//packages/modules/Connectivity:__subpackages__", "//frameworks/base/packages/Connectivity/framework", ], } From 8a12ff6b03328f3800a6d7e3464a5eeb24459b55 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Sat, 22 May 2021 13:16:30 +0000 Subject: [PATCH 193/777] Add visibility for packages/modules/Connectivity Also cleanup previous locations from visibility rules. BUG: 186628461 Test: TH Merged-In: I579cfbae1645643a876883cc586e66a1084e3389 Change-Id: Id48980dede159e48c049f85bc34a84004a72a7e3 --- staticlibs/client-libs/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/client-libs/Android.bp b/staticlibs/client-libs/Android.bp index 9cedd29f4f..8c79d2a10e 100644 --- a/staticlibs/client-libs/Android.bp +++ b/staticlibs/client-libs/Android.bp @@ -12,7 +12,7 @@ java_library { "com.android.tethering" ], visibility: [ - "//packages/modules/Connectivity/Tethering", + "//packages/modules/Connectivity:__subpackages__", "//frameworks/base/services:__subpackages__", "//frameworks/base/packages:__subpackages__", "//frameworks/libs/net/client-libs/tests:__subpackages__", From 82ab3096eab1cd35a86568a31d26e6b6d15590fc Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Sat, 22 May 2021 13:16:30 +0000 Subject: [PATCH 194/777] Add visibility for packages/modules/Connectivity Also cleanup previous locations from visibility rules. BUG: 186628461 Test: TH Merged-In: I579cfbae1645643a876883cc586e66a1084e3389 Change-Id: Id48980dede159e48c049f85bc34a84004a72a7e3 --- staticlibs/Android.bp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 3dbc09f11a..1371c8ccf3 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -49,13 +49,12 @@ java_library { ], visibility: [ "//frameworks/base/packages/Tethering", - "//packages/modules/Connectivity/Tethering", + "//packages/modules/Connectivity:__subpackages__", + "//packages/modules/Connectivity/framework:__subpackages__", "//frameworks/opt/net/ike", "//frameworks/opt/net/wifi/service", "//packages/modules/Wifi/service", "//frameworks/opt/net/telephony", - "//frameworks/base/packages/Connectivity:__subpackages__", - "//packages/modules/Connectivity:__subpackages__", "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", @@ -86,6 +85,7 @@ filegroup { path: "framework", visibility: [ "//frameworks/base", + "//packages/modules/Connectivity:__subpackages__", "//frameworks/base/packages/Connectivity/framework", ], } From 471735769f4b7d5c46f32c9521c30d44993194ff Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Sat, 22 May 2021 13:16:30 +0000 Subject: [PATCH 195/777] Add visibility for packages/modules/Connectivity Also cleanup previous locations from visibility rules. BUG: 186628461 Test: TH Merged-In: I579cfbae1645643a876883cc586e66a1084e3389 Change-Id: Id48980dede159e48c049f85bc34a84004a72a7e3 --- staticlibs/client-libs/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/client-libs/Android.bp b/staticlibs/client-libs/Android.bp index 9cedd29f4f..8c79d2a10e 100644 --- a/staticlibs/client-libs/Android.bp +++ b/staticlibs/client-libs/Android.bp @@ -12,7 +12,7 @@ java_library { "com.android.tethering" ], visibility: [ - "//packages/modules/Connectivity/Tethering", + "//packages/modules/Connectivity:__subpackages__", "//frameworks/base/services:__subpackages__", "//frameworks/base/packages:__subpackages__", "//frameworks/libs/net/client-libs/tests:__subpackages__", From f8c12829c69bf0d9d15a209b7c73d28a23517243 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Fri, 21 May 2021 04:26:52 +0000 Subject: [PATCH 196/777] Add visibility for packages/modules/Connectivity BUG: 186628461 Test: TH Merged-In: Id48980dede159e48c049f85bc34a84004a72a7e3 Change-Id: Ia02ccf880f8299b437c1364d823a3ff1eb6960ff --- staticlibs/Android.bp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 74aafd30dd..ec36608794 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -49,13 +49,12 @@ java_library { ], visibility: [ "//frameworks/base/packages/Tethering", - "//packages/modules/Connectivity/Tethering", + "//packages/modules/Connectivity:__subpackages__", + "//packages/modules/Connectivity/framework:__subpackages__", "//frameworks/opt/net/ike", "//frameworks/opt/net/wifi/service", "//packages/modules/Wifi/service", "//frameworks/opt/net/telephony", - "//frameworks/base/packages/Connectivity:__subpackages__", - "//packages/modules/Connectivity:__subpackages__", "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", From b5f7eba152815d3b037b24da4cbaf42587f7f069 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Fri, 21 May 2021 04:26:52 +0000 Subject: [PATCH 197/777] Add visibility for packages/modules/Connectivity BUG: 186628461 Test: TH Merged-In: Id48980dede159e48c049f85bc34a84004a72a7e3 Change-Id: Ia02ccf880f8299b437c1364d823a3ff1eb6960ff --- staticlibs/client-libs/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/client-libs/Android.bp b/staticlibs/client-libs/Android.bp index 9cedd29f4f..8c79d2a10e 100644 --- a/staticlibs/client-libs/Android.bp +++ b/staticlibs/client-libs/Android.bp @@ -12,7 +12,7 @@ java_library { "com.android.tethering" ], visibility: [ - "//packages/modules/Connectivity/Tethering", + "//packages/modules/Connectivity:__subpackages__", "//frameworks/base/services:__subpackages__", "//frameworks/base/packages:__subpackages__", "//frameworks/libs/net/client-libs/tests:__subpackages__", From d6668fa34aaa45a299d6c354624e04324fd856af Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Mon, 17 May 2021 18:51:01 +0000 Subject: [PATCH 198/777] Add visibility for packages/modules/Connectivity BUG: 186628461 Test: TH Change-Id: I579cfbae1645643a876883cc586e66a1084e3389 (cherry picked from commit deacf7673765ac3c66624fb93eb7a4e587d4fdec) --- staticlibs/Android.bp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 3dbc09f11a..1371c8ccf3 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -49,13 +49,12 @@ java_library { ], visibility: [ "//frameworks/base/packages/Tethering", - "//packages/modules/Connectivity/Tethering", + "//packages/modules/Connectivity:__subpackages__", + "//packages/modules/Connectivity/framework:__subpackages__", "//frameworks/opt/net/ike", "//frameworks/opt/net/wifi/service", "//packages/modules/Wifi/service", "//frameworks/opt/net/telephony", - "//frameworks/base/packages/Connectivity:__subpackages__", - "//packages/modules/Connectivity:__subpackages__", "//packages/modules/NetworkStack:__subpackages__", "//packages/modules/CaptivePortalLogin", "//frameworks/libs/net/common/tests:__subpackages__", @@ -86,6 +85,7 @@ filegroup { path: "framework", visibility: [ "//frameworks/base", + "//packages/modules/Connectivity:__subpackages__", "//frameworks/base/packages/Connectivity/framework", ], } From 4d5af8248fb86e61ee7f784ed6f9864e37238365 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Mon, 17 May 2021 18:51:01 +0000 Subject: [PATCH 199/777] Add visibility for packages/modules/Connectivity BUG: 186628461 Test: TH Change-Id: I579cfbae1645643a876883cc586e66a1084e3389 (cherry picked from commit deacf7673765ac3c66624fb93eb7a4e587d4fdec) --- staticlibs/client-libs/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/client-libs/Android.bp b/staticlibs/client-libs/Android.bp index 9cedd29f4f..8c79d2a10e 100644 --- a/staticlibs/client-libs/Android.bp +++ b/staticlibs/client-libs/Android.bp @@ -12,7 +12,7 @@ java_library { "com.android.tethering" ], visibility: [ - "//packages/modules/Connectivity/Tethering", + "//packages/modules/Connectivity:__subpackages__", "//frameworks/base/services:__subpackages__", "//frameworks/base/packages:__subpackages__", "//frameworks/libs/net/client-libs/tests:__subpackages__", From 253521d294e3f09801f79eb5d379e1582a69b6aa Mon Sep 17 00:00:00 2001 From: James Mattis Date: Sat, 3 Apr 2021 22:20:38 -0700 Subject: [PATCH 200/777] Update TestNetworkTracker tearDown() Update to TestNetworkTracker tearDown() to call TestNetworkManager to tear down the current test network. Bug: 176496580 Bug: 176494815 Test: atest FrameworksNetTests atest NetworkStackTests atest FrameworksNetIntegrationTests atest NetworkStackIntegrationTests atest CtsNetTestCasesLatestSdk Change-Id: I5ba142f601f3942d6e6ec4106fc0e70012b42a49 --- .../devicetests/com/android/testutils/TestNetworkTracker.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt index 5b978617aa..d8dd67a345 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt @@ -51,7 +51,7 @@ fun initTestNetwork(context: Context, interfaceAddr: LinkAddress, setupTimeoutMs class TestNetworkTracker internal constructor( val context: Context, val iface: TestNetworkInterface, - tnm: TestNetworkManager, + val tnm: TestNetworkManager, setupTimeoutMs: Long ) { private val cm = context.getSystemService(ConnectivityManager::class.java) @@ -87,5 +87,6 @@ class TestNetworkTracker internal constructor( fun teardown() { cm.unregisterNetworkCallback(networkCallback) + tnm.teardownTestNetwork(network) } } \ No newline at end of file From 31d1404c210811e3f26ff987189478ae18f20190 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Tue, 1 Jun 2021 02:57:27 +0000 Subject: [PATCH 201/777] Fix NsHeader class unavailable constructor. NsHeader class has two members, however, the public constructor has only one parameter for target IP address, that would throw the exception when parsing the NsHeader struct due to unavailable constructor. Bug: 162944199 Test: atest NetworkStackTests Change-Id: I8d0a63bc258e83be55b9ec2d34ef228cf8549c2e --- .../com/android/net/module/util/structs/NsHeader.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/structs/NsHeader.java b/staticlibs/device/com/android/net/module/util/structs/NsHeader.java index 6e0aa50868..2e8b77ba11 100644 --- a/staticlibs/device/com/android/net/module/util/structs/NsHeader.java +++ b/staticlibs/device/com/android/net/module/util/structs/NsHeader.java @@ -50,8 +50,12 @@ public class NsHeader extends Struct { @Field(order = 1, type = Type.Ipv6Address) public Inet6Address target; - public NsHeader(final Inet6Address target) { - this.reserved = 0; + NsHeader(int reserved, final Inet6Address target) { + this.reserved = reserved; this.target = target; } + + public NsHeader(final Inet6Address target) { + this(0, target); + } } From 1f2ef676767fa799278dfce492216f6e7cdbbfe6 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 12 Jan 2021 20:40:20 +0900 Subject: [PATCH 202/777] [NS02] Remove unused methods Test: FrameworksNetTests NetworkStackTests Merged-In: If1b23e27d8fb2b3b484466245268eb6787e58818 Change-Id: If1b23e27d8fb2b3b484466245268eb6787e58818 (cherry-picked from ag/13918825) --- .../device/android/net/NetworkFactory.java | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/staticlibs/device/android/net/NetworkFactory.java b/staticlibs/device/android/net/NetworkFactory.java index bcc60897b4..8f2d2fa163 100644 --- a/staticlibs/device/android/net/NetworkFactory.java +++ b/staticlibs/device/android/net/NetworkFactory.java @@ -244,12 +244,6 @@ public class NetworkFactory extends Handler { evalRequests(); } - /** @deprecated None of the implementors use the score, remove this method */ - @Deprecated - public boolean acceptRequest(NetworkRequest request, int score) { - return acceptRequest(request); - } - /** * Overridable function to provide complex filtering. * Called for every request every time a new NetworkRequest is seen @@ -284,7 +278,7 @@ public class NetworkFactory extends Handler { } if (shouldNeedNetworkFor(n)) { if (VDBG) log(" needNetworkFor"); - needNetworkFor(n.request, n.score); + needNetworkFor(n.request); n.requested = true; } else if (shouldReleaseNetworkFor(n)) { if (VDBG) log(" releaseNetworkFor"); @@ -307,7 +301,7 @@ public class NetworkFactory extends Handler { && n.request.canBeSatisfiedBy(mCapabilityFilter) // Finally if the concrete implementation of the factory rejects the request, then // don't track it. - && acceptRequest(n.request, n.score); + && acceptRequest(n.request); } private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) { @@ -321,7 +315,7 @@ public class NetworkFactory extends Handler { // - The concrete implementation of the factory rejects the request && ((n.score > mScore && n.providerId != mProvider.getProviderId()) || !n.request.canBeSatisfiedBy(mCapabilityFilter) - || !acceptRequest(n.request, n.score)); + || !acceptRequest(n.request)); } private void evalRequests() { @@ -363,12 +357,6 @@ public class NetworkFactory extends Handler { protected void startNetwork() { } protected void stopNetwork() { } - /** @deprecated none of the implementors use the score : migrate them */ - @Deprecated - protected void needNetworkFor(NetworkRequest networkRequest, int score) { - needNetworkFor(networkRequest); - } - // override to do fancier stuff protected void needNetworkFor(NetworkRequest networkRequest) { if (++mRefCount == 1) startNetwork(); From 0cff4a5440b4c8c5a30375be326f9fffad3ddbbf Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 12 Jan 2021 15:23:38 +0900 Subject: [PATCH 203/777] [NS05] Implement NetworkScore in NetworkFactory Test: FrameworksNetTests FrameworksWifiTests NetworkStackTests Merged-In: I6ec7b49bef74b030687c16bce14c2522431018ab Change-Id: I6ec7b49bef74b030687c16bce14c2522431018ab (cherry-picked from ag/13946208 with api change fix) --- .../device/android/net/NetworkFactory.java | 254 +++++++++--------- 1 file changed, 134 insertions(+), 120 deletions(-) diff --git a/staticlibs/device/android/net/NetworkFactory.java b/staticlibs/device/android/net/NetworkFactory.java index 8f2d2fa163..50cecdead0 100644 --- a/staticlibs/device/android/net/NetworkFactory.java +++ b/staticlibs/device/android/net/NetworkFactory.java @@ -17,7 +17,9 @@ package android.net; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; +import android.net.NetworkProvider.NetworkOfferCallback; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -29,6 +31,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.LinkedHashMap; import java.util.Map; +import java.util.concurrent.Executor; /** * A NetworkFactory is an entity that creates NetworkAgent objects. @@ -48,6 +51,14 @@ import java.util.Map; public class NetworkFactory extends Handler { private static final boolean DBG = true; private static final boolean VDBG = false; + + // A score that will win against everything, so that score filtering will let all requests + // through + // TODO : remove this and replace with an API to listen to all requests. + @NonNull + private static final NetworkScore INVINCIBLE_SCORE = + new NetworkScore.Builder().setLegacyInt(1000).build(); + /** * Pass a network request to the bearer. If the bearer believes it can * satisfy the request it should connect to the network and create a @@ -59,19 +70,9 @@ public class NetworkFactory extends Handler { * disregard any that it will never be able to service, for example * those requiring a different bearer. * msg.obj = NetworkRequest - * msg.arg1 = score - the score of the network currently satisfying this - * request. If this bearer knows in advance it cannot - * exceed this score it should not try to connect, holding the request - * for the future. - * Note that subsequent events may give a different (lower - * or higher) score for this request, transmitted to each - * NetworkFactory through additional CMD_REQUEST_NETWORK msgs - * with the same NetworkRequest but an updated score. - * Also, network conditions may change for this bearer - * allowing for a better score in the future. - * msg.arg2 = the ID of the NetworkProvider currently responsible for the - * NetworkAgent handling this request, or NetworkProvider.ID_NONE if none. */ + // TODO : this and CANCEL_REQUEST are only used by telephony tests. Replace it in the tests + // and remove them and the associated code. public static final int CMD_REQUEST_NETWORK = 1; /** @@ -82,7 +83,7 @@ public class NetworkFactory extends Handler { /** * Internally used to set our best-guess score. - * msg.arg1 = new score + * msg.obj = new score */ private static final int CMD_SET_SCORE = 3; @@ -93,28 +94,73 @@ public class NetworkFactory extends Handler { */ private static final int CMD_SET_FILTER = 4; + /** + * Internally used to send the network offer associated with this factory. + * No arguments, will read from members + */ + private static final int CMD_OFFER_NETWORK = 5; + + /** + * Internally used to send the request to listen to all requests. + * No arguments, will read from members + */ + private static final int CMD_LISTEN_TO_ALL_REQUESTS = 6; + private final Context mContext; private final String LOG_TAG; private final Map mNetworkRequests = new LinkedHashMap<>(); - private int mScore; - private NetworkCapabilities mCapabilityFilter; + @NonNull private NetworkScore mScore = new NetworkScore.Builder().setLegacyInt(0).build(); + @NonNull private NetworkCapabilities mCapabilityFilter; private int mRefCount = 0; private NetworkProvider mProvider = null; + private final NetworkOfferCallback mRequestCallback = new NetworkOfferCallback() { + @Override + public void onNetworkNeeded(@NonNull final NetworkRequest request) { + handleAddRequest(request); + } + + @Override + public void onNetworkUnneeded(@NonNull final NetworkRequest request) { + handleRemoveRequest(request); + } + }; + @NonNull private final Executor mExecutor = command -> post(command); + + // Ideally the filter argument would be non-null, but null has historically meant to see + // no requests and telephony passes null. public NetworkFactory(Looper looper, Context context, String logTag, - NetworkCapabilities filter) { + @Nullable final NetworkCapabilities filter) { super(looper); LOG_TAG = logTag; mContext = context; - mCapabilityFilter = filter; + if (null != filter) { + mCapabilityFilter = filter; + } else { + mCapabilityFilter = new NetworkCapabilities.Builder() + .withoutDefaultCapabilities().build(); + } } /* Registers this NetworkFactory with the system. May only be called once per factory. */ public void register() { + register(false); + } + + /** + * Registers this NetworkFactory with the system ignoring the score filter. This will let + * the factory always see all network requests matching its capabilities filter. + * May only be called once per factory. + */ + public void registerIgnoringScore() { + register(true); + } + + private void register(final boolean listenToAllRequests) { if (mProvider != null) { throw new IllegalStateException("A NetworkFactory must only be registered once"); } @@ -124,7 +170,7 @@ public class NetworkFactory extends Handler { @Override public void onNetworkRequested(@NonNull NetworkRequest request, int score, int servingProviderId) { - handleAddRequest(request, score, servingProviderId); + handleAddRequest(request); } @Override @@ -134,7 +180,19 @@ public class NetworkFactory extends Handler { }; ((ConnectivityManager) mContext.getSystemService( - Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); + Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); + + // The mScore and mCapabilityFilter members can only be accessed on the handler thread. + // TODO : offer a separate API to listen to all requests instead + if (listenToAllRequests) { + sendMessage(obtainMessage(CMD_LISTEN_TO_ALL_REQUESTS)); + } else { + sendMessage(obtainMessage(CMD_OFFER_NETWORK)); + } + } + + private void handleOfferNetwork(@NonNull final NetworkScore score) { + mProvider.registerNetworkOffer(score, mCapabilityFilter, mExecutor, mRequestCallback); } /** Unregisters this NetworkFactory. After this call, the object can no longer be used. */ @@ -156,7 +214,7 @@ public class NetworkFactory extends Handler { public void handleMessage(Message msg) { switch (msg.what) { case CMD_REQUEST_NETWORK: { - handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2); + handleAddRequest((NetworkRequest) msg.obj); break; } case CMD_CANCEL_REQUEST: { @@ -164,32 +222,36 @@ public class NetworkFactory extends Handler { break; } case CMD_SET_SCORE: { - handleSetScore(msg.arg1); + handleSetScore((NetworkScore) msg.obj); break; } case CMD_SET_FILTER: { handleSetFilter((NetworkCapabilities) msg.obj); break; } + case CMD_OFFER_NETWORK: { + handleOfferNetwork(mScore); + break; + } + case CMD_LISTEN_TO_ALL_REQUESTS: { + handleOfferNetwork(INVINCIBLE_SCORE); + break; + } } } private static class NetworkRequestInfo { - public final NetworkRequest request; - public int score; + @NonNull public final NetworkRequest request; public boolean requested; // do we have a request outstanding, limited by score - public int providerId; - NetworkRequestInfo(NetworkRequest request, int score, int providerId) { + NetworkRequestInfo(@NonNull final NetworkRequest request) { this.request = request; - this.score = score; this.requested = false; - this.providerId = providerId; } @Override public String toString() { - return "{" + request + ", score=" + score + ", requested=" + requested + "}"; + return "{" + request + ", requested=" + requested + "}"; } } @@ -198,35 +260,27 @@ public class NetworkFactory extends Handler { * @see #CMD_REQUEST_NETWORK * * @param request the request to handle. - * @param score the score of the NetworkAgent currently satisfying this request. - * @param servingProviderId the ID of the NetworkProvider that created the NetworkAgent - * currently satisfying this request. */ - @VisibleForTesting - protected void handleAddRequest(NetworkRequest request, int score, int servingProviderId) { + private void handleAddRequest(@NonNull final NetworkRequest request) { NetworkRequestInfo n = mNetworkRequests.get(request); if (n == null) { - if (DBG) { - log("got request " + request + " with score " + score - + " and providerId " + servingProviderId); - } - n = new NetworkRequestInfo(request, score, servingProviderId); + if (DBG) log("got request " + request); + n = new NetworkRequestInfo(request); mNetworkRequests.put(n.request, n); } else { if (VDBG) { - log("new score " + score + " for existing request " + request - + " and providerId " + servingProviderId); + log("handle existing request " + request); } - n.score = score; - n.providerId = servingProviderId; } if (VDBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); - evalRequest(n); + if (acceptRequest(request)) { + n.requested = true; + needNetworkFor(request); + } } - @VisibleForTesting - protected void handleRemoveRequest(NetworkRequest request) { + private void handleRemoveRequest(NetworkRequest request) { NetworkRequestInfo n = mNetworkRequests.get(request); if (n != null) { mNetworkRequests.remove(request); @@ -234,14 +288,21 @@ public class NetworkFactory extends Handler { } } - private void handleSetScore(int score) { + private void handleSetScore(@NonNull final NetworkScore score) { + if (mScore.equals(score)) return; mScore = score; - evalRequests(); + reevaluateAllRequests(); } - private void handleSetFilter(NetworkCapabilities netCap) { + private void handleSetFilter(@NonNull final NetworkCapabilities netCap) { + if (netCap.equals(mCapabilityFilter)) return; mCapabilityFilter = netCap; - evalRequests(); + reevaluateAllRequests(); + } + + protected final void reevaluateAllRequests() { + if (mProvider == null) return; + mProvider.registerNetworkOffer(mScore, mCapabilityFilter, mExecutor, mRequestCallback); } /** @@ -263,75 +324,9 @@ public class NetworkFactory extends Handler { * * @return {@code true} to accept the request. */ - public boolean acceptRequest(NetworkRequest request) { + public boolean acceptRequest(@NonNull final NetworkRequest request) { return true; } - - private void evalRequest(NetworkRequestInfo n) { - if (VDBG) { - log("evalRequest"); - log(" n.requests = " + n.requested); - log(" n.score = " + n.score); - log(" mScore = " + mScore); - log(" request.providerId = " + n.providerId); - log(" mProvider.id = " + mProvider.getProviderId()); - } - if (shouldNeedNetworkFor(n)) { - if (VDBG) log(" needNetworkFor"); - needNetworkFor(n.request); - n.requested = true; - } else if (shouldReleaseNetworkFor(n)) { - if (VDBG) log(" releaseNetworkFor"); - releaseNetworkFor(n.request); - n.requested = false; - } else { - if (VDBG) log(" done"); - } - } - - private boolean shouldNeedNetworkFor(NetworkRequestInfo n) { - // If this request is already tracked, it doesn't qualify for need - return !n.requested - // If the score of this request is higher or equal to that of this factory and some - // other factory is responsible for it, then this factory should not track the request - // because it has no hope of satisfying it. - && (n.score < mScore || n.providerId == mProvider.getProviderId()) - // If this factory can't satisfy the capability needs of this request, then it - // should not be tracked. - && n.request.canBeSatisfiedBy(mCapabilityFilter) - // Finally if the concrete implementation of the factory rejects the request, then - // don't track it. - && acceptRequest(n.request); - } - - private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) { - // Don't release a request that's not tracked. - return n.requested - // The request should be released if it can't be satisfied by this factory. That - // means either of the following conditions are met : - // - Its score is too high to be satisfied by this factory and it's not already - // assigned to the factory - // - This factory can't satisfy the capability needs of the request - // - The concrete implementation of the factory rejects the request - && ((n.score > mScore && n.providerId != mProvider.getProviderId()) - || !n.request.canBeSatisfiedBy(mCapabilityFilter) - || !acceptRequest(n.request)); - } - - private void evalRequests() { - for (NetworkRequestInfo n : mNetworkRequests.values()) { - evalRequest(n); - } - } - - /** - * Post a command, on this NetworkFactory Handler, to re-evaluate all - * outstanding requests. Can be called from a factory implementation. - */ - protected void reevaluateAllRequests() { - post(this::evalRequests); - } - /** * Can be called by a factory to release a request as unfulfillable: the request will be * removed, and the caller will get a @@ -358,16 +353,35 @@ public class NetworkFactory extends Handler { protected void stopNetwork() { } // override to do fancier stuff - protected void needNetworkFor(NetworkRequest networkRequest) { + protected void needNetworkFor(@NonNull final NetworkRequest networkRequest) { if (++mRefCount == 1) startNetwork(); } - protected void releaseNetworkFor(NetworkRequest networkRequest) { + protected void releaseNetworkFor(@NonNull final NetworkRequest networkRequest) { if (--mRefCount == 0) stopNetwork(); } - public void setScoreFilter(int score) { - sendMessage(obtainMessage(CMD_SET_SCORE, score, 0)); + /** + * @deprecated this method was never part of the API (system or public) and is only added + * for migration of existing clients. It will be removed before S ships. + */ + @Deprecated + public void setScoreFilter(final int score) { + setScoreFilter(new NetworkScore.Builder().setLegacyInt(score).build()); + } + + /** + * Set a score filter for this factory. + * + * This should include the transports the factory knows its networks will have, and + * an optimistic view of the attributes it may have. This does not commit the factory + * to being able to bring up such a network ; it only lets it avoid hearing about + * requests that it has no chance of fulfilling. + * + * @param score the filter + */ + public void setScoreFilter(@NonNull final NetworkScore score) { + sendMessage(obtainMessage(CMD_SET_SCORE, score)); } public void setCapabilityFilter(NetworkCapabilities netCap) { From 651faf76100e45e163e742d06bdecf908ccfb62d Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 24 Mar 2021 22:40:37 +0900 Subject: [PATCH 204/777] Add visibility to net-utils-framework-srcs Allow framework-connectivity to depend on net-utils-framework-srcs, and add @hide annotations to classes that were missing it. This allows depending on less classes than net-utils-device-common, and avoids transitive dependency on androidx.annotations used by net-utils-device-common (which itself depends on the public SDK). Bug: 183600168 Test: m Merged-In: I89a18bb46311800fd6807dad5785f12648f165d9 Change-Id: I4c37d78198682366f56cde1b2707b0323f2f9e40 --- staticlibs/Android.bp | 5 ++++- .../com/android/net/module/util/CollectionUtils.java | 1 + .../com/android/net/module/util/ConnectivityUtils.java | 1 + .../android/net/module/util/NetworkCapabilitiesUtils.java | 1 + .../com/android/net/module/util/NetworkIdentityUtils.java | 1 + 5 files changed, 8 insertions(+), 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index ec36608794..4810a647ac 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -83,7 +83,10 @@ filegroup { name: "net-utils-framework-common-srcs", srcs: ["framework/**/*.java"], path: "framework", - visibility: ["//frameworks/base"], + visibility: [ + "//frameworks/base", + "//frameworks/base/packages/Connectivity/framework", + ], } java_library { diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index 4fce8f50e4..0696cca897 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -27,6 +27,7 @@ import java.util.function.Predicate; /** * Utilities for {@link Collection} and arrays. + * @hide */ public final class CollectionUtils { private CollectionUtils() {} diff --git a/staticlibs/framework/com/android/net/module/util/ConnectivityUtils.java b/staticlibs/framework/com/android/net/module/util/ConnectivityUtils.java index 382912bf8d..c135e46643 100644 --- a/staticlibs/framework/com/android/net/module/util/ConnectivityUtils.java +++ b/staticlibs/framework/com/android/net/module/util/ConnectivityUtils.java @@ -24,6 +24,7 @@ import java.net.InetAddress; /** * Various utilities used in connectivity code. + * @hide */ public final class ConnectivityUtils { private ConnectivityUtils() {} diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 4c7d675ef7..552ab21f13 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -44,6 +44,7 @@ import com.android.internal.annotations.VisibleForTesting; /** * Utilities to examine {@link android.net.NetworkCapabilities}. + * @hide */ public final class NetworkCapabilitiesUtils { // Transports considered to classify networks in UI, in order of which transport should be diff --git a/staticlibs/framework/com/android/net/module/util/NetworkIdentityUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkIdentityUtils.java index 94e60178fc..b641753c03 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkIdentityUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkIdentityUtils.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; /** * Utilities to examine {@link android.net.NetworkIdentity}. + * @hide */ public class NetworkIdentityUtils { /** From 27e5fcd4838706a9dd9bbb513378a687f2460cea Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Sat, 22 May 2021 13:16:30 +0000 Subject: [PATCH 205/777] Add visibility for packages/modules/Connectivity Also cleanup previous locations from visibility rules. BUG: 186628461 Test: TH Merged-In: I579cfbae1645643a876883cc586e66a1084e3389 Change-Id: Id48980dede159e48c049f85bc34a84004a72a7e3 --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 4810a647ac..f3b2faa76f 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -85,6 +85,7 @@ filegroup { path: "framework", visibility: [ "//frameworks/base", + "//packages/modules/Connectivity:__subpackages__", "//frameworks/base/packages/Connectivity/framework", ], } From d175ef994f9dde08707a2a8b0d33192375adad17 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 8 Jun 2021 01:42:40 +0000 Subject: [PATCH 206/777] Add NET_CAPABILITY_ENTERPRISE into FORCE_RESTRICTED_CAPABILITIES Ignore-AOSP-First: Counter part CL is in internal branch Test: atest FrameworksNetTests Bug: 189809600 Change-Id: Ice1d0b87ed40bd5991217fe9d7b0c919a82d8acc --- .../com/android/net/module/util/NetworkCapabilitiesUtils.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 122b4994a5..d4b1c9e034 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -141,7 +141,8 @@ public final class NetworkCapabilitiesUtils { * See {@code NetworkCapabilities#maybeMarkCapabilitiesRestricted}. */ private static final long FORCE_RESTRICTED_CAPABILITIES = - (1 << NET_CAPABILITY_OEM_PAID) + (1 << NET_CAPABILITY_ENTERPRISE) + | (1 << NET_CAPABILITY_OEM_PAID) | (1 << NET_CAPABILITY_OEM_PRIVATE); /** From f0ab71b893132685bedfd4b30ae0ba424755d4cc Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 8 Jun 2021 01:42:40 +0000 Subject: [PATCH 207/777] Add NET_CAPABILITY_ENTERPRISE into FORCE_RESTRICTED_CAPABILITIES Test: atest FrameworksNetTests Bug: 189809600 Merged-In: Ice1d0b87ed40bd5991217fe9d7b0c919a82d8acc Change-Id: Ice1d0b87ed40bd5991217fe9d7b0c919a82d8acc (cherry-picked from ag/14883335) --- .../com/android/net/module/util/NetworkCapabilitiesUtils.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 4c7d675ef7..3ec0b6246d 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -133,7 +133,8 @@ public final class NetworkCapabilitiesUtils { * See {@code NetworkCapabilities#maybeMarkCapabilitiesRestricted}. */ private static final long FORCE_RESTRICTED_CAPABILITIES = - (1 << NET_CAPABILITY_OEM_PAID) + (1 << NET_CAPABILITY_ENTERPRISE) + | (1 << NET_CAPABILITY_OEM_PAID) | (1 << NET_CAPABILITY_OEM_PRIVATE); /** From f96e02087994fbaa435a8da86b76718771ca772c Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 9 Jun 2021 18:00:43 +0900 Subject: [PATCH 208/777] Add visibility for Connectivity tests Allow all Connectivity test subpackages to use the targets, so that the visibility does not need to be updated when test suites are reorganized inside Connectivity. Bug: 187935317 Test: m Change-Id: I99d1ec954ebe313e553443a9f081d54d7a5f12c1 --- staticlibs/tests/unit/Android.bp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index 45a89b0b11..5c5a431964 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -23,7 +23,8 @@ android_library { ], visibility: [ "//frameworks/base/packages/Tethering/tests/integration", - "//packages/modules/Connectivity/Tethering/tests/integration", + "//packages/modules/Connectivity/tests:__subpackages__", + "//packages/modules/Connectivity/Tethering/tests:__subpackages__", "//packages/modules/NetworkStack/tests/integration", ] } From 94dab0fcfa77a87f2924b2ed6f60ac103f060d89 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 9 Jun 2021 18:00:43 +0900 Subject: [PATCH 209/777] Add visibility for Connectivity tests Allow all Connectivity test subpackages to use the targets, so that the visibility does not need to be updated when test suites are reorganized inside Connectivity. Bug: 187935317 Test: m Change-Id: I99d1ec954ebe313e553443a9f081d54d7a5f12c1 --- staticlibs/client-libs/tests/unit/Android.bp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/staticlibs/client-libs/tests/unit/Android.bp b/staticlibs/client-libs/tests/unit/Android.bp index 2cd39bdcd6..220a6c1904 100644 --- a/staticlibs/client-libs/tests/unit/Android.bp +++ b/staticlibs/client-libs/tests/unit/Android.bp @@ -23,7 +23,8 @@ android_library { // Visible for Tethering and NetworkStack integration test and link NetdStaticLibTestsLib // there, so that the tests under client-libs can also be run when running tethering and // NetworkStack MTS. - "//packages/modules/Connectivity/Tethering/tests/integration", + "//packages/modules/Connectivity/tests:__subpackages__", + "//packages/modules/Connectivity/Tethering/tests:__subpackages__", "//packages/modules/NetworkStack/tests/integration", ] } From 8377130fc01f2014adb6c83d93fa4812aeb091d7 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 2 Jun 2021 05:50:56 +0000 Subject: [PATCH 210/777] Add TestableNetworkOfferCallback Ignore-AOSP-First: Needs cherry-picks Test: android.net.NetworkProviderTest on R/S device Bug: 189074532 Change-Id: Iac7ec1bb4c34b4354f7b43fec86ded68c1a1d0de --- .../testutils/TestableNetworkOfferCallback.kt | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkOfferCallback.kt diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkOfferCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkOfferCallback.kt new file mode 100644 index 0000000000..21bd60c95d --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkOfferCallback.kt @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2021 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 com.android.testutils + +import android.net.NetworkCapabilities +import android.net.NetworkProvider +import android.net.NetworkRequest +import android.util.Log +import com.android.net.module.util.ArrayTrackRecord +import kotlin.test.fail + +class TestableNetworkOfferCallback(val timeoutMs: Long, private val noCallbackTimeoutMs: Long) + : NetworkProvider.NetworkOfferCallback { + private val TAG = this::class.simpleName + val history = ArrayTrackRecord().newReadHead() + + sealed class CallbackEntry { + data class OnNetworkNeeded(val request: NetworkRequest) : CallbackEntry() + data class OnNetworkUnneeded(val request: NetworkRequest) : CallbackEntry() + } + + /** + * Called by the system when a network for this offer is needed to satisfy some + * networking request. + */ + override fun onNetworkNeeded(request: NetworkRequest) { + Log.d(TAG, "onNetworkNeeded $request") + history.add(CallbackEntry.OnNetworkNeeded(request)) + } + + /** + * Called by the system when this offer is no longer valuable for this request. + */ + override fun onNetworkUnneeded(request: NetworkRequest) { + Log.d(TAG, "onNetworkUnneeded $request") + history.add(CallbackEntry.OnNetworkUnneeded(request)) + } + + inline fun expectCallbackThat( + crossinline predicate: (T) -> Boolean + ) { + val event = history.poll(timeoutMs) + ?: fail("Did not receive callback after ${timeoutMs}ms") + if (event !is T || !predicate(event)) fail("Received unexpected callback $event") + } + + fun expectOnNetworkNeeded(capabilities: NetworkCapabilities) = + expectCallbackThat { + it.request.canBeSatisfiedBy(capabilities) + } + + fun expectOnNetworkUnneeded(capabilities: NetworkCapabilities) = + expectCallbackThat { + it.request.canBeSatisfiedBy(capabilities) + } + + fun assertNoCallback() { + val cb = history.poll(noCallbackTimeoutMs) + if (null != cb) fail("Expected no callback but got $cb") + } +} \ No newline at end of file From 860a8ebb6f7aa4a60a2bd977a810881d3988cadf Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 2 Jun 2021 07:39:55 +0800 Subject: [PATCH 211/777] Supports to add a response for the given headers Currently TestHttpServer only supports to add a response for Location header. Make it to add a response for the given headers so that any additional headers that should be returned along with the response. Bug: 181745786 Test: build Change-Id: I80b2fe43016b9cd12fc3cb95ee76f1ec9568ddfc --- .../com/android/testutils/TestHttpServer.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt index 7aae8e3b59..39ce4872ae 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt @@ -54,12 +54,12 @@ class TestHttpServer(host: String? = null) : NanoHTTPD(host, 0 /* auto-select th fun addResponse( uri: Uri, statusCode: Response.IStatus, - locationHeader: String? = null, + headers: Map? = null, content: String = "" ) { addResponse(Request(uri.path ?: "", Method.GET, uri.query ?: ""), - statusCode, locationHeader, content) + statusCode, headers, content) } /** @@ -68,11 +68,13 @@ class TestHttpServer(host: String? = null) : NanoHTTPD(host, 0 /* auto-select th fun addResponse( request: Request, statusCode: Response.IStatus, - locationHeader: String? = null, + headers: Map? = null, content: String = "" ) { val response = newFixedLengthResponse(statusCode, "text/plain", content) - locationHeader?.let { response.addHeader("Location", it) } + headers?.forEach { + (key, value) -> response.addHeader(key, value) + } responses[request] = response } From 1bd069f24d39a33baf757de171c0efb6c66e610c Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Fri, 28 May 2021 09:28:29 -0700 Subject: [PATCH 212/777] Allow lmkd to use bpf_syscall_wrappers LMKD needs access to map_gpu_mem_gpu_mem_total_map BPF map to record the total size of GPU allocations at the time of a kill. Change bpf_syscall_wrappers visibility to allow lmkd to use bpf_syscall_wrappers library. Bug: 189366037 Test: lmkd_unit_test Signed-off-by: Suren Baghdasaryan Change-Id: Ia1f75852a853f62b504351271119714f3fd95232 --- staticlibs/native/bpf_syscall_wrappers/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index fa90655433..befb9f8fd1 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -35,5 +35,6 @@ cc_library_headers { visibility: [ "//packages/modules/Connectivity/Tethering", "//system/bpf/libbpf_android", + "//system/memory/lmkd", ], } From bb6441aa077b49d19fab9af0b1cde37e76a97eb8 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 16 Jun 2021 01:30:05 +0000 Subject: [PATCH 213/777] Update TestNetworkTracker tearDown() Update to TestNetworkTracker tearDown() to call TestNetworkManager to tear down the current test network. Bug: 176496580 Bug: 176494815 Test: atest FrameworksNetTests atest NetworkStackTests atest FrameworksNetIntegrationTests atest NetworkStackIntegrationTests atest CtsNetTestCasesLatestSdk Original-Change: https://android-review.googlesource.com/1663785 Merged-In: I5ba142f601f3942d6e6ec4106fc0e70012b42a49 Change-Id: I5ba142f601f3942d6e6ec4106fc0e70012b42a49 --- .../devicetests/com/android/testutils/TestNetworkTracker.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt index 5b978617aa..d8dd67a345 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt @@ -51,7 +51,7 @@ fun initTestNetwork(context: Context, interfaceAddr: LinkAddress, setupTimeoutMs class TestNetworkTracker internal constructor( val context: Context, val iface: TestNetworkInterface, - tnm: TestNetworkManager, + val tnm: TestNetworkManager, setupTimeoutMs: Long ) { private val cm = context.getSystemService(ConnectivityManager::class.java) @@ -87,5 +87,6 @@ class TestNetworkTracker internal constructor( fun teardown() { cm.unregisterNetworkCallback(networkCallback) + tnm.teardownTestNetwork(network) } } \ No newline at end of file From 953d9cb061839cb9a85dd74278005dbe7b216b2c Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Fri, 28 May 2021 09:28:29 -0700 Subject: [PATCH 214/777] Allow lmkd to use bpf_syscall_wrappers LMKD needs access to map_gpu_mem_gpu_mem_total_map BPF map to record the total size of GPU allocations at the time of a kill. Change bpf_syscall_wrappers visibility to allow lmkd to use bpf_syscall_wrappers library. Bug: 189366037 Test: lmkd_unit_test Signed-off-by: Suren Baghdasaryan Change-Id: Ia1f75852a853f62b504351271119714f3fd95232 Merged-In: Ia1f75852a853f62b504351271119714f3fd95232 --- staticlibs/native/bpf_syscall_wrappers/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index fa90655433..befb9f8fd1 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -35,5 +35,6 @@ cc_library_headers { visibility: [ "//packages/modules/Connectivity/Tethering", "//system/bpf/libbpf_android", + "//system/memory/lmkd", ], } From 25ac0f1fb1de88dcb1219516faea25089aab682c Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 17 Jun 2021 05:35:29 +0000 Subject: [PATCH 215/777] Add ICMPv6 ND header length constants. Bug: 163492391 Test: m Change-Id: Ica318fc476b190416530be4e0d983132adac1ba5 --- .../com/android/net/module/util/NetworkStackConstants.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index b7062e7656..f7151d7b17 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -148,7 +148,10 @@ public final class NetworkStackConstants { public static final int ICMPV6_ND_OPTION_RDNSS = 25; public static final int ICMPV6_ND_OPTION_PREF64 = 38; + public static final int ICMPV6_RS_HEADER_LEN = 8; public static final int ICMPV6_RA_HEADER_LEN = 16; + public static final int ICMPV6_NS_HEADER_LEN = 24; + public static final int ICMPV6_NA_HEADER_LEN = 24; public static final int NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER = 1 << 31; public static final int NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED = 1 << 30; From 2713cdf321be80e70fe2cbaf4170b57140cc7446 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 17 Jun 2021 08:47:42 +0000 Subject: [PATCH 216/777] Allow expect onRequestStatsUpdated with any token Altough token field is not used for now. But by design, the token will be the version number of networkIdentity mappings that maintain by the service, which cannot be predicted by the test. Thus, allow expecting any token is necessary. Ignore-AOSP-First: Counter part CL is not available in aosp. Test: m gts && atest \ GtsNetworkStackHostTestCases:NetworkStatsHostTest#testNetworkStatsManager Bug: 191327585 Change-Id: Ibf10040a5c10b7b1c7d381c01a071fb157409004 --- .../android/testutils/TestableNetworkStatsProvider.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt index d5c3a2a05d..d034a7d509 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt @@ -23,6 +23,7 @@ import kotlin.test.assertTrue import kotlin.test.fail private const val DEFAULT_TIMEOUT_MS = 200L +const val TOKEN_ANY = -1 open class TestableNetworkStatsProvider( val defaultTimeoutMs: Long = DEFAULT_TIMEOUT_MS @@ -49,8 +50,13 @@ open class TestableNetworkStatsProvider( history.add(CallbackType.OnSetAlert(quotaBytes)) } - fun expectOnRequestStatsUpdate(token: Int, timeout: Long = defaultTimeoutMs) { - assertEquals(CallbackType.OnRequestStatsUpdate(token), history.poll(timeout)) + fun expectOnRequestStatsUpdate(token: Int, timeout: Long = defaultTimeoutMs): Int { + val event = history.poll(timeout) + assertTrue(event is CallbackType.OnRequestStatsUpdate) + if (token != TOKEN_ANY) { + assertEquals(token, event.token) + } + return token } fun expectOnSetLimit(iface: String?, quotaBytes: Long, timeout: Long = defaultTimeoutMs) { From 45e737d894f6d0c75258e1215023f4dd1569c9e7 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Fri, 18 Jun 2021 14:55:05 +0800 Subject: [PATCH 217/777] Create a new utils for connectivity related settings ConnectivitySettingsManager and CtsNetUtils are doing the same thing to set/get private DNS related settings. To prevent making the duplication code in two places, having a lib for them to call. Bug: 185311744 Test: atest CtsNetTestCases CtsNetTestCasesLatestSdk Change-Id: Ia192520039b187b24e0a7b8bf9509bb10859ace0 --- .../util/ConnectivitySettingsUtils.java | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 staticlibs/framework/com/android/net/module/util/ConnectivitySettingsUtils.java diff --git a/staticlibs/framework/com/android/net/module/util/ConnectivitySettingsUtils.java b/staticlibs/framework/com/android/net/module/util/ConnectivitySettingsUtils.java new file mode 100644 index 0000000000..b7eb70b08b --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/ConnectivitySettingsUtils.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ContentResolver; +import android.content.Context; +import android.provider.Settings; +import android.text.TextUtils; + +/** + * Collection of connectivity settings utilities. + * + * @hide + */ +public class ConnectivitySettingsUtils { + public static final int PRIVATE_DNS_MODE_OFF = 1; + public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; + public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; + + public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode"; + public static final String PRIVATE_DNS_MODE = "private_dns_mode"; + public static final String PRIVATE_DNS_MODE_OFF_STRING = "off"; + public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING = "opportunistic"; + public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING = "hostname"; + public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier"; + + /** + * Get private DNS mode as string. + * + * @param mode One of the private DNS values. + * @return A string of private DNS mode. + */ + public static String getPrivateDnsModeAsString(int mode) { + switch (mode) { + case PRIVATE_DNS_MODE_OFF: + return PRIVATE_DNS_MODE_OFF_STRING; + case PRIVATE_DNS_MODE_OPPORTUNISTIC: + return PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING; + case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME: + return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING; + default: + throw new IllegalArgumentException("Invalid private dns mode: " + mode); + } + } + + private static int getPrivateDnsModeAsInt(String mode) { + switch (mode) { + case "off": + return PRIVATE_DNS_MODE_OFF; + case "hostname": + return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; + case "opportunistic": + return PRIVATE_DNS_MODE_OPPORTUNISTIC; + default: + throw new IllegalArgumentException("Invalid private dns mode: " + mode); + } + } + + /** + * Get private DNS mode from settings. + * + * @param context The Context to query the private DNS mode from settings. + * @return An integer of private DNS mode. + */ + public static int getPrivateDnsMode(@NonNull Context context) { + final ContentResolver cr = context.getContentResolver(); + String mode = Settings.Global.getString(cr, PRIVATE_DNS_MODE); + if (TextUtils.isEmpty(mode)) mode = Settings.Global.getString(cr, PRIVATE_DNS_DEFAULT_MODE); + // If both PRIVATE_DNS_MODE and PRIVATE_DNS_DEFAULT_MODE are not set, choose + // PRIVATE_DNS_MODE_OPPORTUNISTIC as default mode. + if (TextUtils.isEmpty(mode)) return PRIVATE_DNS_MODE_OPPORTUNISTIC; + return getPrivateDnsModeAsInt(mode); + } + + /** + * Set private DNS mode to settings. + * + * @param context The {@link Context} to set the private DNS mode. + * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants. + */ + public static void setPrivateDnsMode(@NonNull Context context, int mode) { + if (!(mode == PRIVATE_DNS_MODE_OFF + || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC + || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) { + throw new IllegalArgumentException("Invalid private dns mode: " + mode); + } + Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE, + getPrivateDnsModeAsString(mode)); + } + + /** + * Get specific private dns provider name from {@link Settings}. + * + * @param context The {@link Context} to query the setting. + * @return The specific private dns provider name, or null if no setting value. + */ + @Nullable + public static String getPrivateDnsHostname(@NonNull Context context) { + return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER); + } + + /** + * Set specific private dns provider name to {@link Settings}. + * + * @param context The {@link Context} to set the setting. + * @param specifier The specific private dns provider name. + */ + public static void setPrivateDnsHostname(@NonNull Context context, @Nullable String specifier) { + Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER, specifier); + } +} From be5fe44c0b6ad7851b97accdbac55f852fc41f49 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 21 Jun 2021 13:54:13 +0000 Subject: [PATCH 218/777] Add TestableNetworkOfferCallback Ignore-AOSP-First: Needs cherry-picks Test: android.net.NetworkProviderTest on R/S device Bug: 189074532 Original-Change: https://android-review.googlesource.com/1731491 Merged-In: Iac7ec1bb4c34b4354f7b43fec86ded68c1a1d0de Change-Id: Iac7ec1bb4c34b4354f7b43fec86ded68c1a1d0de --- .../testutils/TestableNetworkOfferCallback.kt | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkOfferCallback.kt diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkOfferCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkOfferCallback.kt new file mode 100644 index 0000000000..21bd60c95d --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkOfferCallback.kt @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2021 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 com.android.testutils + +import android.net.NetworkCapabilities +import android.net.NetworkProvider +import android.net.NetworkRequest +import android.util.Log +import com.android.net.module.util.ArrayTrackRecord +import kotlin.test.fail + +class TestableNetworkOfferCallback(val timeoutMs: Long, private val noCallbackTimeoutMs: Long) + : NetworkProvider.NetworkOfferCallback { + private val TAG = this::class.simpleName + val history = ArrayTrackRecord().newReadHead() + + sealed class CallbackEntry { + data class OnNetworkNeeded(val request: NetworkRequest) : CallbackEntry() + data class OnNetworkUnneeded(val request: NetworkRequest) : CallbackEntry() + } + + /** + * Called by the system when a network for this offer is needed to satisfy some + * networking request. + */ + override fun onNetworkNeeded(request: NetworkRequest) { + Log.d(TAG, "onNetworkNeeded $request") + history.add(CallbackEntry.OnNetworkNeeded(request)) + } + + /** + * Called by the system when this offer is no longer valuable for this request. + */ + override fun onNetworkUnneeded(request: NetworkRequest) { + Log.d(TAG, "onNetworkUnneeded $request") + history.add(CallbackEntry.OnNetworkUnneeded(request)) + } + + inline fun expectCallbackThat( + crossinline predicate: (T) -> Boolean + ) { + val event = history.poll(timeoutMs) + ?: fail("Did not receive callback after ${timeoutMs}ms") + if (event !is T || !predicate(event)) fail("Received unexpected callback $event") + } + + fun expectOnNetworkNeeded(capabilities: NetworkCapabilities) = + expectCallbackThat { + it.request.canBeSatisfiedBy(capabilities) + } + + fun expectOnNetworkUnneeded(capabilities: NetworkCapabilities) = + expectCallbackThat { + it.request.canBeSatisfiedBy(capabilities) + } + + fun assertNoCallback() { + val cb = history.poll(noCallbackTimeoutMs) + if (null != cb) fail("Expected no callback but got $cb") + } +} \ No newline at end of file From 98568896279662b1b11ef5df2b579ca19741f52e Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 17 Jun 2021 08:47:42 +0000 Subject: [PATCH 219/777] Allow expect onRequestStatsUpdated with any token Altough token field is not used for now. But by design, the token will be the version number of networkIdentity mappings that maintain by the service, which cannot be predicted by the test. Thus, allow expecting any token is necessary. Test: m gts && atest \ GtsNetworkStackHostTestCases:NetworkStatsHostTest#testNetworkStatsManager Bug: 191327585 Merged-In: Ibf10040a5c10b7b1c7d381c01a071fb157409004 Change-Id: Ibf10040a5c10b7b1c7d381c01a071fb157409004 (cherry-picked from ag/15010113) --- .../android/testutils/TestableNetworkStatsProvider.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt index d5c3a2a05d..d034a7d509 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt @@ -23,6 +23,7 @@ import kotlin.test.assertTrue import kotlin.test.fail private const val DEFAULT_TIMEOUT_MS = 200L +const val TOKEN_ANY = -1 open class TestableNetworkStatsProvider( val defaultTimeoutMs: Long = DEFAULT_TIMEOUT_MS @@ -49,8 +50,13 @@ open class TestableNetworkStatsProvider( history.add(CallbackType.OnSetAlert(quotaBytes)) } - fun expectOnRequestStatsUpdate(token: Int, timeout: Long = defaultTimeoutMs) { - assertEquals(CallbackType.OnRequestStatsUpdate(token), history.poll(timeout)) + fun expectOnRequestStatsUpdate(token: Int, timeout: Long = defaultTimeoutMs): Int { + val event = history.poll(timeout) + assertTrue(event is CallbackType.OnRequestStatsUpdate) + if (token != TOKEN_ANY) { + assertEquals(token, event.token) + } + return token } fun expectOnSetLimit(iface: String?, quotaBytes: Long, timeout: Long = defaultTimeoutMs) { From c73b6391dd0a71d5c367abe8ac99a63e666c17f0 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 21 Jun 2021 10:14:21 +0000 Subject: [PATCH 220/777] Supports to add a response for the given headers Currently TestHttpServer only supports to add a response for Location header. Make it to add a response for the given headers so that any additional headers that should be returned along with the response. Bug: 181745786 Test: build Original-Change: https://android-review.googlesource.com/1724310 Merged-In: I80b2fe43016b9cd12fc3cb95ee76f1ec9568ddfc Change-Id: I80b2fe43016b9cd12fc3cb95ee76f1ec9568ddfc --- .../com/android/testutils/TestHttpServer.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt index 7aae8e3b59..39ce4872ae 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt @@ -54,12 +54,12 @@ class TestHttpServer(host: String? = null) : NanoHTTPD(host, 0 /* auto-select th fun addResponse( uri: Uri, statusCode: Response.IStatus, - locationHeader: String? = null, + headers: Map? = null, content: String = "" ) { addResponse(Request(uri.path ?: "", Method.GET, uri.query ?: ""), - statusCode, locationHeader, content) + statusCode, headers, content) } /** @@ -68,11 +68,13 @@ class TestHttpServer(host: String? = null) : NanoHTTPD(host, 0 /* auto-select th fun addResponse( request: Request, statusCode: Response.IStatus, - locationHeader: String? = null, + headers: Map? = null, content: String = "" ) { val response = newFixedLengthResponse(statusCode, "text/plain", content) - locationHeader?.let { response.addHeader("Location", it) } + headers?.forEach { + (key, value) -> response.addHeader(key, value) + } responses[request] = response } From 40803d4701e2878e38907e81f6731e460be0c329 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Mon, 21 Jun 2021 11:52:44 +0800 Subject: [PATCH 221/777] Add fall back to createTunInterface when running on R TNM.createTunInterface() takes different parameter from S. GTS is multi-release, so it should be compatible with S and before S build. Add sdk version check to support it. Bug: 186680038 Test: atest GtsNetworkStackHostTestCases:\ com.google.android.gts.networkstack.NetworkStackHostTest#\ testNetworkStack Change-Id: I5a08068db43e507637a53a32c15a5eb453d50c32 --- staticlibs/testutils/Android.bp | 1 + .../devicetests/com/android/testutils/TestNetworkTracker.kt | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index d4465dd717..6d9414f8aa 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -32,6 +32,7 @@ java_library { "libnanohttpd", "net-tests-utils-host-device-common", "net-utils-device-common", + "modules-utils-build_system", ], } diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt index d8dd67a345..36c09ce645 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt @@ -26,6 +26,7 @@ import android.net.NetworkRequest import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.os.Binder +import com.android.modules.utils.build.SdkLevel.isAtLeastS import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit @@ -39,7 +40,8 @@ import java.util.concurrent.TimeUnit fun initTestNetwork(context: Context, interfaceAddr: LinkAddress, setupTimeoutMs: Long = 10_000L): TestNetworkTracker { val tnm = context.getSystemService(TestNetworkManager::class.java) - val iface = tnm.createTunInterface(arrayOf(interfaceAddr)) + val iface = if (isAtLeastS()) tnm.createTunInterface(listOf(interfaceAddr)) + else tnm.createTunInterface(arrayOf(interfaceAddr)) return TestNetworkTracker(context, iface, tnm, setupTimeoutMs) } From 1dedd4bc2ad52bc4ca7de25c6ee02b5d2ead6b78 Mon Sep 17 00:00:00 2001 From: Lucas Lin Date: Mon, 21 Jun 2021 20:22:10 +0000 Subject: [PATCH 222/777] Create a new utils for connectivity related settings ConnectivitySettingsManager and CtsNetUtils are doing the same thing to set/get private DNS related settings. To prevent making the duplication code in two places, having a lib for them to call. Bug: 185311744 Test: atest CtsNetTestCases CtsNetTestCasesLatestSdk Original-Change: https://android-review.googlesource.com/1715693 Merged-In: Ia192520039b187b24e0a7b8bf9509bb10859ace0 Change-Id: Ia192520039b187b24e0a7b8bf9509bb10859ace0 --- .../util/ConnectivitySettingsUtils.java | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 staticlibs/framework/com/android/net/module/util/ConnectivitySettingsUtils.java diff --git a/staticlibs/framework/com/android/net/module/util/ConnectivitySettingsUtils.java b/staticlibs/framework/com/android/net/module/util/ConnectivitySettingsUtils.java new file mode 100644 index 0000000000..b7eb70b08b --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/ConnectivitySettingsUtils.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ContentResolver; +import android.content.Context; +import android.provider.Settings; +import android.text.TextUtils; + +/** + * Collection of connectivity settings utilities. + * + * @hide + */ +public class ConnectivitySettingsUtils { + public static final int PRIVATE_DNS_MODE_OFF = 1; + public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; + public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; + + public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode"; + public static final String PRIVATE_DNS_MODE = "private_dns_mode"; + public static final String PRIVATE_DNS_MODE_OFF_STRING = "off"; + public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING = "opportunistic"; + public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING = "hostname"; + public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier"; + + /** + * Get private DNS mode as string. + * + * @param mode One of the private DNS values. + * @return A string of private DNS mode. + */ + public static String getPrivateDnsModeAsString(int mode) { + switch (mode) { + case PRIVATE_DNS_MODE_OFF: + return PRIVATE_DNS_MODE_OFF_STRING; + case PRIVATE_DNS_MODE_OPPORTUNISTIC: + return PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING; + case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME: + return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING; + default: + throw new IllegalArgumentException("Invalid private dns mode: " + mode); + } + } + + private static int getPrivateDnsModeAsInt(String mode) { + switch (mode) { + case "off": + return PRIVATE_DNS_MODE_OFF; + case "hostname": + return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; + case "opportunistic": + return PRIVATE_DNS_MODE_OPPORTUNISTIC; + default: + throw new IllegalArgumentException("Invalid private dns mode: " + mode); + } + } + + /** + * Get private DNS mode from settings. + * + * @param context The Context to query the private DNS mode from settings. + * @return An integer of private DNS mode. + */ + public static int getPrivateDnsMode(@NonNull Context context) { + final ContentResolver cr = context.getContentResolver(); + String mode = Settings.Global.getString(cr, PRIVATE_DNS_MODE); + if (TextUtils.isEmpty(mode)) mode = Settings.Global.getString(cr, PRIVATE_DNS_DEFAULT_MODE); + // If both PRIVATE_DNS_MODE and PRIVATE_DNS_DEFAULT_MODE are not set, choose + // PRIVATE_DNS_MODE_OPPORTUNISTIC as default mode. + if (TextUtils.isEmpty(mode)) return PRIVATE_DNS_MODE_OPPORTUNISTIC; + return getPrivateDnsModeAsInt(mode); + } + + /** + * Set private DNS mode to settings. + * + * @param context The {@link Context} to set the private DNS mode. + * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants. + */ + public static void setPrivateDnsMode(@NonNull Context context, int mode) { + if (!(mode == PRIVATE_DNS_MODE_OFF + || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC + || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) { + throw new IllegalArgumentException("Invalid private dns mode: " + mode); + } + Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE, + getPrivateDnsModeAsString(mode)); + } + + /** + * Get specific private dns provider name from {@link Settings}. + * + * @param context The {@link Context} to query the setting. + * @return The specific private dns provider name, or null if no setting value. + */ + @Nullable + public static String getPrivateDnsHostname(@NonNull Context context) { + return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER); + } + + /** + * Set specific private dns provider name to {@link Settings}. + * + * @param context The {@link Context} to set the setting. + * @param specifier The specific private dns provider name. + */ + public static void setPrivateDnsHostname(@NonNull Context context, @Nullable String specifier) { + Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER, specifier); + } +} From 03f8890ec85e36ae4789bb00e7bc74ae6c991fe9 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 22 Jun 2021 01:21:24 +0000 Subject: [PATCH 223/777] Add OnSetWarningAndLimit into TestableNetworkStatsProvider This change also address left comments at ag/15010113. Ignore-AOSP-First: Counter part CL is not in aosp. Test: m gts && atest \ GtsNetworkStackHostTestCases:NetworkStatsHostTest#testNetworkStatsProvider Bug: 191327585 Change-Id: I100668cc6d4cecbaff29d027d37d313dd48854f3 --- .../testutils/TestableNetworkStatsProvider.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt index d034a7d509..8477151b7e 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt @@ -30,7 +30,12 @@ open class TestableNetworkStatsProvider( ) : NetworkStatsProvider() { sealed class CallbackType { data class OnRequestStatsUpdate(val token: Int) : CallbackType() - data class OnSetLimit(val iface: String?, val quotaBytes: Long) : CallbackType() + data class OnSetWarningAndLimit( + val iface: String?, + val warningBytes: Long, + val limitBytes: Long + ) : CallbackType() + data class OnSetLimit(val iface: String?, val limitBytes: Long) : CallbackType() data class OnSetAlert(val quotaBytes: Long) : CallbackType() } @@ -42,6 +47,10 @@ open class TestableNetworkStatsProvider( history.add(CallbackType.OnRequestStatsUpdate(token)) } + override fun onSetWarningAndLimit(iface: String, warningBytes: Long, limitBytes: Long) { + history.add(CallbackType.OnSetWarningAndLimit(iface, warningBytes, limitBytes)) + } + override fun onSetLimit(iface: String, quotaBytes: Long) { history.add(CallbackType.OnSetLimit(iface, quotaBytes)) } @@ -56,7 +65,7 @@ open class TestableNetworkStatsProvider( if (token != TOKEN_ANY) { assertEquals(token, event.token) } - return token + return event.token } fun expectOnSetLimit(iface: String?, quotaBytes: Long, timeout: Long = defaultTimeoutMs) { From 75b9e6773bfa46eac305f03e75f6b397cb24b878 Mon Sep 17 00:00:00 2001 From: Roy Want Date: Tue, 22 Jun 2021 18:08:58 +0000 Subject: [PATCH 224/777] Revert "Allow expect onRequestStatsUpdated with any token" This reverts commit 6b547a5fce031d25f2640f5da373aac8897634a2. Reason for revert: DroidMonitor: Potential culprit for Bug 191742804 - verifying through Forrest before revert submission. This is part of the standard investigation process: RESULT: Out of the two CL's pointed at by this bug, this CL appeared to be the cause of the failure; submitting revert. Change-Id: Ia727b13b11e9b863a702f83f68da12bbff3bcf3f --- .../android/testutils/TestableNetworkStatsProvider.kt | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt index d034a7d509..d5c3a2a05d 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt @@ -23,7 +23,6 @@ import kotlin.test.assertTrue import kotlin.test.fail private const val DEFAULT_TIMEOUT_MS = 200L -const val TOKEN_ANY = -1 open class TestableNetworkStatsProvider( val defaultTimeoutMs: Long = DEFAULT_TIMEOUT_MS @@ -50,13 +49,8 @@ open class TestableNetworkStatsProvider( history.add(CallbackType.OnSetAlert(quotaBytes)) } - fun expectOnRequestStatsUpdate(token: Int, timeout: Long = defaultTimeoutMs): Int { - val event = history.poll(timeout) - assertTrue(event is CallbackType.OnRequestStatsUpdate) - if (token != TOKEN_ANY) { - assertEquals(token, event.token) - } - return token + fun expectOnRequestStatsUpdate(token: Int, timeout: Long = defaultTimeoutMs) { + assertEquals(CallbackType.OnRequestStatsUpdate(token), history.poll(timeout)) } fun expectOnSetLimit(iface: String?, quotaBytes: Long, timeout: Long = defaultTimeoutMs) { From 4046a83b121907587f6852f49e9f67d6b59c55e0 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 23 Jun 2021 00:33:48 +0000 Subject: [PATCH 225/777] Revert "Revert "Allow expect onRequestStatsUpdated with any token"" This reverts commit 886c3f16352f372f8e384c2dafd74c304008af38. Reason for revert: From result of forrest, it turns out the culprit is not the CL. Hence the revert is not necessary. See https://buganizer.corp.google.com/issues/191742804#comment10 for more detail. Change-Id: If8492233c69d7947300f35f764199a7db1bd0045 --- .../android/testutils/TestableNetworkStatsProvider.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt index d5c3a2a05d..d034a7d509 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt @@ -23,6 +23,7 @@ import kotlin.test.assertTrue import kotlin.test.fail private const val DEFAULT_TIMEOUT_MS = 200L +const val TOKEN_ANY = -1 open class TestableNetworkStatsProvider( val defaultTimeoutMs: Long = DEFAULT_TIMEOUT_MS @@ -49,8 +50,13 @@ open class TestableNetworkStatsProvider( history.add(CallbackType.OnSetAlert(quotaBytes)) } - fun expectOnRequestStatsUpdate(token: Int, timeout: Long = defaultTimeoutMs) { - assertEquals(CallbackType.OnRequestStatsUpdate(token), history.poll(timeout)) + fun expectOnRequestStatsUpdate(token: Int, timeout: Long = defaultTimeoutMs): Int { + val event = history.poll(timeout) + assertTrue(event is CallbackType.OnRequestStatsUpdate) + if (token != TOKEN_ANY) { + assertEquals(token, event.token) + } + return token } fun expectOnSetLimit(iface: String?, quotaBytes: Long, timeout: Long = defaultTimeoutMs) { From 7dc43667f020b36bfd3515382b0fe0ebdf184ead Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Tue, 22 Jun 2021 13:15:21 +0000 Subject: [PATCH 226/777] Add fall back to createTunInterface when running on R TNM.createTunInterface() takes different parameter from S. GTS is multi-release, so it should be compatible with S and before S build. Add sdk version check to support it. Bug: 186680038 Test: atest GtsNetworkStackHostTestCases:\ com.google.android.gts.networkstack.NetworkStackHostTest#\ testNetworkStack Original-Change: https://android-review.googlesource.com/1742033 Merged-In: I5a08068db43e507637a53a32c15a5eb453d50c32 Change-Id: I5a08068db43e507637a53a32c15a5eb453d50c32 --- staticlibs/testutils/Android.bp | 1 + .../devicetests/com/android/testutils/TestNetworkTracker.kt | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index 1a7b4375e0..d29c1cd9a2 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -35,6 +35,7 @@ java_library { "libnanohttpd", "net-tests-utils-host-device-common", "net-utils-device-common", + "modules-utils-build_system", ], } diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt index d8dd67a345..36c09ce645 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt @@ -26,6 +26,7 @@ import android.net.NetworkRequest import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.os.Binder +import com.android.modules.utils.build.SdkLevel.isAtLeastS import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit @@ -39,7 +40,8 @@ import java.util.concurrent.TimeUnit fun initTestNetwork(context: Context, interfaceAddr: LinkAddress, setupTimeoutMs: Long = 10_000L): TestNetworkTracker { val tnm = context.getSystemService(TestNetworkManager::class.java) - val iface = tnm.createTunInterface(arrayOf(interfaceAddr)) + val iface = if (isAtLeastS()) tnm.createTunInterface(listOf(interfaceAddr)) + else tnm.createTunInterface(arrayOf(interfaceAddr)) return TestNetworkTracker(context, iface, tnm, setupTimeoutMs) } From a7ace49440b4a0168fa9bc019a231198d9f35fb1 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 22 Jun 2021 01:21:24 +0000 Subject: [PATCH 227/777] Add OnSetWarningAndLimit into TestableNetworkStatsProvider This change also address left comments at ag/15010113. Test: m gts && atest \ GtsNetworkStackHostTestCases:NetworkStatsHostTest#testNetworkStatsProvider Bug: 191327585 Merged-In: I100668cc6d4cecbaff29d027d37d313dd48854f3 Change-Id: I100668cc6d4cecbaff29d027d37d313dd48854f3 (cherry-picked from ag/15061296) --- .../testutils/TestableNetworkStatsProvider.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt index d034a7d509..8477151b7e 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt @@ -30,7 +30,12 @@ open class TestableNetworkStatsProvider( ) : NetworkStatsProvider() { sealed class CallbackType { data class OnRequestStatsUpdate(val token: Int) : CallbackType() - data class OnSetLimit(val iface: String?, val quotaBytes: Long) : CallbackType() + data class OnSetWarningAndLimit( + val iface: String?, + val warningBytes: Long, + val limitBytes: Long + ) : CallbackType() + data class OnSetLimit(val iface: String?, val limitBytes: Long) : CallbackType() data class OnSetAlert(val quotaBytes: Long) : CallbackType() } @@ -42,6 +47,10 @@ open class TestableNetworkStatsProvider( history.add(CallbackType.OnRequestStatsUpdate(token)) } + override fun onSetWarningAndLimit(iface: String, warningBytes: Long, limitBytes: Long) { + history.add(CallbackType.OnSetWarningAndLimit(iface, warningBytes, limitBytes)) + } + override fun onSetLimit(iface: String, quotaBytes: Long) { history.add(CallbackType.OnSetLimit(iface, quotaBytes)) } @@ -56,7 +65,7 @@ open class TestableNetworkStatsProvider( if (token != TOKEN_ANY) { assertEquals(token, event.token) } - return token + return event.token } fun expectOnSetLimit(iface: String?, quotaBytes: Long, timeout: Long = defaultTimeoutMs) { From 34db409225692f966961615f30759f57b21f4dd9 Mon Sep 17 00:00:00 2001 From: Dennis Liao Date: Thu, 24 Jun 2021 06:24:07 +0000 Subject: [PATCH 228/777] Revert "Add OnSetWarningAndLimit into TestableNetworkStatsProvider" This reverts commit d44e8af26a04fb0b8d73483d7a777cfa94888809. Reason for revert: DroidMonitor-triggered revert due to breakage https://android-build.googleplex.com/builds/quarterdeck?branch=git_rvc-qpr-dev-plus-aosp&target=test_suites_x86_64&lkgb=7487730&lkbb=7488089&fkbb=7487865, bug b/191937497 Change-Id: I21bfa4c481db4e5e5e038a5dd4de432f879aca57 --- .../testutils/TestableNetworkStatsProvider.kt | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt index 8477151b7e..d034a7d509 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt @@ -30,12 +30,7 @@ open class TestableNetworkStatsProvider( ) : NetworkStatsProvider() { sealed class CallbackType { data class OnRequestStatsUpdate(val token: Int) : CallbackType() - data class OnSetWarningAndLimit( - val iface: String?, - val warningBytes: Long, - val limitBytes: Long - ) : CallbackType() - data class OnSetLimit(val iface: String?, val limitBytes: Long) : CallbackType() + data class OnSetLimit(val iface: String?, val quotaBytes: Long) : CallbackType() data class OnSetAlert(val quotaBytes: Long) : CallbackType() } @@ -47,10 +42,6 @@ open class TestableNetworkStatsProvider( history.add(CallbackType.OnRequestStatsUpdate(token)) } - override fun onSetWarningAndLimit(iface: String, warningBytes: Long, limitBytes: Long) { - history.add(CallbackType.OnSetWarningAndLimit(iface, warningBytes, limitBytes)) - } - override fun onSetLimit(iface: String, quotaBytes: Long) { history.add(CallbackType.OnSetLimit(iface, quotaBytes)) } @@ -65,7 +56,7 @@ open class TestableNetworkStatsProvider( if (token != TOKEN_ANY) { assertEquals(token, event.token) } - return event.token + return token } fun expectOnSetLimit(iface: String?, quotaBytes: Long, timeout: Long = defaultTimeoutMs) { From 83c7537a180169a51569e08bd0a5aabe3cbd78f8 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 24 Jun 2021 17:44:46 +0900 Subject: [PATCH 229/777] Use module util HexDump in StructTest The hidden API HexDump causes issues, as coverage tests jarjar its package even though it is a dependency on a hidden platform class, and not included in test packages. Use the HexDump utility in the com.android.net.module.util package instead (no import is necessary as this is the same package). Bug: 187935317 Test: atest StructTest Change-Id: If319a3c20a750c890f8400f1a7104462b41ed556 --- .../tests/unit/src/com/android/net/module/util/StructTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java index df74398fe1..eabc14b4bf 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java @@ -31,7 +31,6 @@ import android.net.MacAddress; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.internal.util.HexDump; import com.android.net.module.util.Struct.Field; import com.android.net.module.util.Struct.Type; From 87e88884b3fc3cca97189c28d8e3ba04f1f4c1a3 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 25 Jun 2021 18:09:31 +0900 Subject: [PATCH 230/777] Support legacy limit reached callback Add a callback entry for the older notifyLimitReached callback, that is used on R devices. Bug: 182962001 Test: atest OffloadControllerTest Change-Id: Ic3c40eeb72b58ff1514f35be8e030a1dd9ba95d7 --- .../testutils/TestableNetworkStatsProviderCbBinder.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt index f15f610b5a..c039cad174 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt @@ -32,6 +32,7 @@ open class TestableNetworkStatsProviderCbBinder : NetworkStatsProviderCbStubComp val uidStats: NetworkStats ) : CallbackType() object NotifyWarningOrLimitReached : CallbackType() + object LegacyNotifyLimitReached : CallbackType() object NotifyAlertReached : CallbackType() object Unregister : CallbackType() } @@ -46,6 +47,11 @@ open class TestableNetworkStatsProviderCbBinder : NetworkStatsProviderCbStubComp history.add(CallbackType.NotifyWarningOrLimitReached) } + override fun notifyLimitReached() { + // Older callback renamed to notifyWarningOrLimitReached in S + history.add(CallbackType.LegacyNotifyLimitReached) + } + override fun notifyAlertReached() { history.add(CallbackType.NotifyAlertReached) } @@ -72,6 +78,9 @@ open class TestableNetworkStatsProviderCbBinder : NetworkStatsProviderCbStubComp fun expectNotifyWarningOrLimitReached() = assertEquals(CallbackType.NotifyWarningOrLimitReached, history.poll(DEFAULT_TIMEOUT_MS)) + fun expectLegacyNotifyLimitReached() = + assertEquals(CallbackType.LegacyNotifyLimitReached, history.poll(DEFAULT_TIMEOUT_MS)) + fun expectNotifyAlertReached() = assertEquals(CallbackType.NotifyAlertReached, history.poll(DEFAULT_TIMEOUT_MS)) From ce1deef731bf6cdb9f5781a6a2d2d98ba0e076f5 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 21 Jun 2021 13:36:05 +0000 Subject: [PATCH 231/777] Add visibility for Connectivity tests Allow all Connectivity test subpackages to use the targets, so that the visibility does not need to be updated when test suites are reorganized inside Connectivity. Bug: 187935317 Test: m Original-Change: https://android-review.googlesource.com/1730122 Merged-In: I99d1ec954ebe313e553443a9f081d54d7a5f12c1 Change-Id: I99d1ec954ebe313e553443a9f081d54d7a5f12c1 --- staticlibs/client-libs/tests/unit/Android.bp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/staticlibs/client-libs/tests/unit/Android.bp b/staticlibs/client-libs/tests/unit/Android.bp index 2cd39bdcd6..220a6c1904 100644 --- a/staticlibs/client-libs/tests/unit/Android.bp +++ b/staticlibs/client-libs/tests/unit/Android.bp @@ -23,7 +23,8 @@ android_library { // Visible for Tethering and NetworkStack integration test and link NetdStaticLibTestsLib // there, so that the tests under client-libs can also be run when running tethering and // NetworkStack MTS. - "//packages/modules/Connectivity/Tethering/tests/integration", + "//packages/modules/Connectivity/tests:__subpackages__", + "//packages/modules/Connectivity/Tethering/tests:__subpackages__", "//packages/modules/NetworkStack/tests/integration", ] } From a75bb6d0be076f342773df00058378e18476856d Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 21 Jun 2021 13:36:05 +0000 Subject: [PATCH 232/777] Add visibility for Connectivity tests Allow all Connectivity test subpackages to use the targets, so that the visibility does not need to be updated when test suites are reorganized inside Connectivity. Bug: 187935317 Test: m Original-Change: https://android-review.googlesource.com/1730122 Merged-In: I99d1ec954ebe313e553443a9f081d54d7a5f12c1 Change-Id: I99d1ec954ebe313e553443a9f081d54d7a5f12c1 --- staticlibs/tests/unit/Android.bp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index c9aad71035..23835fe918 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -24,7 +24,8 @@ android_library { ], visibility: [ "//frameworks/base/packages/Tethering/tests/integration", - "//packages/modules/Connectivity/Tethering/tests/integration", + "//packages/modules/Connectivity/tests:__subpackages__", + "//packages/modules/Connectivity/Tethering/tests:__subpackages__", "//packages/modules/NetworkStack/tests/integration", ] } From 7592a34dc91b14994ee6f810e7daab685a2d8bc6 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 19 Apr 2021 18:04:34 +0900 Subject: [PATCH 233/777] Support both R and S+ in NetworkFactory NetworkFactory needs to be backwards compatible as it is statically linked by the Wifi module, which needs to run on both R and S. To achieve this, maintain 2 separate implementations called NetworkFactoryImpl (S+) and NetworkFactoryLegacyImpl (R). NetworkFactory itself becomes a shim that delegates to one of these implementations depending on the device's SDK version. CP of ag/14265947 Ignore-AOSP-First: Merge in internal first to fix S-on-R test breakages. Bug: 183902758 Test: ClientModeImplTest OemWifiNetworkFactoryTest TelephonyNetworkFactoryTest UntrustedWifiNetworkFactoryTest WifiNetworkFactoryTest Change-Id: I6a08f39ad1633dd7c1582c362c97821e24ce6683 Merged-In: I6a08f39ad1633dd7c1582c362c97821e24ce6683 --- staticlibs/Android.bp | 19 +- .../device/android/net/NetworkFactory.java | 303 +++---------- .../android/net/NetworkFactoryImpl.java | 323 ++++++++++++++ .../android/net/NetworkFactoryLegacyImpl.java | 398 ++++++++++++++++++ .../android/net/NetworkFactoryShim.java | 71 ++++ staticlibs/jarjar-rules-shared.txt | 1 + 6 files changed, 855 insertions(+), 260 deletions(-) create mode 100644 staticlibs/device/android/net/NetworkFactoryImpl.java create mode 100644 staticlibs/device/android/net/NetworkFactoryLegacyImpl.java create mode 100644 staticlibs/device/android/net/NetworkFactoryShim.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index f3b2faa76f..1371c8ccf3 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -34,9 +34,9 @@ package { java_library { name: "net-utils-device-common", srcs: [ - "device/**/*.java", + "device/com/android/net/module/util/**/*.java", // This library is used by system modules, for which the system health impact of Kotlin - // has not yet been evaluated. + // has not yet been evaluated. Annotations may need jarjar'ing. // "src_devicecommon/**/*.kt", ":framework-annotations", ], @@ -117,13 +117,15 @@ java_library { "//frameworks/libs/net/common/tests:__subpackages__", "//frameworks/libs/net/common/device", "//packages/modules/Wifi/framework/tests:__subpackages__", - ] + ], } - filegroup { name: "net-utils-services-common-srcs", srcs: [ "device/android/net/NetworkFactory.java", + "device/android/net/NetworkFactoryImpl.java", + "device/android/net/NetworkFactoryLegacyImpl.java", + "device/android/net/NetworkFactoryShim.java", ], visibility: [ "//frameworks/base/services/net", @@ -138,6 +140,9 @@ java_library { ], sdk_version: "system_current", min_sdk_version: "30", + static_libs: [ + "modules-utils-build_system", + ], visibility: [ "//frameworks/base/services/net", ], @@ -150,6 +155,9 @@ filegroup { srcs: [ // Any class here *must* have a corresponding jarjar rule in the telephony build rules. "device/android/net/NetworkFactory.java", + "device/android/net/NetworkFactoryImpl.java", + "device/android/net/NetworkFactoryLegacyImpl.java", + "device/android/net/NetworkFactoryShim.java", ], path: "device", visibility: [ @@ -178,6 +186,9 @@ filegroup { name: "net-utils-wifi-service-common-srcs", srcs: [ "device/android/net/NetworkFactory.java", + "device/android/net/NetworkFactoryImpl.java", + "device/android/net/NetworkFactoryLegacyImpl.java", + "device/android/net/NetworkFactoryShim.java", "framework/com/android/net/module/util/NetUtils.java", ], visibility: [ diff --git a/staticlibs/device/android/net/NetworkFactory.java b/staticlibs/device/android/net/NetworkFactory.java index 50cecdead0..87f6dee6ec 100644 --- a/staticlibs/device/android/net/NetworkFactory.java +++ b/staticlibs/device/android/net/NetworkFactory.java @@ -16,11 +16,11 @@ package android.net; +import static com.android.modules.utils.build.SdkLevel.isAtLeastS; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; -import android.net.NetworkProvider.NetworkOfferCallback; -import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; @@ -29,9 +29,6 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.concurrent.Executor; /** * A NetworkFactory is an entity that creates NetworkAgent objects. @@ -46,109 +43,54 @@ import java.util.concurrent.Executor; * functions can be overridden. If the bearer needs more interaction, it can * override addNetworkRequest and removeNetworkRequest which will give it each * request that passes their current filters. + * + * This class is mostly a shim which delegates to one of two implementations depending + * on the SDK level of the device it's running on. + * * @hide **/ -public class NetworkFactory extends Handler { - private static final boolean DBG = true; - private static final boolean VDBG = false; +public class NetworkFactory { + static final boolean DBG = true; + static final boolean VDBG = false; - // A score that will win against everything, so that score filtering will let all requests - // through - // TODO : remove this and replace with an API to listen to all requests. - @NonNull - private static final NetworkScore INVINCIBLE_SCORE = - new NetworkScore.Builder().setLegacyInt(1000).build(); + final NetworkFactoryShim mImpl; - /** - * Pass a network request to the bearer. If the bearer believes it can - * satisfy the request it should connect to the network and create a - * NetworkAgent. Once the NetworkAgent is fully functional it will - * register itself with ConnectivityService using registerNetworkAgent. - * If the bearer cannot immediately satisfy the request (no network, - * user disabled the radio, lower-scored network) it should remember - * any NetworkRequests it may be able to satisfy in the future. It may - * disregard any that it will never be able to service, for example - * those requiring a different bearer. - * msg.obj = NetworkRequest - */ - // TODO : this and CANCEL_REQUEST are only used by telephony tests. Replace it in the tests - // and remove them and the associated code. - public static final int CMD_REQUEST_NETWORK = 1; - - /** - * Cancel a network request - * msg.obj = NetworkRequest - */ - public static final int CMD_CANCEL_REQUEST = 2; - - /** - * Internally used to set our best-guess score. - * msg.obj = new score - */ - private static final int CMD_SET_SCORE = 3; - - /** - * Internally used to set our current filter for coarse bandwidth changes with - * technology changes. - * msg.obj = new filter - */ - private static final int CMD_SET_FILTER = 4; - - /** - * Internally used to send the network offer associated with this factory. - * No arguments, will read from members - */ - private static final int CMD_OFFER_NETWORK = 5; - - /** - * Internally used to send the request to listen to all requests. - * No arguments, will read from members - */ - private static final int CMD_LISTEN_TO_ALL_REQUESTS = 6; - - private final Context mContext; private final String LOG_TAG; - private final Map mNetworkRequests = - new LinkedHashMap<>(); - - @NonNull private NetworkScore mScore = new NetworkScore.Builder().setLegacyInt(0).build(); - @NonNull private NetworkCapabilities mCapabilityFilter; - - private int mRefCount = 0; - private NetworkProvider mProvider = null; - - private final NetworkOfferCallback mRequestCallback = new NetworkOfferCallback() { - @Override - public void onNetworkNeeded(@NonNull final NetworkRequest request) { - handleAddRequest(request); - } - - @Override - public void onNetworkUnneeded(@NonNull final NetworkRequest request) { - handleRemoveRequest(request); - } - }; - @NonNull private final Executor mExecutor = command -> post(command); - // Ideally the filter argument would be non-null, but null has historically meant to see // no requests and telephony passes null. public NetworkFactory(Looper looper, Context context, String logTag, @Nullable final NetworkCapabilities filter) { - super(looper); LOG_TAG = logTag; - mContext = context; - if (null != filter) { - mCapabilityFilter = filter; + if (isAtLeastS()) { + mImpl = new NetworkFactoryImpl(this, looper, context, filter); } else { - mCapabilityFilter = new NetworkCapabilities.Builder() - .withoutDefaultCapabilities().build(); + mImpl = new NetworkFactoryLegacyImpl(this, looper, context, filter); } } + // TODO : these two constants and the method are only used by telephony tests. Replace it in + // the tests and remove them and the associated code. + public static final int CMD_REQUEST_NETWORK = 1; + public static final int CMD_CANCEL_REQUEST = 2; + /** Like Handler#obtainMessage */ + @VisibleForTesting + public Message obtainMessage(final int what, final int arg1, final int arg2, + final @Nullable Object obj) { + return mImpl.obtainMessage(what, arg1, arg2, obj); + } + + // Called by BluetoothNetworkFactory + public final Looper getLooper() { + return mImpl.getLooper(); + } + + // Refcount for simple mode requests + private int mRefCount = 0; + /* Registers this NetworkFactory with the system. May only be called once per factory. */ public void register() { - register(false); + mImpl.register(LOG_TAG); } /** @@ -157,152 +99,16 @@ public class NetworkFactory extends Handler { * May only be called once per factory. */ public void registerIgnoringScore() { - register(true); - } - - private void register(final boolean listenToAllRequests) { - if (mProvider != null) { - throw new IllegalStateException("A NetworkFactory must only be registered once"); - } - if (DBG) log("Registering NetworkFactory"); - - mProvider = new NetworkProvider(mContext, NetworkFactory.this.getLooper(), LOG_TAG) { - @Override - public void onNetworkRequested(@NonNull NetworkRequest request, int score, - int servingProviderId) { - handleAddRequest(request); - } - - @Override - public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { - handleRemoveRequest(request); - } - }; - - ((ConnectivityManager) mContext.getSystemService( - Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); - - // The mScore and mCapabilityFilter members can only be accessed on the handler thread. - // TODO : offer a separate API to listen to all requests instead - if (listenToAllRequests) { - sendMessage(obtainMessage(CMD_LISTEN_TO_ALL_REQUESTS)); - } else { - sendMessage(obtainMessage(CMD_OFFER_NETWORK)); - } - } - - private void handleOfferNetwork(@NonNull final NetworkScore score) { - mProvider.registerNetworkOffer(score, mCapabilityFilter, mExecutor, mRequestCallback); + mImpl.registerIgnoringScore(LOG_TAG); } /** Unregisters this NetworkFactory. After this call, the object can no longer be used. */ public void terminate() { - if (mProvider == null) { - throw new IllegalStateException("This NetworkFactory was never registered"); - } - if (DBG) log("Unregistering NetworkFactory"); - - ((ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) - .unregisterNetworkProvider(mProvider); - - // Remove all pending messages, since this object cannot be reused. Any message currently - // being processed will continue to run. - removeCallbacksAndMessages(null); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case CMD_REQUEST_NETWORK: { - handleAddRequest((NetworkRequest) msg.obj); - break; - } - case CMD_CANCEL_REQUEST: { - handleRemoveRequest((NetworkRequest) msg.obj); - break; - } - case CMD_SET_SCORE: { - handleSetScore((NetworkScore) msg.obj); - break; - } - case CMD_SET_FILTER: { - handleSetFilter((NetworkCapabilities) msg.obj); - break; - } - case CMD_OFFER_NETWORK: { - handleOfferNetwork(mScore); - break; - } - case CMD_LISTEN_TO_ALL_REQUESTS: { - handleOfferNetwork(INVINCIBLE_SCORE); - break; - } - } - } - - private static class NetworkRequestInfo { - @NonNull public final NetworkRequest request; - public boolean requested; // do we have a request outstanding, limited by score - - NetworkRequestInfo(@NonNull final NetworkRequest request) { - this.request = request; - this.requested = false; - } - - @Override - public String toString() { - return "{" + request + ", requested=" + requested + "}"; - } - } - - /** - * Add a NetworkRequest that the bearer may want to attempt to satisfy. - * @see #CMD_REQUEST_NETWORK - * - * @param request the request to handle. - */ - private void handleAddRequest(@NonNull final NetworkRequest request) { - NetworkRequestInfo n = mNetworkRequests.get(request); - if (n == null) { - if (DBG) log("got request " + request); - n = new NetworkRequestInfo(request); - mNetworkRequests.put(n.request, n); - } else { - if (VDBG) { - log("handle existing request " + request); - } - } - if (VDBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); - - if (acceptRequest(request)) { - n.requested = true; - needNetworkFor(request); - } - } - - private void handleRemoveRequest(NetworkRequest request) { - NetworkRequestInfo n = mNetworkRequests.get(request); - if (n != null) { - mNetworkRequests.remove(request); - if (n.requested) releaseNetworkFor(n.request); - } - } - - private void handleSetScore(@NonNull final NetworkScore score) { - if (mScore.equals(score)) return; - mScore = score; - reevaluateAllRequests(); - } - - private void handleSetFilter(@NonNull final NetworkCapabilities netCap) { - if (netCap.equals(mCapabilityFilter)) return; - mCapabilityFilter = netCap; - reevaluateAllRequests(); + mImpl.terminate(); } protected final void reevaluateAllRequests() { - if (mProvider == null) return; - mProvider.registerNetworkOffer(mScore, mCapabilityFilter, mExecutor, mRequestCallback); + mImpl.reevaluateAllRequests(); } /** @@ -327,6 +133,7 @@ public class NetworkFactory extends Handler { public boolean acceptRequest(@NonNull final NetworkRequest request) { return true; } + /** * Can be called by a factory to release a request as unfulfillable: the request will be * removed, and the caller will get a @@ -337,15 +144,7 @@ public class NetworkFactory extends Handler { * is able to fulfill this request! */ protected void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) { - post(() -> { - if (DBG) log("releaseRequestAsUnfulfillableByAnyFactory: " + r); - final NetworkProvider provider = mProvider; - if (provider == null) { - Log.e(LOG_TAG, "Ignoring attempt to release unregistered request as unfulfillable"); - return; - } - provider.declareNetworkRequestUnfulfillable(r); - }); + mImpl.releaseRequestAsUnfulfillableByAnyFactory(r); } // override to do simple mode (request independent) @@ -363,11 +162,11 @@ public class NetworkFactory extends Handler { /** * @deprecated this method was never part of the API (system or public) and is only added - * for migration of existing clients. It will be removed before S ships. + * for migration of existing clients. */ @Deprecated public void setScoreFilter(final int score) { - setScoreFilter(new NetworkScore.Builder().setLegacyInt(score).build()); + mImpl.setScoreFilter(score); } /** @@ -381,25 +180,24 @@ public class NetworkFactory extends Handler { * @param score the filter */ public void setScoreFilter(@NonNull final NetworkScore score) { - sendMessage(obtainMessage(CMD_SET_SCORE, score)); + mImpl.setScoreFilter(score); } public void setCapabilityFilter(NetworkCapabilities netCap) { - sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); + mImpl.setCapabilityFilter(netCap); } @VisibleForTesting protected int getRequestCount() { - return mNetworkRequests.size(); + return mImpl.getRequestCount(); } - /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ public int getSerialNumber() { - return mProvider.getProviderId(); + return mImpl.getSerialNumber(); } public NetworkProvider getProvider() { - return mProvider; + return mImpl.getProvider(); } protected void log(String s) { @@ -407,18 +205,11 @@ public class NetworkFactory extends Handler { } public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - writer.println(toString()); - for (NetworkRequestInfo n : mNetworkRequests.values()) { - writer.println(" " + n); - } + mImpl.dump(fd, writer, args); } @Override public String toString() { - return "{" + LOG_TAG + " - providerId=" - + mProvider.getProviderId() + ", ScoreFilter=" - + mScore + ", Filter=" + mCapabilityFilter + ", requests=" - + mNetworkRequests.size() + ", refCount=" + mRefCount - + "}"; + return "{" + LOG_TAG + " " + mImpl.toString() + "}"; } } diff --git a/staticlibs/device/android/net/NetworkFactoryImpl.java b/staticlibs/device/android/net/NetworkFactoryImpl.java new file mode 100644 index 0000000000..1b7ea936b3 --- /dev/null +++ b/staticlibs/device/android/net/NetworkFactoryImpl.java @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2021 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 android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.net.NetworkProvider.NetworkOfferCallback; +import android.os.Looper; +import android.os.Message; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.Executor; + +/** + * A NetworkFactory is an entity that creates NetworkAgent objects. + * The bearers register with ConnectivityService using {@link #register} and + * their factory will start receiving scored NetworkRequests. NetworkRequests + * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by + * overridden function. All of these can be dynamic - changing NetworkCapabilities + * or score forces re-evaluation of all current requests. + * + * If any requests pass the filter some overrideable functions will be called. + * If the bearer only cares about very simple start/stopNetwork callbacks, those + * functions can be overridden. If the bearer needs more interaction, it can + * override addNetworkRequest and removeNetworkRequest which will give it each + * request that passes their current filters. + * @hide + **/ +// TODO(b/187083878): factor out common code between this and NetworkFactoryLegacyImpl +class NetworkFactoryImpl extends NetworkFactoryLegacyImpl { + private static final boolean DBG = NetworkFactory.DBG; + private static final boolean VDBG = NetworkFactory.VDBG; + + // A score that will win against everything, so that score filtering will let all requests + // through + // TODO : remove this and replace with an API to listen to all requests. + @NonNull + private static final NetworkScore INVINCIBLE_SCORE = + new NetworkScore.Builder().setLegacyInt(1000).build(); + + // TODO(b/187082970): Replace CMD_* with Handler.post(() -> { ... }) since all the CMDs do is to + // run the tasks asynchronously on the Handler thread. + + /** + * Pass a network request to the bearer. If the bearer believes it can + * satisfy the request it should connect to the network and create a + * NetworkAgent. Once the NetworkAgent is fully functional it will + * register itself with ConnectivityService using registerNetworkAgent. + * If the bearer cannot immediately satisfy the request (no network, + * user disabled the radio, lower-scored network) it should remember + * any NetworkRequests it may be able to satisfy in the future. It may + * disregard any that it will never be able to service, for example + * those requiring a different bearer. + * msg.obj = NetworkRequest + */ + // TODO : this and CANCEL_REQUEST are only used by telephony tests. Replace it in the tests + // and remove them and the associated code. + private static final int CMD_REQUEST_NETWORK = NetworkFactory.CMD_REQUEST_NETWORK; + + /** + * Cancel a network request + * msg.obj = NetworkRequest + */ + private static final int CMD_CANCEL_REQUEST = NetworkFactory.CMD_CANCEL_REQUEST; + + /** + * Internally used to set our best-guess score. + * msg.obj = new score + */ + private static final int CMD_SET_SCORE = 3; + + /** + * Internally used to set our current filter for coarse bandwidth changes with + * technology changes. + * msg.obj = new filter + */ + private static final int CMD_SET_FILTER = 4; + + /** + * Internally used to send the network offer associated with this factory. + * No arguments, will read from members + */ + private static final int CMD_OFFER_NETWORK = 5; + + /** + * Internally used to send the request to listen to all requests. + * No arguments, will read from members + */ + private static final int CMD_LISTEN_TO_ALL_REQUESTS = 6; + + private final Map mNetworkRequests = + new LinkedHashMap<>(); + + @NonNull private NetworkScore mScore = new NetworkScore.Builder().setLegacyInt(0).build(); + + private final NetworkOfferCallback mRequestCallback = new NetworkOfferCallback() { + @Override + public void onNetworkNeeded(@NonNull final NetworkRequest request) { + handleAddRequest(request); + } + + @Override + public void onNetworkUnneeded(@NonNull final NetworkRequest request) { + handleRemoveRequest(request); + } + }; + @NonNull private final Executor mExecutor = command -> post(command); + + + // Ideally the filter argument would be non-null, but null has historically meant to see + // no requests and telephony passes null. + NetworkFactoryImpl(NetworkFactory parent, Looper looper, Context context, + @Nullable final NetworkCapabilities filter) { + super(parent, looper, context, + null != filter ? filter : + new NetworkCapabilities.Builder().withoutDefaultCapabilities().build()); + } + + /* Registers this NetworkFactory with the system. May only be called once per factory. */ + @Override public void register(final String logTag) { + register(logTag, false); + } + + /** + * Registers this NetworkFactory with the system ignoring the score filter. This will let + * the factory always see all network requests matching its capabilities filter. + * May only be called once per factory. + */ + @Override public void registerIgnoringScore(final String logTag) { + register(logTag, true); + } + + private void register(final String logTag, final boolean listenToAllRequests) { + if (mProvider != null) { + throw new IllegalStateException("A NetworkFactory must only be registered once"); + } + if (DBG) mParent.log("Registering NetworkFactory"); + + mProvider = new NetworkProvider(mContext, NetworkFactoryImpl.this.getLooper(), logTag) { + @Override + public void onNetworkRequested(@NonNull NetworkRequest request, int score, + int servingProviderId) { + handleAddRequest(request); + } + + @Override + public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { + handleRemoveRequest(request); + } + }; + + ((ConnectivityManager) mContext.getSystemService( + Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); + + // The mScore and mCapabilityFilter members can only be accessed on the handler thread. + // TODO : offer a separate API to listen to all requests instead + if (listenToAllRequests) { + sendMessage(obtainMessage(CMD_LISTEN_TO_ALL_REQUESTS)); + } else { + sendMessage(obtainMessage(CMD_OFFER_NETWORK)); + } + } + + private void handleOfferNetwork(@NonNull final NetworkScore score) { + mProvider.registerNetworkOffer(score, mCapabilityFilter, mExecutor, mRequestCallback); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case CMD_REQUEST_NETWORK: { + handleAddRequest((NetworkRequest) msg.obj); + break; + } + case CMD_CANCEL_REQUEST: { + handleRemoveRequest((NetworkRequest) msg.obj); + break; + } + case CMD_SET_SCORE: { + handleSetScore((NetworkScore) msg.obj); + break; + } + case CMD_SET_FILTER: { + handleSetFilter((NetworkCapabilities) msg.obj); + break; + } + case CMD_OFFER_NETWORK: { + handleOfferNetwork(mScore); + break; + } + case CMD_LISTEN_TO_ALL_REQUESTS: { + handleOfferNetwork(INVINCIBLE_SCORE); + break; + } + } + } + + private static class NetworkRequestInfo { + @NonNull public final NetworkRequest request; + public boolean requested; // do we have a request outstanding, limited by score + + NetworkRequestInfo(@NonNull final NetworkRequest request) { + this.request = request; + this.requested = false; + } + + @Override + public String toString() { + return "{" + request + ", requested=" + requested + "}"; + } + } + + /** + * Add a NetworkRequest that the bearer may want to attempt to satisfy. + * @see #CMD_REQUEST_NETWORK + * + * @param request the request to handle. + */ + private void handleAddRequest(@NonNull final NetworkRequest request) { + NetworkRequestInfo n = mNetworkRequests.get(request); + if (n == null) { + if (DBG) mParent.log("got request " + request); + n = new NetworkRequestInfo(request); + mNetworkRequests.put(n.request, n); + } else { + if (VDBG) mParent.log("handle existing request " + request); + } + if (VDBG) mParent.log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); + + if (mParent.acceptRequest(request)) { + n.requested = true; + mParent.needNetworkFor(request); + } + } + + private void handleRemoveRequest(NetworkRequest request) { + NetworkRequestInfo n = mNetworkRequests.get(request); + if (n != null) { + mNetworkRequests.remove(request); + if (n.requested) mParent.releaseNetworkFor(n.request); + } + } + + private void handleSetScore(@NonNull final NetworkScore score) { + if (mScore.equals(score)) return; + mScore = score; + mParent.reevaluateAllRequests(); + } + + private void handleSetFilter(@NonNull final NetworkCapabilities netCap) { + if (netCap.equals(mCapabilityFilter)) return; + mCapabilityFilter = netCap; + mParent.reevaluateAllRequests(); + } + + @Override public final void reevaluateAllRequests() { + if (mProvider == null) return; + mProvider.registerNetworkOffer(mScore, mCapabilityFilter, mExecutor, mRequestCallback); + } + + /** + * @deprecated this method was never part of the API (system or public) and is only added + * for migration of existing clients. + */ + @Deprecated + public void setScoreFilter(final int score) { + setScoreFilter(new NetworkScore.Builder().setLegacyInt(score).build()); + } + + /** + * Set a score filter for this factory. + * + * This should include the transports the factory knows its networks will have, and + * an optimistic view of the attributes it may have. This does not commit the factory + * to being able to bring up such a network ; it only lets it avoid hearing about + * requests that it has no chance of fulfilling. + * + * @param score the filter + */ + @Override public void setScoreFilter(@NonNull final NetworkScore score) { + sendMessage(obtainMessage(CMD_SET_SCORE, score)); + } + + @Override public void setCapabilityFilter(NetworkCapabilities netCap) { + sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); + } + + @Override public int getRequestCount() { + return mNetworkRequests.size(); + } + + @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + writer.println(toString()); + for (NetworkRequestInfo n : mNetworkRequests.values()) { + writer.println(" " + n); + } + } + + @Override public String toString() { + return "providerId=" + + mProvider.getProviderId() + ", ScoreFilter=" + + mScore + ", Filter=" + mCapabilityFilter + ", requests=" + + mNetworkRequests.size(); + } +} diff --git a/staticlibs/device/android/net/NetworkFactoryLegacyImpl.java b/staticlibs/device/android/net/NetworkFactoryLegacyImpl.java new file mode 100644 index 0000000000..6dd0adb0c9 --- /dev/null +++ b/staticlibs/device/android/net/NetworkFactoryLegacyImpl.java @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2021 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 android.annotation.NonNull; +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * A NetworkFactory is an entity that creates NetworkAgent objects. + * The bearers register with ConnectivityService using {@link #register} and + * their factory will start receiving scored NetworkRequests. NetworkRequests + * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by + * overridden function. All of these can be dynamic - changing NetworkCapabilities + * or score forces re-evaluation of all current requests. + * + * If any requests pass the filter some overrideable functions will be called. + * If the bearer only cares about very simple start/stopNetwork callbacks, those + * functions can be overridden. If the bearer needs more interaction, it can + * override addNetworkRequest and removeNetworkRequest which will give it each + * request that passes their current filters. + * @hide + **/ +// TODO(b/187083878): factor out common code between this and NetworkFactoryImpl +class NetworkFactoryLegacyImpl extends Handler + implements NetworkFactoryShim { + private static final boolean DBG = NetworkFactory.DBG; + private static final boolean VDBG = NetworkFactory.VDBG; + + // TODO(b/187082970): Replace CMD_* with Handler.post(() -> { ... }) since all the CMDs do is to + // run the tasks asynchronously on the Handler thread. + + /** + * Pass a network request to the bearer. If the bearer believes it can + * satisfy the request it should connect to the network and create a + * NetworkAgent. Once the NetworkAgent is fully functional it will + * register itself with ConnectivityService using registerNetworkAgent. + * If the bearer cannot immediately satisfy the request (no network, + * user disabled the radio, lower-scored network) it should remember + * any NetworkRequests it may be able to satisfy in the future. It may + * disregard any that it will never be able to service, for example + * those requiring a different bearer. + * msg.obj = NetworkRequest + * msg.arg1 = score - the score of the network currently satisfying this + * request. If this bearer knows in advance it cannot + * exceed this score it should not try to connect, holding the request + * for the future. + * Note that subsequent events may give a different (lower + * or higher) score for this request, transmitted to each + * NetworkFactory through additional CMD_REQUEST_NETWORK msgs + * with the same NetworkRequest but an updated score. + * Also, network conditions may change for this bearer + * allowing for a better score in the future. + * msg.arg2 = the ID of the NetworkProvider currently responsible for the + * NetworkAgent handling this request, or NetworkProvider.ID_NONE if none. + */ + public static final int CMD_REQUEST_NETWORK = 1; + + /** + * Cancel a network request + * msg.obj = NetworkRequest + */ + public static final int CMD_CANCEL_REQUEST = 2; + + /** + * Internally used to set our best-guess score. + * msg.arg1 = new score + */ + private static final int CMD_SET_SCORE = 3; + + /** + * Internally used to set our current filter for coarse bandwidth changes with + * technology changes. + * msg.obj = new filter + */ + private static final int CMD_SET_FILTER = 4; + + final Context mContext; + final NetworkFactory mParent; + + private final Map mNetworkRequests = + new LinkedHashMap<>(); + + private int mScore; + NetworkCapabilities mCapabilityFilter; + + NetworkProvider mProvider = null; + + NetworkFactoryLegacyImpl(NetworkFactory parent, Looper looper, Context context, + NetworkCapabilities filter) { + super(looper); + mParent = parent; + mContext = context; + mCapabilityFilter = filter; + } + + /* Registers this NetworkFactory with the system. May only be called once per factory. */ + @Override public void register(final String logTag) { + if (mProvider != null) { + throw new IllegalStateException("A NetworkFactory must only be registered once"); + } + if (DBG) mParent.log("Registering NetworkFactory"); + + mProvider = new NetworkProvider(mContext, NetworkFactoryLegacyImpl.this.getLooper(), + logTag) { + @Override + public void onNetworkRequested(@NonNull NetworkRequest request, int score, + int servingProviderId) { + handleAddRequest(request, score, servingProviderId); + } + + @Override + public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { + handleRemoveRequest(request); + } + }; + + ((ConnectivityManager) mContext.getSystemService( + Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); + } + + /** Unregisters this NetworkFactory. After this call, the object can no longer be used. */ + @Override public void terminate() { + if (mProvider == null) { + throw new IllegalStateException("This NetworkFactory was never registered"); + } + if (DBG) mParent.log("Unregistering NetworkFactory"); + + ((ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) + .unregisterNetworkProvider(mProvider); + + // Remove all pending messages, since this object cannot be reused. Any message currently + // being processed will continue to run. + removeCallbacksAndMessages(null); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case CMD_REQUEST_NETWORK: { + handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2); + break; + } + case CMD_CANCEL_REQUEST: { + handleRemoveRequest((NetworkRequest) msg.obj); + break; + } + case CMD_SET_SCORE: { + handleSetScore(msg.arg1); + break; + } + case CMD_SET_FILTER: { + handleSetFilter((NetworkCapabilities) msg.obj); + break; + } + } + } + + private static class NetworkRequestInfo { + public final NetworkRequest request; + public int score; + public boolean requested; // do we have a request outstanding, limited by score + public int providerId; + + NetworkRequestInfo(NetworkRequest request, int score, int providerId) { + this.request = request; + this.score = score; + this.requested = false; + this.providerId = providerId; + } + + @Override + public String toString() { + return "{" + request + ", score=" + score + ", requested=" + requested + "}"; + } + } + + /** + * Add a NetworkRequest that the bearer may want to attempt to satisfy. + * @see #CMD_REQUEST_NETWORK + * + * @param request the request to handle. + * @param score the score of the NetworkAgent currently satisfying this request. + * @param servingProviderId the ID of the NetworkProvider that created the NetworkAgent + * currently satisfying this request. + */ + @VisibleForTesting + protected void handleAddRequest(NetworkRequest request, int score, int servingProviderId) { + NetworkRequestInfo n = mNetworkRequests.get(request); + if (n == null) { + if (DBG) { + mParent.log("got request " + request + " with score " + score + + " and providerId " + servingProviderId); + } + n = new NetworkRequestInfo(request, score, servingProviderId); + mNetworkRequests.put(n.request, n); + } else { + if (VDBG) { + mParent.log("new score " + score + " for existing request " + request + + " and providerId " + servingProviderId); + } + n.score = score; + n.providerId = servingProviderId; + } + if (VDBG) mParent.log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); + + evalRequest(n); + } + + private void handleRemoveRequest(NetworkRequest request) { + NetworkRequestInfo n = mNetworkRequests.get(request); + if (n != null) { + mNetworkRequests.remove(request); + if (n.requested) mParent.releaseNetworkFor(n.request); + } + } + + private void handleSetScore(int score) { + mScore = score; + evalRequests(); + } + + private void handleSetFilter(NetworkCapabilities netCap) { + mCapabilityFilter = netCap; + evalRequests(); + } + + /** + * Overridable function to provide complex filtering. + * Called for every request every time a new NetworkRequest is seen + * and whenever the filterScore or filterNetworkCapabilities change. + * + * acceptRequest can be overridden to provide complex filter behavior + * for the incoming requests + * + * For output, this class will call {@link NetworkFactory#needNetworkFor} and + * {@link NetworkFactory#releaseNetworkFor} for every request that passes the filters. + * If you don't need to see every request, you can leave the base + * implementations of those two functions and instead override + * {@link NetworkFactory#startNetwork} and {@link NetworkFactory#stopNetwork}. + * + * If you want to see every score fluctuation on every request, set + * your score filter to a very high number and watch {@link NetworkFactory#needNetworkFor}. + * + * @return {@code true} to accept the request. + */ + public boolean acceptRequest(NetworkRequest request) { + return mParent.acceptRequest(request); + } + + private void evalRequest(NetworkRequestInfo n) { + if (VDBG) { + mParent.log("evalRequest"); + mParent.log(" n.requests = " + n.requested); + mParent.log(" n.score = " + n.score); + mParent.log(" mScore = " + mScore); + mParent.log(" request.providerId = " + n.providerId); + mParent.log(" mProvider.id = " + mProvider.getProviderId()); + } + if (shouldNeedNetworkFor(n)) { + if (VDBG) mParent.log(" needNetworkFor"); + mParent.needNetworkFor(n.request); + n.requested = true; + } else if (shouldReleaseNetworkFor(n)) { + if (VDBG) mParent.log(" releaseNetworkFor"); + mParent.releaseNetworkFor(n.request); + n.requested = false; + } else { + if (VDBG) mParent.log(" done"); + } + } + + private boolean shouldNeedNetworkFor(NetworkRequestInfo n) { + // If this request is already tracked, it doesn't qualify for need + return !n.requested + // If the score of this request is higher or equal to that of this factory and some + // other factory is responsible for it, then this factory should not track the request + // because it has no hope of satisfying it. + && (n.score < mScore || n.providerId == mProvider.getProviderId()) + // If this factory can't satisfy the capability needs of this request, then it + // should not be tracked. + && n.request.canBeSatisfiedBy(mCapabilityFilter) + // Finally if the concrete implementation of the factory rejects the request, then + // don't track it. + && acceptRequest(n.request); + } + + private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) { + // Don't release a request that's not tracked. + return n.requested + // The request should be released if it can't be satisfied by this factory. That + // means either of the following conditions are met : + // - Its score is too high to be satisfied by this factory and it's not already + // assigned to the factory + // - This factory can't satisfy the capability needs of the request + // - The concrete implementation of the factory rejects the request + && ((n.score > mScore && n.providerId != mProvider.getProviderId()) + || !n.request.canBeSatisfiedBy(mCapabilityFilter) + || !acceptRequest(n.request)); + } + + private void evalRequests() { + for (NetworkRequestInfo n : mNetworkRequests.values()) { + evalRequest(n); + } + } + + /** + * Post a command, on this NetworkFactory Handler, to re-evaluate all + * outstanding requests. Can be called from a factory implementation. + */ + @Override public void reevaluateAllRequests() { + post(this::evalRequests); + } + + /** + * Can be called by a factory to release a request as unfulfillable: the request will be + * removed, and the caller will get a + * {@link ConnectivityManager.NetworkCallback#onUnavailable()} callback after this function + * returns. + * + * Note: this should only be called by factory which KNOWS that it is the ONLY factory which + * is able to fulfill this request! + */ + @Override public void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) { + post(() -> { + if (DBG) mParent.log("releaseRequestAsUnfulfillableByAnyFactory: " + r); + final NetworkProvider provider = mProvider; + if (provider == null) { + mParent.log("Ignoring attempt to release unregistered request as unfulfillable"); + return; + } + provider.declareNetworkRequestUnfulfillable(r); + }); + } + + @Override public void setScoreFilter(int score) { + sendMessage(obtainMessage(CMD_SET_SCORE, score, 0)); + } + + @Override public void setScoreFilter(@NonNull final NetworkScore score) { + setScoreFilter(score.getLegacyInt()); + } + + @Override public void setCapabilityFilter(NetworkCapabilities netCap) { + sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); + } + + @Override public int getRequestCount() { + return mNetworkRequests.size(); + } + + /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ + @Override public int getSerialNumber() { + return mProvider.getProviderId(); + } + + @Override public NetworkProvider getProvider() { + return mProvider; + } + + @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + writer.println(toString()); + for (NetworkRequestInfo n : mNetworkRequests.values()) { + writer.println(" " + n); + } + } + + @Override public String toString() { + return "providerId=" + + mProvider.getProviderId() + ", ScoreFilter=" + + mScore + ", Filter=" + mCapabilityFilter + ", requests=" + + mNetworkRequests.size(); + } +} diff --git a/staticlibs/device/android/net/NetworkFactoryShim.java b/staticlibs/device/android/net/NetworkFactoryShim.java new file mode 100644 index 0000000000..dfbb5ec104 --- /dev/null +++ b/staticlibs/device/android/net/NetworkFactoryShim.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2021 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 android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Looper; +import android.os.Message; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +/** + * Extract an interface for multiple implementation of {@link NetworkFactory}, depending on the SDK + * version. + * + * Known implementations: + * - {@link NetworkFactoryImpl}: For Android S+ + * - {@link NetworkFactoryLegacyImpl}: For Android R- + * + * @hide + */ +interface NetworkFactoryShim { + void register(String logTag); + + default void registerIgnoringScore(String logTag) { + throw new UnsupportedOperationException(); + } + + void terminate(); + + void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r); + + void reevaluateAllRequests(); + + void setScoreFilter(int score); + + void setScoreFilter(@NonNull NetworkScore score); + + void setCapabilityFilter(NetworkCapabilities netCap); + + int getRequestCount(); + + int getSerialNumber(); + + NetworkProvider getProvider(); + + void dump(FileDescriptor fd, PrintWriter writer, String[] args); + + // All impls inherit Handler + @VisibleForTesting + Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj); + + Looper getLooper(); +} diff --git a/staticlibs/jarjar-rules-shared.txt b/staticlibs/jarjar-rules-shared.txt index a7fda7c0ac..e26999dd0f 100644 --- a/staticlibs/jarjar-rules-shared.txt +++ b/staticlibs/jarjar-rules-shared.txt @@ -1,2 +1,3 @@ rule android.annotation.** com.android.net.module.annotation.@1 rule com.android.internal.annotations.** com.android.net.module.annotation.@1 +rule com.android.modules.utils.build.** com.android.net.module.util.build.$1 From a7702b6379571f1720c27668ae4622ecf727f040 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 1 Jul 2021 18:27:56 +0900 Subject: [PATCH 234/777] Add filterable, sortable to DevSdkIgnoreRunner Without a Filterable implementation like the AndroidJUnit4 runner, DevSdkIgnoreRunner will still run tests annotated with @AppModeFull or @SdkSuppress. Filterable should be implemented by runners that support filtering as per the JUnit documentation, so the DevSdkIgnoreRunner did not support filtering and would run all tests. Add a Filterable implementation based on the base AndroidJUnit4 runner. Bug: 192530637 Test: atest CtsNetTestCasesLatestSdk adding annotations to tests Change-Id: Ica9451e34fb5d98675f754269f44c0354bdde1a4 --- .../android/testutils/DevSdkIgnoreRunner.kt | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt index 73b2843f83..da7bf97b95 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt @@ -21,7 +21,13 @@ import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo import org.junit.runner.Description import org.junit.runner.Runner +import org.junit.runner.manipulation.Filter +import org.junit.runner.manipulation.Filterable +import org.junit.runner.manipulation.NoTestsRemainException +import org.junit.runner.manipulation.Sortable +import org.junit.runner.manipulation.Sorter import org.junit.runner.notification.RunNotifier +import kotlin.jvm.Throws /** * A runner that can skip tests based on the development SDK as defined in [DevSdkIgnoreRule]. @@ -41,7 +47,7 @@ import org.junit.runner.notification.RunNotifier * @IgnoreUpTo(Build.VERSION_CODES.Q) * class MyTestClass { ... } */ -class DevSdkIgnoreRunner(private val klass: Class<*>) : Runner() { +class DevSdkIgnoreRunner(private val klass: Class<*>) : Runner(), Filterable, Sortable { private val baseRunner = klass.let { val ignoreAfter = it.getAnnotation(IgnoreAfter::class.java) val ignoreUpTo = it.getAnnotation(IgnoreUpTo::class.java) @@ -55,8 +61,9 @@ class DevSdkIgnoreRunner(private val klass: Class<*>) : Runner() { return } - // Report a single, skipped placeholder test for this class, so that the class is still - // visible as skipped in test results. + // Report a single, skipped placeholder test for this class, as the class is expected to + // report results when run. In practice runners that apply the Filterable implementation + // would see a NoTestsRemainException and not call the run method. notifier.fireTestIgnored( Description.createTestDescription(klass, "skippedClassForDevSdkMismatch")) } @@ -65,8 +72,20 @@ class DevSdkIgnoreRunner(private val klass: Class<*>) : Runner() { return baseRunner?.description ?: Description.createSuiteDescription(klass) } + /** + * Get the test count before applying the [Filterable] implementation. + */ override fun testCount(): Int { // When ignoring the tests, a skipped placeholder test is reported, so test count is 1. return baseRunner?.testCount() ?: 1 } + + @Throws(NoTestsRemainException::class) + override fun filter(filter: Filter?) { + baseRunner?.filter(filter) ?: throw NoTestsRemainException() + } + + override fun sort(sorter: Sorter?) { + baseRunner?.sort(sorter) + } } \ No newline at end of file From 5ecba24e627f551bfafb50860f3ee34774269a3e Mon Sep 17 00:00:00 2001 From: lucaslin Date: Tue, 6 Apr 2021 09:54:45 +0800 Subject: [PATCH 235/777] Define TRANSPORT_USB in NetworkCapabilitiesUtils temporarily The new API constant - TRANSPORT_USB didn't in mainline branch, so the user of TRANSPORT_USB will get build break when it is built in mainline branch. Define TRANSPORT_USB in NetworkCapabilitiesUtils temporarily is a workaround to fix this problem, and it should be removed once downstream branches are S-based. (clean cherry-pick) Bug: 184158327 Test: m Merged-In: I83560c75761e7008b457a66296364cb4ce24db50 Change-Id: I83560c75761e7008b457a66296364cb4ce24db50 --- .../net/module/util/NetworkCapabilitiesUtils.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 382ed9f2c5..d4b1c9e034 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -47,6 +47,12 @@ import com.android.internal.annotations.VisibleForTesting; * @hide */ public final class NetworkCapabilitiesUtils { + /** + * See android.net.NetworkCapabilities.TRANSPORT_USB + * TODO: Use API constant when all downstream branches are S-based + */ + public static final int TRANSPORT_USB = 8; + // Transports considered to classify networks in UI, in order of which transport should be // surfaced when there are multiple transports. Transports not in this list do not have // an ordering preference (in practice they will have a deterministic order based on the @@ -64,7 +70,8 @@ public final class NetworkCapabilitiesUtils { TRANSPORT_WIFI_AWARE, TRANSPORT_BLUETOOTH, TRANSPORT_WIFI, - TRANSPORT_ETHERNET + TRANSPORT_ETHERNET, + TRANSPORT_USB // Notably, TRANSPORT_TEST is not in this list as any network that has TRANSPORT_TEST and // one of the above transports should be counted as that transport, to keep tests as From 844901b2a7fafcfd5c2f6a9831ead046fa416506 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 14 Jul 2021 16:30:33 +0900 Subject: [PATCH 236/777] Remove TRANSPORT_USB in NetworkCapabilitiesUtils The constant can now be used from the SDK, and will be inlined at compile time. This reverts commit 4c087c18114ec0026b5cdf4824b34477cd8f77c2. Bug: 184158327 Test: m Change-Id: Ie577677d237ccfbc73fd3924e6a6d32f9f655851 --- .../android/net/module/util/NetworkCapabilitiesUtils.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index d4b1c9e034..903214e22c 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -33,6 +33,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP; import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; +import static android.net.NetworkCapabilities.TRANSPORT_USB; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; @@ -47,12 +48,6 @@ import com.android.internal.annotations.VisibleForTesting; * @hide */ public final class NetworkCapabilitiesUtils { - /** - * See android.net.NetworkCapabilities.TRANSPORT_USB - * TODO: Use API constant when all downstream branches are S-based - */ - public static final int TRANSPORT_USB = 8; - // Transports considered to classify networks in UI, in order of which transport should be // surfaced when there are multiple transports. Transports not in this list do not have // an ordering preference (in practice they will have a deterministic order based on the From cdf45529adfa539854910b603894fc1fdda987e7 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 14 Jul 2021 13:19:58 +0800 Subject: [PATCH 237/777] Add assertNoCallbackThat assertNoCallback() fails when any callbacks are received. In some cases, the test is expected to not to receive certain callback, like available or lost. Depending on the network environment, network may trigger linkproperties change. It will fail the test, but these callback does not go against the intention of the test. It should not fail the test. Thus, add this method to allow tests to verify no certain callback received. Bug: 192239030 Test: atest TestableNetworkCallbackTest Change-Id: I7db720becb23636f85a9ac21192f8185eceb22fe --- .../com/android/testutils/TestableNetworkCallback.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index 1b3d0f69e1..7d851f114a 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -116,6 +116,7 @@ open class RecorderCallback private constructor( val mark get() = history.mark override fun onAvailable(network: Network) { + Log.d(TAG, "onAvailable $network") history.add(Available(network)) } @@ -199,6 +200,15 @@ open class TestableNetworkCallback private constructor( if (null != cb) fail("Expected no callback but got $cb") } + fun assertNoCallbackThat( + timeoutMs: Long = defaultTimeoutMs, + valid: (CallbackEntry) -> Boolean + ) { + val cb = history.poll(timeoutMs) { valid(it) }.let { + if (null != it) fail("Expected no callback but got $it") + } + } + // Expects a callback of the specified type on the specified network within the timeout. // If no callback arrives, or a different callback arrives, fail. Returns the callback. inline fun expectCallback( From 57b3442c653fcc6211c70b02f97f4a9007fa0ab4 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 1 Jul 2021 13:57:02 +0000 Subject: [PATCH 238/777] Migrate netlink-client to net-utils-device-common-netlink. Move netlink stuff to frameworks/libs/net/common/device, and build the source files as an individual libraray. NetworkStack module just depends on the net-utils-device-common-netlink. Besides, also fix the incorrect format detected by checkstyle_hook script such as missing java doc and make some public function as private, rename the variable and etc. Bug: 192535368 Test: atest NetworkStaticlibTests Change-Id: I00e7f30be1bc9ebc2e24d7cd53efc403d6ba3daa --- staticlibs/Android.bp | 36 +- .../com/android/net/module/util/HexDump.java | 2 +- .../com/android/net/module/util/Struct.java | 5 +- .../module/util/netlink/ConntrackMessage.java | 558 ++++++++++++++++++ .../module/util/netlink/InetDiagMessage.java | 231 ++++++++ .../net/module/util/netlink/NdOption.java | 83 +++ .../module/util/netlink/NduseroptMessage.java | 141 +++++ .../module/util/netlink/NetlinkConstants.java | 260 ++++++++ .../util/netlink/NetlinkErrorMessage.java | 64 ++ .../module/util/netlink/NetlinkMessage.java | 153 +++++ .../module/util/netlink/NetlinkSocket.java | 174 ++++++ .../netlink/RtNetlinkNeighborMessage.java | 237 ++++++++ .../util/netlink/StructInetDiagMsg.java | 62 ++ .../util/netlink/StructInetDiagReqV2.java | 100 ++++ .../util/netlink/StructInetDiagSockId.java | 90 +++ .../net/module/util/netlink/StructNdMsg.java | 198 +++++++ .../util/netlink/StructNdOptPref64.java | 169 ++++++ .../util/netlink/StructNdaCacheInfo.java | 133 +++++ .../module/util/netlink/StructNfGenMsg.java | 105 ++++ .../net/module/util/netlink/StructNlAttr.java | 315 ++++++++++ .../module/util/netlink/StructNlMsgErr.java | 77 +++ .../module/util/netlink/StructNlMsgHdr.java | 173 ++++++ .../util/structs/PrefixInformationOption.java | 3 +- .../util/netlink/ConntrackMessageTest.java | 433 ++++++++++++++ .../util/netlink/InetDiagSocketTest.java | 268 +++++++++ .../util/netlink/NduseroptMessageTest.java | 246 ++++++++ .../util/netlink/NetlinkConstantsTest.java | 132 +++++ .../util/netlink/NetlinkErrorMessageTest.java | 91 +++ .../util/netlink/NetlinkSocketTest.java | 242 ++++++++ .../netlink/RtNetlinkNeighborMessageTest.java | 207 +++++++ .../util/netlink/StructNdOptPref64Test.java | 200 +++++++ .../util/netlink/StructNlMsgHdrTest.java | 102 ++++ staticlibs/testutils/Android.bp | 1 + .../com/android/testutils/NetlinkTestUtils.kt | 102 ++++ 34 files changed, 5388 insertions(+), 5 deletions(-) create mode 100644 staticlibs/device/com/android/net/module/util/netlink/ConntrackMessage.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/NdOption.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/NduseroptMessage.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/NetlinkErrorMessage.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/NetlinkSocket.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/RtNetlinkNeighborMessage.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/StructInetDiagMsg.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/StructNdMsg.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/StructNdaCacheInfo.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/StructNfGenMsg.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/StructNlAttr.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/StructNlMsgErr.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/StructNlMsgHdr.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/netlink/ConntrackMessageTest.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/netlink/NduseroptMessageTest.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkConstantsTest.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkErrorMessageTest.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkSocketTest.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkNeighborMessageTest.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlMsgHdrTest.java create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/NetlinkTestUtils.kt diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 1371c8ccf3..4e7a9da7d0 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -34,7 +34,10 @@ package { java_library { name: "net-utils-device-common", srcs: [ - "device/com/android/net/module/util/**/*.java", + "device/com/android/net/module/util/DeviceConfigUtils.java", + "device/com/android/net/module/util/FdEventsReader.java", + "device/com/android/net/module/util/HexDump.java", + "device/com/android/net/module/util/PacketReader.java", // This library is used by system modules, for which the system health impact of Kotlin // has not yet been evaluated. Annotations may need jarjar'ing. // "src_devicecommon/**/*.kt", @@ -90,6 +93,37 @@ filegroup { ], } +java_library { + name: "net-utils-device-common-netlink", + // TODO: Ipv6Utils and Struct stuff could be separated out of th netlink library into + // an individual Struct library, and remove the net-utils-framework-common lib dependency. + // But there is no need doing this at the moment. + srcs: [ + "device/com/android/net/module/util/HexDump.java", + "device/com/android/net/module/util/Ipv6Utils.java", + "device/com/android/net/module/util/Struct.java", + "device/com/android/net/module/util/netlink/*.java", + "device/com/android/net/module/util/structs/*.java", + ], + sdk_version: "system_current", + min_sdk_version: "29", + visibility: [ + "//frameworks/libs/net/common/testutils:__subpackages__", + "//packages/modules/Connectivity:__subpackages__", + "//packages/modules/NetworkStack:__subpackages__", + ], + static_libs: [ + "net-utils-framework-common", + ], + libs: [ + "androidx.annotation_annotation", + ], + apex_available: [ + "com.android.tethering", + "//apex_available:platform", + ], +} + java_library { name: "net-utils-framework-common", srcs: [ diff --git a/staticlibs/device/com/android/net/module/util/HexDump.java b/staticlibs/device/com/android/net/module/util/HexDump.java index 6d36487b07..a27c0a3c95 100644 --- a/staticlibs/device/com/android/net/module/util/HexDump.java +++ b/staticlibs/device/com/android/net/module/util/HexDump.java @@ -16,7 +16,7 @@ package com.android.net.module.util; -import android.annotation.Nullable; +import androidx.annotation.Nullable; /** * Hex utility functions. diff --git a/staticlibs/device/com/android/net/module/util/Struct.java b/staticlibs/device/com/android/net/module/util/Struct.java index d95c303714..b43e2c458e 100644 --- a/staticlibs/device/com/android/net/module/util/Struct.java +++ b/staticlibs/device/com/android/net/module/util/Struct.java @@ -16,10 +16,11 @@ package com.android.net.module.util; -import android.annotation.NonNull; -import android.annotation.Nullable; import android.net.MacAddress; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/staticlibs/device/com/android/net/module/util/netlink/ConntrackMessage.java b/staticlibs/device/com/android/net/module/util/netlink/ConntrackMessage.java new file mode 100644 index 0000000000..1763c04ba8 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/ConntrackMessage.java @@ -0,0 +1,558 @@ +/* + * Copyright (C) 2017 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 com.android.net.module.util.netlink; + +import static android.system.OsConstants.IPPROTO_TCP; +import static android.system.OsConstants.IPPROTO_UDP; + +import static com.android.net.module.util.netlink.StructNlAttr.findNextAttrOfType; +import static com.android.net.module.util.netlink.StructNlAttr.makeNestedType; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REPLACE; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; + +import static java.nio.ByteOrder.BIG_ENDIAN; + +import android.system.OsConstants; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Objects; + +/** + * A NetlinkMessage subclass for netlink conntrack messages. + * + * see also: <linux_src>/include/uapi/linux/netfilter/nfnetlink_conntrack.h + * + * @hide + */ +public class ConntrackMessage extends NetlinkMessage { + public static final int STRUCT_SIZE = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE; + + // enum ctattr_type + public static final short CTA_TUPLE_ORIG = 1; + public static final short CTA_TUPLE_REPLY = 2; + public static final short CTA_STATUS = 3; + public static final short CTA_TIMEOUT = 7; + + // enum ctattr_tuple + public static final short CTA_TUPLE_IP = 1; + public static final short CTA_TUPLE_PROTO = 2; + + // enum ctattr_ip + public static final short CTA_IP_V4_SRC = 1; + public static final short CTA_IP_V4_DST = 2; + + // enum ctattr_l4proto + public static final short CTA_PROTO_NUM = 1; + public static final short CTA_PROTO_SRC_PORT = 2; + public static final short CTA_PROTO_DST_PORT = 3; + + // enum ip_conntrack_status + public static final int IPS_EXPECTED = 0x00000001; + public static final int IPS_SEEN_REPLY = 0x00000002; + public static final int IPS_ASSURED = 0x00000004; + public static final int IPS_CONFIRMED = 0x00000008; + public static final int IPS_SRC_NAT = 0x00000010; + public static final int IPS_DST_NAT = 0x00000020; + public static final int IPS_SEQ_ADJUST = 0x00000040; + public static final int IPS_SRC_NAT_DONE = 0x00000080; + public static final int IPS_DST_NAT_DONE = 0x00000100; + public static final int IPS_DYING = 0x00000200; + public static final int IPS_FIXED_TIMEOUT = 0x00000400; + public static final int IPS_TEMPLATE = 0x00000800; + public static final int IPS_UNTRACKED = 0x00001000; + public static final int IPS_HELPER = 0x00002000; + public static final int IPS_OFFLOAD = 0x00004000; + public static final int IPS_HW_OFFLOAD = 0x00008000; + + // ip_conntrack_status mask + // Interesting on the NAT conntrack session which has already seen two direction traffic. + // TODO: Probably IPS_{SRC, DST}_NAT_DONE are also interesting. + public static final int ESTABLISHED_MASK = IPS_CONFIRMED | IPS_ASSURED | IPS_SEEN_REPLY + | IPS_SRC_NAT; + // Interesting on the established NAT conntrack session which is dying. + public static final int DYING_MASK = ESTABLISHED_MASK | IPS_DYING; + + /** + * A tuple for the conntrack connection information. + * + * see also CTA_TUPLE_ORIG and CTA_TUPLE_REPLY. + */ + public static class Tuple { + public final Inet4Address srcIp; + public final Inet4Address dstIp; + + // Both port and protocol number are unsigned numbers stored in signed integers, and that + // callers that want to compare them to integers should either cast those integers, or + // convert them to unsigned using Byte.toUnsignedInt() and Short.toUnsignedInt(). + public final short srcPort; + public final short dstPort; + public final byte protoNum; + + public Tuple(TupleIpv4 ip, TupleProto proto) { + this.srcIp = ip.src; + this.dstIp = ip.dst; + this.srcPort = proto.srcPort; + this.dstPort = proto.dstPort; + this.protoNum = proto.protoNum; + } + + @Override + @VisibleForTesting + public boolean equals(Object o) { + if (!(o instanceof Tuple)) return false; + Tuple that = (Tuple) o; + return Objects.equals(this.srcIp, that.srcIp) + && Objects.equals(this.dstIp, that.dstIp) + && this.srcPort == that.srcPort + && this.dstPort == that.dstPort + && this.protoNum == that.protoNum; + } + + @Override + public int hashCode() { + return Objects.hash(srcIp, dstIp, srcPort, dstPort, protoNum); + } + + @Override + public String toString() { + final String srcIpStr = (srcIp == null) ? "null" : srcIp.getHostAddress(); + final String dstIpStr = (dstIp == null) ? "null" : dstIp.getHostAddress(); + final String protoStr = NetlinkConstants.stringForProtocol(protoNum); + + return "Tuple{" + + protoStr + ": " + + srcIpStr + ":" + Short.toUnsignedInt(srcPort) + " -> " + + dstIpStr + ":" + Short.toUnsignedInt(dstPort) + + "}"; + } + } + + /** + * A tuple for the conntrack connection address. + * + * see also CTA_TUPLE_IP. + */ + public static class TupleIpv4 { + public final Inet4Address src; + public final Inet4Address dst; + + public TupleIpv4(Inet4Address src, Inet4Address dst) { + this.src = src; + this.dst = dst; + } + } + + /** + * A tuple for the conntrack connection protocol. + * + * see also CTA_TUPLE_PROTO. + */ + public static class TupleProto { + public final byte protoNum; + public final short srcPort; + public final short dstPort; + + public TupleProto(byte protoNum, short srcPort, short dstPort) { + this.protoNum = protoNum; + this.srcPort = srcPort; + this.dstPort = dstPort; + } + } + + /** + * Create a netlink message to refresh IPv4 conntrack entry timeout. + */ + public static byte[] newIPv4TimeoutUpdateRequest( + int proto, Inet4Address src, int sport, Inet4Address dst, int dport, int timeoutSec) { + // *** STYLE WARNING *** + // + // Code below this point uses extra block indentation to highlight the + // packing of nested tuple netlink attribute types. + final StructNlAttr ctaTupleOrig = new StructNlAttr(CTA_TUPLE_ORIG, + new StructNlAttr(CTA_TUPLE_IP, + new StructNlAttr(CTA_IP_V4_SRC, src), + new StructNlAttr(CTA_IP_V4_DST, dst)), + new StructNlAttr(CTA_TUPLE_PROTO, + new StructNlAttr(CTA_PROTO_NUM, (byte) proto), + new StructNlAttr(CTA_PROTO_SRC_PORT, (short) sport, BIG_ENDIAN), + new StructNlAttr(CTA_PROTO_DST_PORT, (short) dport, BIG_ENDIAN))); + + final StructNlAttr ctaTimeout = new StructNlAttr(CTA_TIMEOUT, timeoutSec, BIG_ENDIAN); + + final int payloadLength = ctaTupleOrig.getAlignedLength() + ctaTimeout.getAlignedLength(); + final byte[] bytes = new byte[STRUCT_SIZE + payloadLength]; + final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); + byteBuffer.order(ByteOrder.nativeOrder()); + + final ConntrackMessage ctmsg = new ConntrackMessage(); + ctmsg.mHeader.nlmsg_len = bytes.length; + ctmsg.mHeader.nlmsg_type = (NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8) + | NetlinkConstants.IPCTNL_MSG_CT_NEW; + ctmsg.mHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE; + ctmsg.mHeader.nlmsg_seq = 1; + ctmsg.pack(byteBuffer); + + ctaTupleOrig.pack(byteBuffer); + ctaTimeout.pack(byteBuffer); + + return bytes; + } + + /** + * Parses a netfilter conntrack message from a {@link ByteBuffer}. + * + * @param header the netlink message header. + * @param byteBuffer The buffer from which to parse the netfilter conntrack message. + * @return the parsed netfilter conntrack message, or {@code null} if the netfilter conntrack + * message could not be parsed successfully (for example, if it was truncated). + */ + public static ConntrackMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) { + // Just build the netlink header and netfilter header for now and pretend the whole message + // was consumed. + // TODO: Parse the conntrack attributes. + final StructNfGenMsg nfGenMsg = StructNfGenMsg.parse(byteBuffer); + if (nfGenMsg == null) { + return null; + } + + final int baseOffset = byteBuffer.position(); + StructNlAttr nlAttr = findNextAttrOfType(CTA_STATUS, byteBuffer); + int status = 0; + if (nlAttr != null) { + status = nlAttr.getValueAsBe32(0); + } + + byteBuffer.position(baseOffset); + nlAttr = findNextAttrOfType(CTA_TIMEOUT, byteBuffer); + int timeoutSec = 0; + if (nlAttr != null) { + timeoutSec = nlAttr.getValueAsBe32(0); + } + + byteBuffer.position(baseOffset); + nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_ORIG), byteBuffer); + Tuple tupleOrig = null; + if (nlAttr != null) { + tupleOrig = parseTuple(nlAttr.getValueAsByteBuffer()); + } + + byteBuffer.position(baseOffset); + nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_REPLY), byteBuffer); + Tuple tupleReply = null; + if (nlAttr != null) { + tupleReply = parseTuple(nlAttr.getValueAsByteBuffer()); + } + + // Advance to the end of the message. + byteBuffer.position(baseOffset); + final int kMinConsumed = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE; + final int kAdditionalSpace = NetlinkConstants.alignedLengthOf( + header.nlmsg_len - kMinConsumed); + if (byteBuffer.remaining() < kAdditionalSpace) { + return null; + } + byteBuffer.position(baseOffset + kAdditionalSpace); + + return new ConntrackMessage(header, nfGenMsg, tupleOrig, tupleReply, status, timeoutSec); + } + + /** + * Parses a conntrack tuple from a {@link ByteBuffer}. + * + * The attribute parsing is interesting on: + * - CTA_TUPLE_IP + * CTA_IP_V4_SRC + * CTA_IP_V4_DST + * - CTA_TUPLE_PROTO + * CTA_PROTO_NUM + * CTA_PROTO_SRC_PORT + * CTA_PROTO_DST_PORT + * + * Assume that the minimum size is the sum of CTA_TUPLE_IP (size: 20) and CTA_TUPLE_PROTO + * (size: 28). Here is an example for an expected CTA_TUPLE_ORIG message in raw data: + * +--------------------------------------------------------------------------------------+ + * | CTA_TUPLE_ORIG | + * +--------------------------+-----------------------------------------------------------+ + * | 1400 | nla_len = 20 | + * | 0180 | nla_type = nested CTA_TUPLE_IP | + * | 0800 0100 C0A8500C | nla_type=CTA_IP_V4_SRC, ip=192.168.80.12 | + * | 0800 0200 8C700874 | nla_type=CTA_IP_V4_DST, ip=140.112.8.116 | + * | 1C00 | nla_len = 28 | + * | 0280 | nla_type = nested CTA_TUPLE_PROTO | + * | 0500 0100 06 000000 | nla_type=CTA_PROTO_NUM, proto=IPPROTO_TCP (6) | + * | 0600 0200 F3F1 0000 | nla_type=CTA_PROTO_SRC_PORT, port=62449 (big endian) | + * | 0600 0300 01BB 0000 | nla_type=CTA_PROTO_DST_PORT, port=433 (big endian) | + * +--------------------------+-----------------------------------------------------------+ + * + * The position of the byte buffer doesn't set to the end when the function returns. It is okay + * because the caller ConntrackMessage#parse has passed a copy which is used for this parser + * only. Moreover, the parser behavior is the same as other existing netlink struct class + * parser. Ex: StructInetDiagMsg#parse. + */ + @Nullable + private static Tuple parseTuple(@Nullable ByteBuffer byteBuffer) { + if (byteBuffer == null) return null; + + TupleIpv4 tupleIpv4 = null; + TupleProto tupleProto = null; + + final int baseOffset = byteBuffer.position(); + StructNlAttr nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_IP), byteBuffer); + if (nlAttr != null) { + tupleIpv4 = parseTupleIpv4(nlAttr.getValueAsByteBuffer()); + } + if (tupleIpv4 == null) return null; + + byteBuffer.position(baseOffset); + nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_PROTO), byteBuffer); + if (nlAttr != null) { + tupleProto = parseTupleProto(nlAttr.getValueAsByteBuffer()); + } + if (tupleProto == null) return null; + + return new Tuple(tupleIpv4, tupleProto); + } + + @Nullable + private static Inet4Address castToInet4Address(@Nullable InetAddress address) { + if (address == null || !(address instanceof Inet4Address)) return null; + return (Inet4Address) address; + } + + @Nullable + private static TupleIpv4 parseTupleIpv4(@Nullable ByteBuffer byteBuffer) { + if (byteBuffer == null) return null; + + Inet4Address src = null; + Inet4Address dst = null; + + final int baseOffset = byteBuffer.position(); + StructNlAttr nlAttr = findNextAttrOfType(CTA_IP_V4_SRC, byteBuffer); + if (nlAttr != null) { + src = castToInet4Address(nlAttr.getValueAsInetAddress()); + } + if (src == null) return null; + + byteBuffer.position(baseOffset); + nlAttr = findNextAttrOfType(CTA_IP_V4_DST, byteBuffer); + if (nlAttr != null) { + dst = castToInet4Address(nlAttr.getValueAsInetAddress()); + } + if (dst == null) return null; + + return new TupleIpv4(src, dst); + } + + @Nullable + private static TupleProto parseTupleProto(@Nullable ByteBuffer byteBuffer) { + if (byteBuffer == null) return null; + + byte protoNum = 0; + short srcPort = 0; + short dstPort = 0; + + final int baseOffset = byteBuffer.position(); + StructNlAttr nlAttr = findNextAttrOfType(CTA_PROTO_NUM, byteBuffer); + if (nlAttr != null) { + protoNum = nlAttr.getValueAsByte((byte) 0); + } + if (!(protoNum == IPPROTO_TCP || protoNum == IPPROTO_UDP)) return null; + + byteBuffer.position(baseOffset); + nlAttr = StructNlAttr.findNextAttrOfType(CTA_PROTO_SRC_PORT, byteBuffer); + if (nlAttr != null) { + srcPort = nlAttr.getValueAsBe16((short) 0); + } + if (srcPort == 0) return null; + + byteBuffer.position(baseOffset); + nlAttr = StructNlAttr.findNextAttrOfType(CTA_PROTO_DST_PORT, byteBuffer); + if (nlAttr != null) { + dstPort = nlAttr.getValueAsBe16((short) 0); + } + if (dstPort == 0) return null; + + return new TupleProto(protoNum, srcPort, dstPort); + } + + /** + * Netfilter header. + */ + public final StructNfGenMsg nfGenMsg; + /** + * Original direction conntrack tuple. + * + * The tuple is determined by the parsed attribute value CTA_TUPLE_ORIG, or null if the + * tuple could not be parsed successfully (for example, if it was truncated or absent). + */ + @Nullable + public final Tuple tupleOrig; + /** + * Reply direction conntrack tuple. + * + * The tuple is determined by the parsed attribute value CTA_TUPLE_REPLY, or null if the + * tuple could not be parsed successfully (for example, if it was truncated or absent). + */ + @Nullable + public final Tuple tupleReply; + /** + * Connection status. A bitmask of ip_conntrack_status enum flags. + * + * The status is determined by the parsed attribute value CTA_STATUS, or 0 if the status could + * not be parsed successfully (for example, if it was truncated or absent). For the message + * from kernel, the valid status is non-zero. For the message from user space, the status may + * be 0 (absent). + */ + public final int status; + /** + * Conntrack timeout. + * + * The timeout is determined by the parsed attribute value CTA_TIMEOUT, or 0 if the timeout + * could not be parsed successfully (for example, if it was truncated or absent). For + * IPCTNL_MSG_CT_NEW event, the valid timeout is non-zero. For IPCTNL_MSG_CT_DELETE event, the + * timeout is 0 (absent). + */ + public final int timeoutSec; + + private ConntrackMessage() { + super(new StructNlMsgHdr()); + nfGenMsg = new StructNfGenMsg((byte) OsConstants.AF_INET); + + // This constructor is only used by #newIPv4TimeoutUpdateRequest which doesn't use these + // data member for packing message. Simply fill them to null or 0. + tupleOrig = null; + tupleReply = null; + status = 0; + timeoutSec = 0; + } + + private ConntrackMessage(@NonNull StructNlMsgHdr header, @NonNull StructNfGenMsg nfGenMsg, + @Nullable Tuple tupleOrig, @Nullable Tuple tupleReply, int status, int timeoutSec) { + super(header); + this.nfGenMsg = nfGenMsg; + this.tupleOrig = tupleOrig; + this.tupleReply = tupleReply; + this.status = status; + this.timeoutSec = timeoutSec; + } + + /** + * Write a netfilter message to {@link ByteBuffer}. + */ + public void pack(ByteBuffer byteBuffer) { + mHeader.pack(byteBuffer); + nfGenMsg.pack(byteBuffer); + } + + public short getMessageType() { + return (short) (getHeader().nlmsg_type & ~(NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8)); + } + + /** + * Convert an ip conntrack status to a string. + */ + public static String stringForIpConntrackStatus(int flags) { + final StringBuilder sb = new StringBuilder(); + + if ((flags & IPS_EXPECTED) != 0) { + sb.append("IPS_EXPECTED"); + } + if ((flags & IPS_SEEN_REPLY) != 0) { + if (sb.length() > 0) sb.append("|"); + sb.append("IPS_SEEN_REPLY"); + } + if ((flags & IPS_ASSURED) != 0) { + if (sb.length() > 0) sb.append("|"); + sb.append("IPS_ASSURED"); + } + if ((flags & IPS_CONFIRMED) != 0) { + if (sb.length() > 0) sb.append("|"); + sb.append("IPS_CONFIRMED"); + } + if ((flags & IPS_SRC_NAT) != 0) { + if (sb.length() > 0) sb.append("|"); + sb.append("IPS_SRC_NAT"); + } + if ((flags & IPS_DST_NAT) != 0) { + if (sb.length() > 0) sb.append("|"); + sb.append("IPS_DST_NAT"); + } + if ((flags & IPS_SEQ_ADJUST) != 0) { + if (sb.length() > 0) sb.append("|"); + sb.append("IPS_SEQ_ADJUST"); + } + if ((flags & IPS_SRC_NAT_DONE) != 0) { + if (sb.length() > 0) sb.append("|"); + sb.append("IPS_SRC_NAT_DONE"); + } + if ((flags & IPS_DST_NAT_DONE) != 0) { + if (sb.length() > 0) sb.append("|"); + sb.append("IPS_DST_NAT_DONE"); + } + if ((flags & IPS_DYING) != 0) { + if (sb.length() > 0) sb.append("|"); + sb.append("IPS_DYING"); + } + if ((flags & IPS_FIXED_TIMEOUT) != 0) { + if (sb.length() > 0) sb.append("|"); + sb.append("IPS_FIXED_TIMEOUT"); + } + if ((flags & IPS_TEMPLATE) != 0) { + if (sb.length() > 0) sb.append("|"); + sb.append("IPS_TEMPLATE"); + } + if ((flags & IPS_UNTRACKED) != 0) { + if (sb.length() > 0) sb.append("|"); + sb.append("IPS_UNTRACKED"); + } + if ((flags & IPS_HELPER) != 0) { + if (sb.length() > 0) sb.append("|"); + sb.append("IPS_HELPER"); + } + if ((flags & IPS_OFFLOAD) != 0) { + if (sb.length() > 0) sb.append("|"); + sb.append("IPS_OFFLOAD"); + } + if ((flags & IPS_HW_OFFLOAD) != 0) { + if (sb.length() > 0) sb.append("|"); + sb.append("IPS_HW_OFFLOAD"); + } + return sb.toString(); + } + + @Override + public String toString() { + return "ConntrackMessage{" + + "nlmsghdr{" + + (mHeader == null ? "" : mHeader.toString(OsConstants.NETLINK_NETFILTER)) + + "}, " + + "nfgenmsg{" + nfGenMsg + "}, " + + "tuple_orig{" + tupleOrig + "}, " + + "tuple_reply{" + tupleReply + "}, " + + "status{" + status + "(" + stringForIpConntrackStatus(status) + ")" + "}, " + + "timeout_sec{" + Integer.toUnsignedLong(timeoutSec) + "}" + + "}"; + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java new file mode 100644 index 0000000000..7b200e7597 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2018 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 com.android.net.module.util.netlink; + +import static android.os.Process.INVALID_UID; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.IPPROTO_UDP; +import static android.system.OsConstants.NETLINK_INET_DIAG; + +import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY; +import static com.android.net.module.util.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; + +import android.net.util.SocketUtils; +import android.system.ErrnoException; +import android.util.Log; + +import androidx.annotation.Nullable; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * A NetlinkMessage subclass for netlink inet_diag messages. + * + * see also: <linux_src>/include/uapi/linux/inet_diag.h + * + * @hide + */ +public class InetDiagMessage extends NetlinkMessage { + public static final String TAG = "InetDiagMessage"; + private static final int TIMEOUT_MS = 500; + + /** + * Construct an inet_diag_req_v2 message. This method will throw {@code NullPointerException} + * if local and remote are not both null or both non-null. + */ + public static byte[] inetDiagReqV2(int protocol, InetSocketAddress local, + InetSocketAddress remote, int family, short flags) { + return inetDiagReqV2(protocol, local, remote, family, flags, 0 /* pad */, + 0 /* idiagExt */, StructInetDiagReqV2.INET_DIAG_REQ_V2_ALL_STATES); + } + + /** + * Construct an inet_diag_req_v2 message. This method will throw {@code NullPointerException} + * if local and remote are not both null or both non-null. + * + * @param protocol the request protocol type. This should be set to one of IPPROTO_TCP, + * IPPROTO_UDP, or IPPROTO_UDPLITE. + * @param local local socket address of the target socket. This will be packed into a + * {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of + * local or remote address is null. + * @param remote remote socket address of the target socket. This will be packed into a + * {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of + * local or remote address is null. + * @param family the ip family of the request message. This should be set to either AF_INET or + * AF_INET6 for IPv4 or IPv6 sockets respectively. + * @param flags message flags. See <linux_src>/include/uapi/linux/netlink.h. + * @param pad for raw socket protocol specification. + * @param idiagExt a set of flags defining what kind of extended information to report. + * @param state a bit mask that defines a filter of socket states. + * + * @return bytes array representation of the message + */ + public static byte[] inetDiagReqV2(int protocol, @Nullable InetSocketAddress local, + @Nullable InetSocketAddress remote, int family, short flags, int pad, int idiagExt, + int state) throws NullPointerException { + final byte[] bytes = new byte[StructNlMsgHdr.STRUCT_SIZE + StructInetDiagReqV2.STRUCT_SIZE]; + final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); + byteBuffer.order(ByteOrder.nativeOrder()); + + final StructNlMsgHdr nlMsgHdr = new StructNlMsgHdr(); + nlMsgHdr.nlmsg_len = bytes.length; + nlMsgHdr.nlmsg_type = SOCK_DIAG_BY_FAMILY; + nlMsgHdr.nlmsg_flags = flags; + nlMsgHdr.pack(byteBuffer); + final StructInetDiagReqV2 inetDiagReqV2 = + new StructInetDiagReqV2(protocol, local, remote, family, pad, idiagExt, state); + + inetDiagReqV2.pack(byteBuffer); + return bytes; + } + + public StructInetDiagMsg mStructInetDiagMsg; + + private InetDiagMessage(StructNlMsgHdr header) { + super(header); + mStructInetDiagMsg = new StructInetDiagMsg(); + } + + /** + * Parse an inet_diag_req_v2 message from buffer. + */ + public static InetDiagMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) { + final InetDiagMessage msg = new InetDiagMessage(header); + msg.mStructInetDiagMsg = StructInetDiagMsg.parse(byteBuffer); + return msg; + } + + private static int lookupUidByFamily(int protocol, InetSocketAddress local, + InetSocketAddress remote, int family, short flags, + FileDescriptor fd) + throws ErrnoException, InterruptedIOException { + byte[] msg = inetDiagReqV2(protocol, local, remote, family, flags); + NetlinkSocket.sendMessage(fd, msg, 0, msg.length, TIMEOUT_MS); + ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT_MS); + + final NetlinkMessage nlMsg = NetlinkMessage.parse(response, NETLINK_INET_DIAG); + final StructNlMsgHdr hdr = nlMsg.getHeader(); + if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) { + return INVALID_UID; + } + if (nlMsg instanceof InetDiagMessage) { + return ((InetDiagMessage) nlMsg).mStructInetDiagMsg.idiag_uid; + } + return INVALID_UID; + } + + private static final int[] FAMILY = {AF_INET6, AF_INET}; + + private static int lookupUid(int protocol, InetSocketAddress local, + InetSocketAddress remote, FileDescriptor fd) + throws ErrnoException, InterruptedIOException { + int uid; + + for (int family : FAMILY) { + /** + * For exact match lookup, swap local and remote for UDP lookups due to kernel + * bug which will not be fixed. See aosp/755889 and + * https://www.mail-archive.com/netdev@vger.kernel.org/msg248638.html + */ + if (protocol == IPPROTO_UDP) { + uid = lookupUidByFamily(protocol, remote, local, family, NLM_F_REQUEST, fd); + } else { + uid = lookupUidByFamily(protocol, local, remote, family, NLM_F_REQUEST, fd); + } + if (uid != INVALID_UID) { + return uid; + } + } + + /** + * For UDP it's possible for a socket to send packets to arbitrary destinations, even if the + * socket is not connected (and even if the socket is connected to a different destination). + * If we want this API to work for such packets, then on miss we need to do a second lookup + * with only the local address and port filled in. + * Always use flags == NLM_F_REQUEST | NLM_F_DUMP for wildcard. + */ + if (protocol == IPPROTO_UDP) { + try { + InetSocketAddress wildcard = new InetSocketAddress( + Inet6Address.getByName("::"), 0); + uid = lookupUidByFamily(protocol, local, wildcard, AF_INET6, + (short) (NLM_F_REQUEST | NLM_F_DUMP), fd); + if (uid != INVALID_UID) { + return uid; + } + wildcard = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), 0); + uid = lookupUidByFamily(protocol, local, wildcard, AF_INET, + (short) (NLM_F_REQUEST | NLM_F_DUMP), fd); + if (uid != INVALID_UID) { + return uid; + } + } catch (UnknownHostException e) { + Log.e(TAG, e.toString()); + } + } + return INVALID_UID; + } + + /** + * Use an inet_diag socket to look up the UID associated with the input local and remote + * address/port and protocol of a connection. + */ + public static int getConnectionOwnerUid(int protocol, InetSocketAddress local, + InetSocketAddress remote) { + int uid = INVALID_UID; + FileDescriptor fd = null; + try { + fd = NetlinkSocket.forProto(NETLINK_INET_DIAG); + NetlinkSocket.connectToKernel(fd); + uid = lookupUid(protocol, local, remote, fd); + } catch (ErrnoException | SocketException | IllegalArgumentException + | InterruptedIOException e) { + Log.e(TAG, e.toString()); + } finally { + if (fd != null) { + try { + SocketUtils.closeSocket(fd); + } catch (IOException e) { + Log.e(TAG, e.toString()); + } + } + } + return uid; + } + + @Override + public String toString() { + return "InetDiagMessage{ " + + "nlmsghdr{" + + (mHeader == null ? "" : mHeader.toString(NETLINK_INET_DIAG)) + "}, " + + "inet_diag_msg{" + + (mStructInetDiagMsg == null ? "" : mStructInetDiagMsg.toString()) + "} " + + "}"; + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/NdOption.java b/staticlibs/device/com/android/net/module/util/netlink/NdOption.java new file mode 100644 index 0000000000..50a3496660 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/NdOption.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util.netlink; + +import java.nio.ByteBuffer; + +/** + * Base class for IPv6 neighbour discovery options. + */ +public class NdOption { + public static final int STRUCT_SIZE = 2; + + /** The option type. */ + public final byte type; + /** The length of the option in 8-byte units. Actually an unsigned 8-bit integer */ + public final int length; + + /** Constructs a new NdOption. */ + NdOption(byte type, int length) { + this.type = type; + this.length = length; + } + + /** + * Parses a neighbour discovery option. + * + * Parses (and consumes) the option if it is of a known type. If the option is of an unknown + * type, advances the buffer (so the caller can continue parsing if desired) and returns + * {@link #UNKNOWN}. If the option claims a length of 0, returns null because parsing cannot + * continue. + * + * No checks are performed on the length other than ensuring it is not 0, so if a caller wants + * to deal with options that might overflow the structure that contains them, it must explicitly + * set the buffer's limit to the position at which that structure ends. + * + * @param buf the buffer to parse. + * @return a subclass of {@link NdOption}, or {@code null} for an unknown or malformed option. + */ + public static NdOption parse(ByteBuffer buf) { + if (buf == null || buf.remaining() < STRUCT_SIZE) return null; + + // Peek the type without advancing the buffer. + byte type = buf.get(buf.position()); + int length = Byte.toUnsignedInt(buf.get(buf.position() + 1)); + if (length == 0) return null; + + switch (type) { + case StructNdOptPref64.TYPE: + return StructNdOptPref64.parse(buf); + + default: + int newPosition = Math.min(buf.limit(), buf.position() + length * 8); + buf.position(newPosition); + return UNKNOWN; + } + } + + void writeToByteBuffer(ByteBuffer buf) { + buf.put(type); + buf.put((byte) length); + } + + @Override + public String toString() { + return String.format("NdOption(%d, %d)", Byte.toUnsignedInt(type), length); + } + + public static final NdOption UNKNOWN = new NdOption((byte) 0, 0); +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/NduseroptMessage.java b/staticlibs/device/com/android/net/module/util/netlink/NduseroptMessage.java new file mode 100644 index 0000000000..4e3b9f2da6 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/NduseroptMessage.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util.netlink; + +import static android.system.OsConstants.AF_INET6; + +import androidx.annotation.NonNull; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * A NetlinkMessage subclass for RTM_NEWNDUSEROPT messages. + */ +public class NduseroptMessage extends NetlinkMessage { + public static final int STRUCT_SIZE = 16; + + static final int NDUSEROPT_SRCADDR = 1; + + /** The address family. Presumably always AF_INET6. */ + public final byte family; + /** + * The total length in bytes of the options that follow this structure. + * Actually a 16-bit unsigned integer. + */ + public final int opts_len; + /** The interface index on which the options were received. */ + public final int ifindex; + /** The ICMP type of the packet that contained the options. */ + public final byte icmp_type; + /** The ICMP code of the packet that contained the options. */ + public final byte icmp_code; + + /** + * ND option that was in this message. + * Even though the length field is called "opts_len", the kernel only ever sends one option per + * message. It is unlikely that this will ever change as it would break existing userspace code. + * But if it does, we can simply update this code, since userspace is typically newer than the + * kernel. + */ + public final NdOption option; + + /** The IP address that sent the packet containing the option. */ + public final InetAddress srcaddr; + + NduseroptMessage(@NonNull StructNlMsgHdr header, @NonNull ByteBuffer buf) + throws UnknownHostException { + super(header); + + // The structure itself. + buf.order(ByteOrder.nativeOrder()); // Restored in the finally clause inside parse(). + final int start = buf.position(); + family = buf.get(); + buf.get(); // Skip 1 byte of padding. + opts_len = Short.toUnsignedInt(buf.getShort()); + ifindex = buf.getInt(); + icmp_type = buf.get(); + icmp_code = buf.get(); + buf.position(buf.position() + 6); // Skip 6 bytes of padding. + + // The ND option. + // Ensure we don't read past opts_len even if the option length is invalid. + // Note that this check is not really necessary since if the option length is not valid, + // this struct won't be very useful to the caller. + buf.order(ByteOrder.BIG_ENDIAN); + int oldLimit = buf.limit(); + buf.limit(start + STRUCT_SIZE + opts_len); + try { + option = NdOption.parse(buf); + } finally { + buf.limit(oldLimit); + } + + // The source address. + int newPosition = start + STRUCT_SIZE + opts_len; + if (newPosition >= buf.limit()) { + throw new IllegalArgumentException("ND options extend past end of buffer"); + } + buf.position(newPosition); + + StructNlAttr nla = StructNlAttr.parse(buf); + if (nla == null || nla.nla_type != NDUSEROPT_SRCADDR || nla.nla_value == null) { + throw new IllegalArgumentException("Invalid source address in ND useropt"); + } + if (family == AF_INET6) { + // InetAddress.getByAddress only looks at the ifindex if the address type needs one. + srcaddr = Inet6Address.getByAddress(null /* hostname */, nla.nla_value, ifindex); + } else { + srcaddr = InetAddress.getByAddress(nla.nla_value); + } + } + + /** + * Parses a StructNduseroptmsg from a {@link ByteBuffer}. + * + * @param header the netlink message header. + * @param buf The buffer from which to parse the option. The buffer's byte order must be + * {@link java.nio.ByteOrder#BIG_ENDIAN}. + * @return the parsed option, or {@code null} if the option could not be parsed successfully + * (for example, if it was truncated, or if the prefix length code was wrong). + */ + public static NduseroptMessage parse(@NonNull StructNlMsgHdr header, @NonNull ByteBuffer buf) { + if (buf == null || buf.remaining() < STRUCT_SIZE) return null; + ByteOrder oldOrder = buf.order(); + try { + return new NduseroptMessage(header, buf); + } catch (IllegalArgumentException | UnknownHostException | BufferUnderflowException e) { + // Not great, but better than throwing an exception that might crash the caller. + // Convention in this package is that null indicates that the option was truncated, so + // callers must already handle it. + return null; + } finally { + buf.order(oldOrder); + } + } + + @Override + public String toString() { + return String.format("Nduseroptmsg(%d, %d, %d, %d, %d, %s)", + family, opts_len, ifindex, Byte.toUnsignedInt(icmp_type), + Byte.toUnsignedInt(icmp_code), srcaddr.getHostAddress()); + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java new file mode 100644 index 0000000000..cf9d2c54b2 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2015 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 com.android.net.module.util.netlink; + +import android.system.OsConstants; + +import androidx.annotation.NonNull; + +import java.nio.ByteBuffer; + +/** + * Various constants and static helper methods for netlink communications. + * + * Values taken from: + * + * include/uapi/linux/netfilter/nfnetlink.h + * include/uapi/linux/netfilter/nfnetlink_conntrack.h + * include/uapi/linux/netlink.h + * include/uapi/linux/rtnetlink.h + * + * @hide + */ +public class NetlinkConstants { + private NetlinkConstants() {} + + public static final int NLA_ALIGNTO = 4; + /** + * Flag for dumping struct tcp_info. + * Corresponding to enum definition in external/strace/linux/inet_diag.h. + */ + public static final int INET_DIAG_MEMINFO = 1; + + public static final int SOCKDIAG_MSG_HEADER_SIZE = + StructNlMsgHdr.STRUCT_SIZE + StructInetDiagMsg.STRUCT_SIZE; + + /** + * Get the aligned length based on a Short type number. + */ + public static final int alignedLengthOf(short length) { + final int intLength = (int) length & 0xffff; + return alignedLengthOf(intLength); + } + + /** + * Get the aligned length based on a Integer type number. + */ + public static final int alignedLengthOf(int length) { + if (length <= 0) return 0; + return (((length + NLA_ALIGNTO - 1) / NLA_ALIGNTO) * NLA_ALIGNTO); + } + + /** + * Convert a address family type to a string. + */ + public static String stringForAddressFamily(int family) { + if (family == OsConstants.AF_INET) return "AF_INET"; + if (family == OsConstants.AF_INET6) return "AF_INET6"; + if (family == OsConstants.AF_NETLINK) return "AF_NETLINK"; + return String.valueOf(family); + } + + /** + * Convert a protocol type to a string. + */ + public static String stringForProtocol(int protocol) { + if (protocol == OsConstants.IPPROTO_TCP) return "IPPROTO_TCP"; + if (protocol == OsConstants.IPPROTO_UDP) return "IPPROTO_UDP"; + return String.valueOf(protocol); + } + + /** + * Convert a byte array to a hexadecimal string. + */ + public static String hexify(byte[] bytes) { + if (bytes == null) return "(null)"; + return toHexString(bytes, 0, bytes.length); + } + + /** + * Convert a {@link ByteBuffer} to a hexadecimal string. + */ + public static String hexify(ByteBuffer buffer) { + if (buffer == null) return "(null)"; + return toHexString( + buffer.array(), buffer.position(), buffer.remaining()); + } + + // Known values for struct nlmsghdr nlm_type. + public static final short NLMSG_NOOP = 1; // Nothing + public static final short NLMSG_ERROR = 2; // Error + public static final short NLMSG_DONE = 3; // End of a dump + public static final short NLMSG_OVERRUN = 4; // Data lost + public static final short NLMSG_MAX_RESERVED = 15; // Max reserved value + + public static final short RTM_NEWLINK = 16; + public static final short RTM_DELLINK = 17; + public static final short RTM_GETLINK = 18; + public static final short RTM_SETLINK = 19; + public static final short RTM_NEWADDR = 20; + public static final short RTM_DELADDR = 21; + public static final short RTM_GETADDR = 22; + public static final short RTM_NEWROUTE = 24; + public static final short RTM_DELROUTE = 25; + public static final short RTM_GETROUTE = 26; + public static final short RTM_NEWNEIGH = 28; + public static final short RTM_DELNEIGH = 29; + public static final short RTM_GETNEIGH = 30; + public static final short RTM_NEWRULE = 32; + public static final short RTM_DELRULE = 33; + public static final short RTM_GETRULE = 34; + public static final short RTM_NEWNDUSEROPT = 68; + + // Netfilter netlink message types are presented by two bytes: high byte subsystem and + // low byte operation. See the macro NFNL_SUBSYS_ID and NFNL_MSG_TYPE in + // include/uapi/linux/netfilter/nfnetlink.h + public static final short NFNL_SUBSYS_CTNETLINK = 1; + + public static final short IPCTNL_MSG_CT_NEW = 0; + public static final short IPCTNL_MSG_CT_GET = 1; + public static final short IPCTNL_MSG_CT_DELETE = 2; + public static final short IPCTNL_MSG_CT_GET_CTRZERO = 3; + public static final short IPCTNL_MSG_CT_GET_STATS_CPU = 4; + public static final short IPCTNL_MSG_CT_GET_STATS = 5; + public static final short IPCTNL_MSG_CT_GET_DYING = 6; + public static final short IPCTNL_MSG_CT_GET_UNCONFIRMED = 7; + + /* see include/uapi/linux/sock_diag.h */ + public static final short SOCK_DIAG_BY_FAMILY = 20; + + // Netlink groups. + public static final int RTNLGRP_ND_USEROPT = 20; + public static final int RTMGRP_ND_USEROPT = 1 << (RTNLGRP_ND_USEROPT - 1); + + /** + * Convert a netlink message type to a string for control message. + */ + @NonNull + private static String stringForCtlMsgType(short nlmType) { + switch (nlmType) { + case NLMSG_NOOP: return "NLMSG_NOOP"; + case NLMSG_ERROR: return "NLMSG_ERROR"; + case NLMSG_DONE: return "NLMSG_DONE"; + case NLMSG_OVERRUN: return "NLMSG_OVERRUN"; + default: return "unknown control message type: " + String.valueOf(nlmType); + } + } + + /** + * Convert a netlink message type to a string for NETLINK_ROUTE. + */ + @NonNull + private static String stringForRtMsgType(short nlmType) { + switch (nlmType) { + case RTM_NEWLINK: return "RTM_NEWLINK"; + case RTM_DELLINK: return "RTM_DELLINK"; + case RTM_GETLINK: return "RTM_GETLINK"; + case RTM_SETLINK: return "RTM_SETLINK"; + case RTM_NEWADDR: return "RTM_NEWADDR"; + case RTM_DELADDR: return "RTM_DELADDR"; + case RTM_GETADDR: return "RTM_GETADDR"; + case RTM_NEWROUTE: return "RTM_NEWROUTE"; + case RTM_DELROUTE: return "RTM_DELROUTE"; + case RTM_GETROUTE: return "RTM_GETROUTE"; + case RTM_NEWNEIGH: return "RTM_NEWNEIGH"; + case RTM_DELNEIGH: return "RTM_DELNEIGH"; + case RTM_GETNEIGH: return "RTM_GETNEIGH"; + case RTM_NEWRULE: return "RTM_NEWRULE"; + case RTM_DELRULE: return "RTM_DELRULE"; + case RTM_GETRULE: return "RTM_GETRULE"; + case RTM_NEWNDUSEROPT: return "RTM_NEWNDUSEROPT"; + default: return "unknown RTM type: " + String.valueOf(nlmType); + } + } + + /** + * Convert a netlink message type to a string for NETLINK_INET_DIAG. + */ + @NonNull + private static String stringForInetDiagMsgType(short nlmType) { + switch (nlmType) { + case SOCK_DIAG_BY_FAMILY: return "SOCK_DIAG_BY_FAMILY"; + default: return "unknown SOCK_DIAG type: " + String.valueOf(nlmType); + } + } + + /** + * Convert a netlink message type to a string for NETLINK_NETFILTER. + */ + @NonNull + private static String stringForNfMsgType(short nlmType) { + final byte subsysId = (byte) (nlmType >> 8); + final byte msgType = (byte) nlmType; + switch (subsysId) { + case NFNL_SUBSYS_CTNETLINK: + switch (msgType) { + case IPCTNL_MSG_CT_NEW: return "IPCTNL_MSG_CT_NEW"; + case IPCTNL_MSG_CT_GET: return "IPCTNL_MSG_CT_GET"; + case IPCTNL_MSG_CT_DELETE: return "IPCTNL_MSG_CT_DELETE"; + case IPCTNL_MSG_CT_GET_CTRZERO: return "IPCTNL_MSG_CT_GET_CTRZERO"; + case IPCTNL_MSG_CT_GET_STATS_CPU: return "IPCTNL_MSG_CT_GET_STATS_CPU"; + case IPCTNL_MSG_CT_GET_STATS: return "IPCTNL_MSG_CT_GET_STATS"; + case IPCTNL_MSG_CT_GET_DYING: return "IPCTNL_MSG_CT_GET_DYING"; + case IPCTNL_MSG_CT_GET_UNCONFIRMED: return "IPCTNL_MSG_CT_GET_UNCONFIRMED"; + } + break; + } + return "unknown NETFILTER type: " + String.valueOf(nlmType); + } + + /** + * Convert a netlink message type to a string by netlink family. + */ + @NonNull + public static String stringForNlMsgType(short nlmType, int nlFamily) { + // Reserved control messages. The netlink family is ignored. + // See NLMSG_MIN_TYPE in include/uapi/linux/netlink.h. + if (nlmType <= NLMSG_MAX_RESERVED) return stringForCtlMsgType(nlmType); + + // Netlink family messages. The netlink family is required. Note that the reason for using + // if-statement is that switch-case can't be used because the OsConstants.NETLINK_* are + // not constant. + if (nlFamily == OsConstants.NETLINK_ROUTE) return stringForRtMsgType(nlmType); + if (nlFamily == OsConstants.NETLINK_INET_DIAG) return stringForInetDiagMsgType(nlmType); + if (nlFamily == OsConstants.NETLINK_NETFILTER) return stringForNfMsgType(nlmType); + + return "unknown type: " + String.valueOf(nlmType); + } + + private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' }; + /** + * Convert a byte array to a hexadecimal string. + */ + public static String toHexString(byte[] array, int offset, int length) { + char[] buf = new char[length * 2]; + + int bufIndex = 0; + for (int i = offset; i < offset + length; i++) { + byte b = array[i]; + buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F]; + buf[bufIndex++] = HEX_DIGITS[b & 0x0F]; + } + + return new String(buf); + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkErrorMessage.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkErrorMessage.java new file mode 100644 index 0000000000..d9fb09e64f --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkErrorMessage.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util.netlink; + +import java.nio.ByteBuffer; + +/** + * A NetlinkMessage subclass for netlink error messages. + * + * @hide + */ +public class NetlinkErrorMessage extends NetlinkMessage { + + /** + * Parse a netlink error message from a {@link ByteBuffer}. + * + * @param byteBuffer The buffer from which to parse the netlink error message. + * @return the parsed netlink error message, or {@code null} if the netlink error message + * could not be parsed successfully (for example, if it was truncated). + */ + public static NetlinkErrorMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) { + final NetlinkErrorMessage errorMsg = new NetlinkErrorMessage(header); + + errorMsg.mNlMsgErr = StructNlMsgErr.parse(byteBuffer); + if (errorMsg.mNlMsgErr == null) { + return null; + } + + return errorMsg; + } + + private StructNlMsgErr mNlMsgErr; + + NetlinkErrorMessage(StructNlMsgHdr header) { + super(header); + mNlMsgErr = null; + } + + public StructNlMsgErr getNlMsgError() { + return mNlMsgErr; + } + + @Override + public String toString() { + return "NetlinkErrorMessage{ " + + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, " + + "nlmsgerr{" + (mNlMsgErr == null ? "" : mNlMsgErr.toString()) + "} " + + "}"; + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java new file mode 100644 index 0000000000..f425384f34 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util.netlink; + +import android.system.OsConstants; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.nio.ByteBuffer; + +/** + * NetlinkMessage base class for other, more specific netlink message types. + * + * Classes that extend NetlinkMessage should: + * - implement a public static parse(StructNlMsgHdr, ByteBuffer) method + * - returning either null (parse errors) or a new object of the subclass + * type (cast-able to NetlinkMessage) + * + * NetlinkMessage.parse() should be updated to know which nlmsg_type values + * correspond with which message subclasses. + * + * @hide + */ +public class NetlinkMessage { + private static final String TAG = "NetlinkMessage"; + + /** + * Parsing netlink messages for reserved control message or specific netlink message. The + * netlink family is required for parsing specific netlink message. See man-pages/netlink. + */ + @Nullable + public static NetlinkMessage parse(@NonNull ByteBuffer byteBuffer, int nlFamily) { + final int startPosition = (byteBuffer != null) ? byteBuffer.position() : -1; + final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(byteBuffer); + if (nlmsghdr == null) { + return null; + } + + int payloadLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len); + payloadLength -= StructNlMsgHdr.STRUCT_SIZE; + if (payloadLength < 0 || payloadLength > byteBuffer.remaining()) { + // Malformed message or runt buffer. Pretend the buffer was consumed. + byteBuffer.position(byteBuffer.limit()); + return null; + } + + // Reserved control messages. The netlink family is ignored. + // See NLMSG_MIN_TYPE in include/uapi/linux/netlink.h. + if (nlmsghdr.nlmsg_type <= NetlinkConstants.NLMSG_MAX_RESERVED) { + return parseCtlMessage(nlmsghdr, byteBuffer, payloadLength); + } + + // Netlink family messages. The netlink family is required. Note that the reason for using + // if-statement is that switch-case can't be used because the OsConstants.NETLINK_* are + // not constant. + if (nlFamily == OsConstants.NETLINK_ROUTE) { + return parseRtMessage(nlmsghdr, byteBuffer); + } else if (nlFamily == OsConstants.NETLINK_INET_DIAG) { + return parseInetDiagMessage(nlmsghdr, byteBuffer); + } else if (nlFamily == OsConstants.NETLINK_NETFILTER) { + return parseNfMessage(nlmsghdr, byteBuffer); + } + + return null; + } + + protected StructNlMsgHdr mHeader; + + public NetlinkMessage(StructNlMsgHdr nlmsghdr) { + mHeader = nlmsghdr; + } + + public StructNlMsgHdr getHeader() { + return mHeader; + } + + @Override + public String toString() { + // The netlink family is not provided to StructNlMsgHdr#toString because NetlinkMessage + // doesn't store the information. So the netlink message type can't be transformed into + // a string by StructNlMsgHdr#toString and just keep as an integer. The specific message + // which inherits NetlinkMessage could override NetlinkMessage#toString and provide the + // specific netlink family to StructNlMsgHdr#toString. + return "NetlinkMessage{" + (mHeader == null ? "" : mHeader.toString()) + "}"; + } + + @NonNull + private static NetlinkMessage parseCtlMessage(@NonNull StructNlMsgHdr nlmsghdr, + @NonNull ByteBuffer byteBuffer, int payloadLength) { + switch (nlmsghdr.nlmsg_type) { + case NetlinkConstants.NLMSG_ERROR: + return (NetlinkMessage) NetlinkErrorMessage.parse(nlmsghdr, byteBuffer); + default: { + // Other netlink control messages. Just parse the header for now, + // pretending the whole message was consumed. + byteBuffer.position(byteBuffer.position() + payloadLength); + return new NetlinkMessage(nlmsghdr); + } + } + } + + @Nullable + private static NetlinkMessage parseRtMessage(@NonNull StructNlMsgHdr nlmsghdr, + @NonNull ByteBuffer byteBuffer) { + switch (nlmsghdr.nlmsg_type) { + case NetlinkConstants.RTM_NEWNEIGH: + case NetlinkConstants.RTM_DELNEIGH: + case NetlinkConstants.RTM_GETNEIGH: + return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer); + case NetlinkConstants.RTM_NEWNDUSEROPT: + return (NetlinkMessage) NduseroptMessage.parse(nlmsghdr, byteBuffer); + default: return null; + } + } + + @Nullable + private static NetlinkMessage parseInetDiagMessage(@NonNull StructNlMsgHdr nlmsghdr, + @NonNull ByteBuffer byteBuffer) { + switch (nlmsghdr.nlmsg_type) { + case NetlinkConstants.SOCK_DIAG_BY_FAMILY: + return (NetlinkMessage) InetDiagMessage.parse(nlmsghdr, byteBuffer); + default: return null; + } + } + + @Nullable + private static NetlinkMessage parseNfMessage(@NonNull StructNlMsgHdr nlmsghdr, + @NonNull ByteBuffer byteBuffer) { + switch (nlmsghdr.nlmsg_type) { + case NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8 + | NetlinkConstants.IPCTNL_MSG_CT_NEW: + case NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8 + | NetlinkConstants.IPCTNL_MSG_CT_DELETE: + return (NetlinkMessage) ConntrackMessage.parse(nlmsghdr, byteBuffer); + default: return null; + } + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkSocket.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkSocket.java new file mode 100644 index 0000000000..ec326dd7c2 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkSocket.java @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2015 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 com.android.net.module.util.netlink; + +import static android.net.util.SocketUtils.makeNetlinkSocketAddress; +import static android.system.OsConstants.AF_NETLINK; +import static android.system.OsConstants.EIO; +import static android.system.OsConstants.EPROTO; +import static android.system.OsConstants.ETIMEDOUT; +import static android.system.OsConstants.SOCK_DGRAM; +import static android.system.OsConstants.SOL_SOCKET; +import static android.system.OsConstants.SO_RCVBUF; +import static android.system.OsConstants.SO_RCVTIMEO; +import static android.system.OsConstants.SO_SNDTIMEO; + +import android.net.util.SocketUtils; +import android.system.ErrnoException; +import android.system.Os; +import android.system.StructTimeval; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.SocketException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + + +/** + * NetlinkSocket + * + * A small static class to assist with AF_NETLINK socket operations. + * + * @hide + */ +public class NetlinkSocket { + private static final String TAG = "NetlinkSocket"; + private static final long IO_TIMEOUT_MS = 300L; + + public static final int DEFAULT_RECV_BUFSIZE = 8 * 1024; + public static final int SOCKET_RECV_BUFSIZE = 64 * 1024; + + /** + * Send one netlink message to kernel via netlink socket. + * + * @param nlProto netlink protocol type. + * @param msg the raw bytes of netlink message to be sent. + */ + public static void sendOneShotKernelMessage(int nlProto, byte[] msg) throws ErrnoException { + final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage"; + final FileDescriptor fd = forProto(nlProto); + + try { + connectToKernel(fd); + sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT_MS); + final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT_MS); + // recvMessage() guaranteed to not return null if it did not throw. + final NetlinkMessage response = NetlinkMessage.parse(bytes, nlProto); + if (response != null && response instanceof NetlinkErrorMessage + && (((NetlinkErrorMessage) response).getNlMsgError() != null)) { + final int errno = ((NetlinkErrorMessage) response).getNlMsgError().error; + if (errno != 0) { + // TODO: consider ignoring EINVAL (-22), which appears to be + // normal when probing a neighbor for which the kernel does + // not already have / no longer has a link layer address. + Log.e(TAG, errPrefix + ", errmsg=" + response.toString()); + // Note: convert kernel errnos (negative) into userspace errnos (positive). + throw new ErrnoException(response.toString(), Math.abs(errno)); + } + } else { + final String errmsg; + if (response == null) { + bytes.position(0); + errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes); + } else { + errmsg = response.toString(); + } + Log.e(TAG, errPrefix + ", errmsg=" + errmsg); + throw new ErrnoException(errmsg, EPROTO); + } + } catch (InterruptedIOException e) { + Log.e(TAG, errPrefix, e); + throw new ErrnoException(errPrefix, ETIMEDOUT, e); + } catch (SocketException e) { + Log.e(TAG, errPrefix, e); + throw new ErrnoException(errPrefix, EIO, e); + } finally { + try { + SocketUtils.closeSocket(fd); + } catch (IOException e) { + // Nothing we can do here + } + } + } + + /** + * Create netlink socket with the given netlink protocol type. + * + * @return fd the fileDescriptor of the socket. + * Throw ErrnoException if the exception is thrown. + */ + public static FileDescriptor forProto(int nlProto) throws ErrnoException { + final FileDescriptor fd = Os.socket(AF_NETLINK, SOCK_DGRAM, nlProto); + Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, SOCKET_RECV_BUFSIZE); + return fd; + } + + /** + * Connect to kernel via netlink socket. + * + * Throw ErrnoException, SocketException if the exception is thrown. + */ + public static void connectToKernel(FileDescriptor fd) throws ErrnoException, SocketException { + Os.connect(fd, makeNetlinkSocketAddress(0, 0)); + } + + private static void checkTimeout(long timeoutMs) { + if (timeoutMs < 0) { + throw new IllegalArgumentException("Negative timeouts not permitted"); + } + } + + /** + * Wait up to |timeoutMs| (or until underlying socket error) for a + * netlink message of at most |bufsize| size. + * + * Multi-threaded calls with different timeouts will cause unexpected results. + */ + public static ByteBuffer recvMessage(FileDescriptor fd, int bufsize, long timeoutMs) + throws ErrnoException, IllegalArgumentException, InterruptedIOException { + checkTimeout(timeoutMs); + + Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs)); + + ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize); + int length = Os.read(fd, byteBuffer); + if (length == bufsize) { + Log.w(TAG, "maximum read"); + } + byteBuffer.position(0); + byteBuffer.limit(length); + byteBuffer.order(ByteOrder.nativeOrder()); + return byteBuffer; + } + + /** + * Send a message to a peer to which this socket has previously connected, + * waiting at most |timeoutMs| milliseconds for the send to complete. + * + * Multi-threaded calls with different timeouts will cause unexpected results. + */ + public static int sendMessage( + FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs) + throws ErrnoException, IllegalArgumentException, InterruptedIOException { + checkTimeout(timeoutMs); + Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs)); + return Os.write(fd, bytes, offset, count); + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkNeighborMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkNeighborMessage.java new file mode 100644 index 0000000000..a75ef8dd23 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkNeighborMessage.java @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util.netlink; + +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REPLACE; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; + +import android.system.OsConstants; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * A NetlinkMessage subclass for rtnetlink neighbor messages. + * + * see also: <linux_src>/include/uapi/linux/neighbour.h + * + * @hide + */ +public class RtNetlinkNeighborMessage extends NetlinkMessage { + public static final short NDA_UNSPEC = 0; + public static final short NDA_DST = 1; + public static final short NDA_LLADDR = 2; + public static final short NDA_CACHEINFO = 3; + public static final short NDA_PROBES = 4; + public static final short NDA_VLAN = 5; + public static final short NDA_PORT = 6; + public static final short NDA_VNI = 7; + public static final short NDA_IFINDEX = 8; + public static final short NDA_MASTER = 9; + + /** + * Parse routing socket netlink neighbor message from ByteBuffer. + * + * @param header netlink message header. + * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. + */ + public static RtNetlinkNeighborMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) { + final RtNetlinkNeighborMessage neighMsg = new RtNetlinkNeighborMessage(header); + + neighMsg.mNdmsg = StructNdMsg.parse(byteBuffer); + if (neighMsg.mNdmsg == null) { + return null; + } + + // Some of these are message-type dependent, and not always present. + final int baseOffset = byteBuffer.position(); + StructNlAttr nlAttr = StructNlAttr.findNextAttrOfType(NDA_DST, byteBuffer); + if (nlAttr != null) { + neighMsg.mDestination = nlAttr.getValueAsInetAddress(); + } + + byteBuffer.position(baseOffset); + nlAttr = StructNlAttr.findNextAttrOfType(NDA_LLADDR, byteBuffer); + if (nlAttr != null) { + neighMsg.mLinkLayerAddr = nlAttr.nla_value; + } + + byteBuffer.position(baseOffset); + nlAttr = StructNlAttr.findNextAttrOfType(NDA_PROBES, byteBuffer); + if (nlAttr != null) { + neighMsg.mNumProbes = nlAttr.getValueAsInt(0); + } + + byteBuffer.position(baseOffset); + nlAttr = StructNlAttr.findNextAttrOfType(NDA_CACHEINFO, byteBuffer); + if (nlAttr != null) { + neighMsg.mCacheInfo = StructNdaCacheInfo.parse(nlAttr.getValueAsByteBuffer()); + } + + final int kMinConsumed = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE; + final int kAdditionalSpace = NetlinkConstants.alignedLengthOf( + neighMsg.mHeader.nlmsg_len - kMinConsumed); + if (byteBuffer.remaining() < kAdditionalSpace) { + byteBuffer.position(byteBuffer.limit()); + } else { + byteBuffer.position(baseOffset + kAdditionalSpace); + } + + return neighMsg; + } + + /** + * A convenience method to create an RTM_GETNEIGH request message. + */ + public static byte[] newGetNeighborsRequest(int seqNo) { + final int length = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE; + final byte[] bytes = new byte[length]; + final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); + byteBuffer.order(ByteOrder.nativeOrder()); + + final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); + nlmsghdr.nlmsg_len = length; + nlmsghdr.nlmsg_type = NetlinkConstants.RTM_GETNEIGH; + nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + nlmsghdr.nlmsg_seq = seqNo; + nlmsghdr.pack(byteBuffer); + + final StructNdMsg ndmsg = new StructNdMsg(); + ndmsg.pack(byteBuffer); + + return bytes; + } + + /** + * A convenience method to create an RTM_NEWNEIGH message, to modify + * the kernel's state information for a specific neighbor. + */ + public static byte[] newNewNeighborMessage( + int seqNo, InetAddress ip, short nudState, int ifIndex, byte[] llAddr) { + final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); + nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWNEIGH; + nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE; + nlmsghdr.nlmsg_seq = seqNo; + + final RtNetlinkNeighborMessage msg = new RtNetlinkNeighborMessage(nlmsghdr); + msg.mNdmsg = new StructNdMsg(); + msg.mNdmsg.ndm_family = + (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET); + msg.mNdmsg.ndm_ifindex = ifIndex; + msg.mNdmsg.ndm_state = nudState; + msg.mDestination = ip; + msg.mLinkLayerAddr = llAddr; // might be null + + final byte[] bytes = new byte[msg.getRequiredSpace()]; + nlmsghdr.nlmsg_len = bytes.length; + final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); + byteBuffer.order(ByteOrder.nativeOrder()); + msg.pack(byteBuffer); + return bytes; + } + + private StructNdMsg mNdmsg; + private InetAddress mDestination; + private byte[] mLinkLayerAddr; + private int mNumProbes; + private StructNdaCacheInfo mCacheInfo; + + private RtNetlinkNeighborMessage(StructNlMsgHdr header) { + super(header); + mNdmsg = null; + mDestination = null; + mLinkLayerAddr = null; + mNumProbes = 0; + mCacheInfo = null; + } + + public StructNdMsg getNdHeader() { + return mNdmsg; + } + + public InetAddress getDestination() { + return mDestination; + } + + public byte[] getLinkLayerAddress() { + return mLinkLayerAddr; + } + + public int getProbes() { + return mNumProbes; + } + + public StructNdaCacheInfo getCacheInfo() { + return mCacheInfo; + } + + private int getRequiredSpace() { + int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE; + if (mDestination != null) { + spaceRequired += NetlinkConstants.alignedLengthOf( + StructNlAttr.NLA_HEADERLEN + mDestination.getAddress().length); + } + if (mLinkLayerAddr != null) { + spaceRequired += NetlinkConstants.alignedLengthOf( + StructNlAttr.NLA_HEADERLEN + mLinkLayerAddr.length); + } + // Currently we don't write messages with NDA_PROBES nor NDA_CACHEINFO + // attributes appended. Fix later, if necessary. + return spaceRequired; + } + + private static void packNlAttr(short nlType, byte[] nlValue, ByteBuffer byteBuffer) { + final StructNlAttr nlAttr = new StructNlAttr(); + nlAttr.nla_type = nlType; + nlAttr.nla_value = nlValue; + nlAttr.nla_len = (short) (StructNlAttr.NLA_HEADERLEN + nlAttr.nla_value.length); + nlAttr.pack(byteBuffer); + } + + /** + * Write a neighbor discovery netlink message to {@link ByteBuffer}. + */ + public void pack(ByteBuffer byteBuffer) { + getHeader().pack(byteBuffer); + mNdmsg.pack(byteBuffer); + + if (mDestination != null) { + packNlAttr(NDA_DST, mDestination.getAddress(), byteBuffer); + } + if (mLinkLayerAddr != null) { + packNlAttr(NDA_LLADDR, mLinkLayerAddr, byteBuffer); + } + } + + @Override + public String toString() { + final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress(); + return "RtNetlinkNeighborMessage{ " + + "nlmsghdr{" + + (mHeader == null ? "" : mHeader.toString(OsConstants.NETLINK_ROUTE)) + "}, " + + "ndmsg{" + (mNdmsg == null ? "" : mNdmsg.toString()) + "}, " + + "destination{" + ipLiteral + "} " + + "linklayeraddr{" + NetlinkConstants.hexify(mLinkLayerAddr) + "} " + + "probes{" + mNumProbes + "} " + + "cacheinfo{" + (mCacheInfo == null ? "" : mCacheInfo.toString()) + "} " + + "}"; + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagMsg.java new file mode 100644 index 0000000000..205656e3b5 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagMsg.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util.netlink; + +import java.nio.ByteBuffer; + +/** + * struct inet_diag_msg + * + * see <linux_src>/include/uapi/linux/inet_diag.h + * + * struct inet_diag_msg { + * __u8 idiag_family; + * __u8 idiag_state; + * __u8 idiag_timer; + * __u8 idiag_retrans; + * struct inet_diag_sockid id; + * __u32 idiag_expires; + * __u32 idiag_rqueue; + * __u32 idiag_wqueue; + * __u32 idiag_uid; + * __u32 idiag_inode; + * }; + * + * @hide + */ +public class StructInetDiagMsg { + public static final int STRUCT_SIZE = 4 + StructInetDiagSockId.STRUCT_SIZE + 20; + private static final int IDIAG_UID_OFFSET = StructNlMsgHdr.STRUCT_SIZE + 4 + + StructInetDiagSockId.STRUCT_SIZE + 12; + public int idiag_uid; + + /** + * Parse inet diag netlink message from buffer. + */ + public static StructInetDiagMsg parse(ByteBuffer byteBuffer) { + StructInetDiagMsg struct = new StructInetDiagMsg(); + struct.idiag_uid = byteBuffer.getInt(IDIAG_UID_OFFSET); + return struct; + } + + @Override + public String toString() { + return "StructInetDiagMsg{ " + + "idiag_uid{" + idiag_uid + "}, " + + "}"; + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java new file mode 100644 index 0000000000..6eef8653fe --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util.netlink; + +import androidx.annotation.Nullable; + +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; + +/** + * struct inet_diag_req_v2 + * + * see <linux_src>/include/uapi/linux/inet_diag.h + * + * struct inet_diag_req_v2 { + * __u8 sdiag_family; + * __u8 sdiag_protocol; + * __u8 idiag_ext; + * __u8 pad; + * __u32 idiag_states; + * struct inet_diag_sockid id; + * }; + * + * @hide + */ +public class StructInetDiagReqV2 { + public static final int STRUCT_SIZE = 8 + StructInetDiagSockId.STRUCT_SIZE; + + private final byte mSdiagFamily; + private final byte mSdiagProtocol; + private final byte mIdiagExt; + private final byte mPad; + private final StructInetDiagSockId mId; + private final int mState; + public static final int INET_DIAG_REQ_V2_ALL_STATES = (int) 0xffffffff; + + public StructInetDiagReqV2(int protocol, InetSocketAddress local, InetSocketAddress remote, + int family) { + this(protocol, local, remote, family, 0 /* pad */, 0 /* extension */, + INET_DIAG_REQ_V2_ALL_STATES); + } + + public StructInetDiagReqV2(int protocol, @Nullable InetSocketAddress local, + @Nullable InetSocketAddress remote, int family, int pad, int extension, int state) + throws NullPointerException { + mSdiagFamily = (byte) family; + mSdiagProtocol = (byte) protocol; + // Request for all sockets if no specific socket is requested. Specify the local and remote + // socket address information for target request socket. + if ((local == null) != (remote == null)) { + throw new NullPointerException("Local and remote must be both null or both non-null"); + } + mId = ((local != null && remote != null) ? new StructInetDiagSockId(local, remote) : null); + mPad = (byte) pad; + mIdiagExt = (byte) extension; + mState = state; + } + + /** + * Write the int diag request v2 message to ByteBuffer. + */ + public void pack(ByteBuffer byteBuffer) { + // The ByteOrder must have already been set by the caller. + byteBuffer.put((byte) mSdiagFamily); + byteBuffer.put((byte) mSdiagProtocol); + byteBuffer.put((byte) mIdiagExt); + byteBuffer.put((byte) mPad); + byteBuffer.putInt(mState); + if (mId != null) mId.pack(byteBuffer); + } + + @Override + public String toString() { + final String familyStr = NetlinkConstants.stringForAddressFamily(mSdiagFamily); + final String protocolStr = NetlinkConstants.stringForAddressFamily(mSdiagProtocol); + + return "StructInetDiagReqV2{ " + + "sdiag_family{" + familyStr + "}, " + + "sdiag_protocol{" + protocolStr + "}, " + + "idiag_ext{" + mIdiagExt + ")}, " + + "pad{" + mPad + "}, " + + "idiag_states{" + Integer.toHexString(mState) + "}, " + + ((mId != null) ? mId.toString() : "inet_diag_sockid=null") + + "}"; + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java new file mode 100644 index 0000000000..95d60e5319 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2018 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 com.android.net.module.util.netlink; + +import static java.nio.ByteOrder.BIG_ENDIAN; + +import java.net.Inet4Address; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * struct inet_diag_req_v2 + * + * see <linux_src>/include/uapi/linux/inet_diag.h + * + * struct inet_diag_sockid { + * __be16 idiag_sport; + * __be16 idiag_dport; + * __be32 idiag_src[4]; + * __be32 idiag_dst[4]; + * __u32 idiag_if; + * __u32 idiag_cookie[2]; + * #define INET_DIAG_NOCOOKIE (~0U) + * }; + * + * @hide + */ +public class StructInetDiagSockId { + public static final int STRUCT_SIZE = 48; + + private static final byte[] INET_DIAG_NOCOOKIE = new byte[]{ + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}; + private static final byte[] IPV4_PADDING = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + private final InetSocketAddress mLocSocketAddress; + private final InetSocketAddress mRemSocketAddress; + + public StructInetDiagSockId(InetSocketAddress loc, InetSocketAddress rem) { + mLocSocketAddress = loc; + mRemSocketAddress = rem; + } + + /** + * Write inet diag socket id message to ByteBuffer in big endian. + */ + public void pack(ByteBuffer byteBuffer) { + byteBuffer.order(BIG_ENDIAN); + byteBuffer.putShort((short) mLocSocketAddress.getPort()); + byteBuffer.putShort((short) mRemSocketAddress.getPort()); + byteBuffer.put(mLocSocketAddress.getAddress().getAddress()); + if (mLocSocketAddress.getAddress() instanceof Inet4Address) { + byteBuffer.put(IPV4_PADDING); + } + byteBuffer.put(mRemSocketAddress.getAddress().getAddress()); + if (mRemSocketAddress.getAddress() instanceof Inet4Address) { + byteBuffer.put(IPV4_PADDING); + } + byteBuffer.order(ByteOrder.nativeOrder()); + byteBuffer.putInt(0); + byteBuffer.put(INET_DIAG_NOCOOKIE); + } + + @Override + public String toString() { + return "StructInetDiagSockId{ " + + "idiag_sport{" + mLocSocketAddress.getPort() + "}, " + + "idiag_dport{" + mRemSocketAddress.getPort() + "}, " + + "idiag_src{" + mLocSocketAddress.getAddress().getHostAddress() + "}, " + + "idiag_dst{" + mRemSocketAddress.getAddress().getHostAddress() + "}, " + + "idiag_if{" + 0 + "} " + + "idiag_cookie{INET_DIAG_NOCOOKIE}" + + "}"; + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNdMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructNdMsg.java new file mode 100644 index 0000000000..53ce89918a --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNdMsg.java @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util.netlink; + +import android.system.OsConstants; + +import java.nio.ByteBuffer; + +/** + * struct ndmsg + * + * see: <linux_src>/include/uapi/linux/neighbour.h + * + * @hide + */ +public class StructNdMsg { + // Already aligned. + public static final int STRUCT_SIZE = 12; + + // Neighbor Cache Entry States + public static final short NUD_NONE = 0x00; + public static final short NUD_INCOMPLETE = 0x01; + public static final short NUD_REACHABLE = 0x02; + public static final short NUD_STALE = 0x04; + public static final short NUD_DELAY = 0x08; + public static final short NUD_PROBE = 0x10; + public static final short NUD_FAILED = 0x20; + public static final short NUD_NOARP = 0x40; + public static final short NUD_PERMANENT = 0x80; + + /** + * Convert neighbor cache entry state integer to string. + */ + public static String stringForNudState(short nudState) { + switch (nudState) { + case NUD_NONE: return "NUD_NONE"; + case NUD_INCOMPLETE: return "NUD_INCOMPLETE"; + case NUD_REACHABLE: return "NUD_REACHABLE"; + case NUD_STALE: return "NUD_STALE"; + case NUD_DELAY: return "NUD_DELAY"; + case NUD_PROBE: return "NUD_PROBE"; + case NUD_FAILED: return "NUD_FAILED"; + case NUD_NOARP: return "NUD_NOARP"; + case NUD_PERMANENT: return "NUD_PERMANENT"; + default: + return "unknown NUD state: " + String.valueOf(nudState); + } + } + + /** + * Check whether a neighbor is connected or not. + */ + public static boolean isNudStateConnected(short nudState) { + return ((nudState & (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE)) != 0); + } + + /** + * Check whether a neighbor is in the valid NUD state or not. + */ + public static boolean isNudStateValid(short nudState) { + return (isNudStateConnected(nudState) + || ((nudState & (NUD_PROBE | NUD_STALE | NUD_DELAY)) != 0)); + } + + // Neighbor Cache Entry Flags + public static byte NTF_USE = (byte) 0x01; + public static byte NTF_SELF = (byte) 0x02; + public static byte NTF_MASTER = (byte) 0x04; + public static byte NTF_PROXY = (byte) 0x08; + public static byte NTF_ROUTER = (byte) 0x80; + + private static String stringForNudFlags(byte flags) { + final StringBuilder sb = new StringBuilder(); + if ((flags & NTF_USE) != 0) { + sb.append("NTF_USE"); + } + if ((flags & NTF_SELF) != 0) { + if (sb.length() > 0) { + sb.append("|"); + } + sb.append("NTF_SELF"); + } + if ((flags & NTF_MASTER) != 0) { + if (sb.length() > 0) { + sb.append("|"); + } + sb.append("NTF_MASTER"); + } + if ((flags & NTF_PROXY) != 0) { + if (sb.length() > 0) { + sb.append("|"); + } + sb.append("NTF_PROXY"); + } + if ((flags & NTF_ROUTER) != 0) { + if (sb.length() > 0) { + sb.append("|"); + } + sb.append("NTF_ROUTER"); + } + return sb.toString(); + } + + private static boolean hasAvailableSpace(ByteBuffer byteBuffer) { + return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE; + } + + /** + * Parse a neighbor discovery netlink message header from a {@link ByteBuffer}. + * + * @param byteBuffer The buffer from which to parse the nd netlink message header. + * @return the parsed nd netlink message header, or {@code null} if the nd netlink message + * header could not be parsed successfully (for example, if it was truncated). + */ + public static StructNdMsg parse(ByteBuffer byteBuffer) { + if (!hasAvailableSpace(byteBuffer)) return null; + + // The ByteOrder must have already been set by the caller. In most + // cases ByteOrder.nativeOrder() is correct, with the possible + // exception of usage within unittests. + final StructNdMsg struct = new StructNdMsg(); + struct.ndm_family = byteBuffer.get(); + final byte pad1 = byteBuffer.get(); + final short pad2 = byteBuffer.getShort(); + struct.ndm_ifindex = byteBuffer.getInt(); + struct.ndm_state = byteBuffer.getShort(); + struct.ndm_flags = byteBuffer.get(); + struct.ndm_type = byteBuffer.get(); + return struct; + } + + public byte ndm_family; + public int ndm_ifindex; + public short ndm_state; + public byte ndm_flags; + public byte ndm_type; + + public StructNdMsg() { + ndm_family = (byte) OsConstants.AF_UNSPEC; + } + + /** + * Write the neighbor discovery message header to {@link ByteBuffer}. + */ + public void pack(ByteBuffer byteBuffer) { + // The ByteOrder must have already been set by the caller. In most + // cases ByteOrder.nativeOrder() is correct, with the exception + // of usage within unittests. + byteBuffer.put(ndm_family); + byteBuffer.put((byte) 0); // pad1 + byteBuffer.putShort((short) 0); // pad2 + byteBuffer.putInt(ndm_ifindex); + byteBuffer.putShort(ndm_state); + byteBuffer.put(ndm_flags); + byteBuffer.put(ndm_type); + } + + /** + * Check whether a neighbor is connected or not. + */ + public boolean nudConnected() { + return isNudStateConnected(ndm_state); + } + + /** + * Check whether a neighbor is in the valid NUD state or not. + */ + public boolean nudValid() { + return isNudStateValid(ndm_state); + } + + @Override + public String toString() { + final String stateStr = "" + ndm_state + " (" + stringForNudState(ndm_state) + ")"; + final String flagsStr = "" + ndm_flags + " (" + stringForNudFlags(ndm_flags) + ")"; + return "StructNdMsg{ " + + "family{" + NetlinkConstants.stringForAddressFamily((int) ndm_family) + "}, " + + "ifindex{" + ndm_ifindex + "}, " + + "state{" + stateStr + "}, " + + "flags{" + flagsStr + "}, " + + "type{" + ndm_type + "} " + + "}"; + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java b/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java new file mode 100644 index 0000000000..bde6983187 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util.netlink; + +import android.net.IpPrefix; +import android.util.Log; + +import androidx.annotation.NonNull; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.util.Objects; + +/** + * The PREF64 router advertisement option. RFC 8781. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Scaled Lifetime | PLC | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | Highest 96 bits of the Prefix | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ +public class StructNdOptPref64 extends NdOption { + public static final int STRUCT_SIZE = 16; + public static final int TYPE = 38; + public static final byte LENGTH = 2; + + private static final String TAG = StructNdOptPref64.class.getSimpleName(); + + /** + * How many seconds the prefix is expected to remain valid. + * Valid values are from 0 to 65528 in multiples of 8. + */ + public final int lifetime; + /** The NAT64 prefix. */ + @NonNull public final IpPrefix prefix; + + static int plcToPrefixLength(int plc) { + switch (plc) { + case 0: return 96; + case 1: return 64; + case 2: return 56; + case 3: return 48; + case 4: return 40; + case 5: return 32; + default: + throw new IllegalArgumentException("Invalid prefix length code " + plc); + } + } + + static int prefixLengthToPlc(int prefixLength) { + switch (prefixLength) { + case 96: return 0; + case 64: return 1; + case 56: return 2; + case 48: return 3; + case 40: return 4; + case 32: return 5; + default: + throw new IllegalArgumentException("Invalid prefix length " + prefixLength); + } + } + + /** + * Returns the 2-byte "scaled lifetime and prefix length code" field: 13-bit lifetime, 3-bit PLC + */ + static short getScaledLifetimePlc(int lifetime, int prefixLengthCode) { + return (short) ((lifetime & 0xfff8) | (prefixLengthCode & 0x7)); + } + + public StructNdOptPref64(@NonNull IpPrefix prefix, int lifetime) { + super((byte) TYPE, LENGTH); + + Objects.requireNonNull(prefix, "prefix must not be null"); + if (!(prefix.getAddress() instanceof Inet6Address)) { + throw new IllegalArgumentException("Must be an IPv6 prefix: " + prefix); + } + prefixLengthToPlc(prefix.getPrefixLength()); // Throw if the prefix length is invalid. + this.prefix = prefix; + + if (lifetime < 0 || lifetime > 0xfff8) { + throw new IllegalArgumentException("Invalid lifetime " + lifetime); + } + this.lifetime = lifetime & 0xfff8; + } + + private StructNdOptPref64(@NonNull ByteBuffer buf) { + super(buf.get(), Byte.toUnsignedInt(buf.get())); + if (type != TYPE) throw new IllegalArgumentException("Invalid type " + type); + if (length != LENGTH) throw new IllegalArgumentException("Invalid length " + length); + + int scaledLifetimePlc = Short.toUnsignedInt(buf.getShort()); + lifetime = scaledLifetimePlc & 0xfff8; + + byte[] addressBytes = new byte[16]; + buf.get(addressBytes, 0, 12); + InetAddress addr; + try { + addr = InetAddress.getByAddress(addressBytes); + } catch (UnknownHostException e) { + throw new AssertionError("16-byte array not valid InetAddress?"); + } + prefix = new IpPrefix(addr, plcToPrefixLength(scaledLifetimePlc & 7)); + } + + /** + * Parses an option from a {@link ByteBuffer}. + * + * @param buf The buffer from which to parse the option. The buffer's byte order must be + * {@link java.nio.ByteOrder#BIG_ENDIAN}. + * @return the parsed option, or {@code null} if the option could not be parsed successfully + * (for example, if it was truncated, or if the prefix length code was wrong). + */ + public static StructNdOptPref64 parse(@NonNull ByteBuffer buf) { + if (buf == null || buf.remaining() < STRUCT_SIZE) return null; + try { + return new StructNdOptPref64(buf); + } catch (IllegalArgumentException e) { + // Not great, but better than throwing an exception that might crash the caller. + // Convention in this package is that null indicates that the option was truncated, so + // callers must already handle it. + Log.d(TAG, "Invalid PREF64 option: " + e); + return null; + } + } + + protected void writeToByteBuffer(ByteBuffer buf) { + super.writeToByteBuffer(buf); + buf.putShort(getScaledLifetimePlc(lifetime, prefixLengthToPlc(prefix.getPrefixLength()))); + buf.put(prefix.getRawAddress(), 0, 12); + } + + /** Outputs the wire format of the option to a new big-endian ByteBuffer. */ + public ByteBuffer toByteBuffer() { + ByteBuffer buf = ByteBuffer.allocate(STRUCT_SIZE); + writeToByteBuffer(buf); + buf.flip(); + return buf; + } + + @Override + @NonNull + public String toString() { + return String.format("NdOptPref64(%s, %d)", prefix, lifetime); + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNdaCacheInfo.java b/staticlibs/device/com/android/net/module/util/netlink/StructNdaCacheInfo.java new file mode 100644 index 0000000000..79d5ff4ad8 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNdaCacheInfo.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2015 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 com.android.net.module.util.netlink; + +import android.system.Os; +import android.system.OsConstants; + +import java.nio.ByteBuffer; + +/** + * struct nda_cacheinfo + * + * see: <linux_src>/include/uapi/linux/neighbour.h + * + * @hide + */ +public class StructNdaCacheInfo { + // Already aligned. + public static final int STRUCT_SIZE = 16; + + private static boolean hasAvailableSpace(ByteBuffer byteBuffer) { + return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE; + } + + /** + * Parse a nd cacheinfo netlink attribute from a {@link ByteBuffer}. + * + * @param byteBuffer The buffer from which to parse the nd cacheinfo attribute. + * @return the parsed nd cacheinfo attribute, or {@code null} if the nd cacheinfo attribute + * could not be parsed successfully (for example, if it was truncated). + */ + public static StructNdaCacheInfo parse(ByteBuffer byteBuffer) { + if (!hasAvailableSpace(byteBuffer)) return null; + + // The ByteOrder must have already been set by the caller. In most + // cases ByteOrder.nativeOrder() is correct, with the possible + // exception of usage within unittests. + final StructNdaCacheInfo struct = new StructNdaCacheInfo(); + struct.ndm_used = byteBuffer.getInt(); + struct.ndm_confirmed = byteBuffer.getInt(); + struct.ndm_updated = byteBuffer.getInt(); + struct.ndm_refcnt = byteBuffer.getInt(); + return struct; + } + + // TODO: investigate whether this can change during device runtime and + // decide what (if anything) should be done about that. + private static final long CLOCK_TICKS_PER_SECOND = Os.sysconf(OsConstants._SC_CLK_TCK); + + private static long ticksToMilliSeconds(int intClockTicks) { + final long longClockTicks = (long) intClockTicks & 0xffffffff; + return (longClockTicks * 1000) / CLOCK_TICKS_PER_SECOND; + } + + /** + * Explanatory notes, for reference. + * + * Before being returned to user space, the neighbor entry times are + * converted to clock_t's like so: + * + * ndm_used = jiffies_to_clock_t(now - neigh->used); + * ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed); + * ndm_updated = jiffies_to_clock_t(now - neigh->updated); + * + * meaning that these values are expressed as "clock ticks ago". To + * convert these clock ticks to seconds divide by sysconf(_SC_CLK_TCK). + * When _SC_CLK_TCK is 100, for example, the ndm_* times are expressed + * in centiseconds. + * + * These values are unsigned, but fortunately being expressed as "some + * clock ticks ago", these values are typically very small (and + * 2^31 centiseconds = 248 days). + * + * By observation, it appears that: + * ndm_used: the last time ARP/ND took place for this neighbor + * ndm_confirmed: the last time ARP/ND succeeded for this neighbor OR + * higher layer confirmation (TCP or MSG_CONFIRM) + * was received + * ndm_updated: the time when the current NUD state was entered + */ + public int ndm_used; + public int ndm_confirmed; + public int ndm_updated; + public int ndm_refcnt; + + public StructNdaCacheInfo() {} + + /** + * The last time ARP/ND took place for this neighbor. + */ + public long lastUsed() { + return ticksToMilliSeconds(ndm_used); + } + + /** + * The last time ARP/ND succeeded for this neighbor or higher layer confirmation (TCP or + * MSG_CONFIRM) was received. + */ + public long lastConfirmed() { + return ticksToMilliSeconds(ndm_confirmed); + } + + /** + * The time when the current NUD state was entered. + */ + public long lastUpdated() { + return ticksToMilliSeconds(ndm_updated); + } + + @Override + public String toString() { + return "NdaCacheInfo{ " + + "ndm_used{" + lastUsed() + "}, " + + "ndm_confirmed{" + lastConfirmed() + "}, " + + "ndm_updated{" + lastUpdated() + "}, " + + "ndm_refcnt{" + ndm_refcnt + "} " + + "}"; + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNfGenMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructNfGenMsg.java new file mode 100644 index 0000000000..2de5490bce --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNfGenMsg.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2017 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 com.android.net.module.util.netlink; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Objects; + +/** + * struct nfgenmsg + * + * see <linux_src>/include/uapi/linux/netfilter/nfnetlink.h + * + * @hide + */ +public class StructNfGenMsg { + public static final int STRUCT_SIZE = 2 + Short.BYTES; + + public static final int NFNETLINK_V0 = 0; + + public final byte nfgen_family; + public final byte version; + public final short res_id; // N.B.: this is big endian in the kernel + + /** + * Parse a netfilter netlink header from a {@link ByteBuffer}. + * + * @param byteBuffer The buffer from which to parse the netfilter netlink header. + * @return the parsed netfilter netlink header, or {@code null} if the netfilter netlink header + * could not be parsed successfully (for example, if it was truncated). + */ + @Nullable + public static StructNfGenMsg parse(@NonNull ByteBuffer byteBuffer) { + Objects.requireNonNull(byteBuffer); + + if (!hasAvailableSpace(byteBuffer)) return null; + + final byte nfgen_family = byteBuffer.get(); + final byte version = byteBuffer.get(); + + final ByteOrder originalOrder = byteBuffer.order(); + byteBuffer.order(ByteOrder.BIG_ENDIAN); + final short res_id = byteBuffer.getShort(); + byteBuffer.order(originalOrder); + + return new StructNfGenMsg(nfgen_family, version, res_id); + } + + public StructNfGenMsg(byte family, byte ver, short id) { + nfgen_family = family; + version = ver; + res_id = id; + } + + public StructNfGenMsg(byte family) { + nfgen_family = family; + version = (byte) NFNETLINK_V0; + res_id = (short) 0; + } + + /** + * Write a netfilter netlink header to a {@link ByteBuffer}. + */ + public void pack(ByteBuffer byteBuffer) { + byteBuffer.put(nfgen_family); + byteBuffer.put(version); + + final ByteOrder originalOrder = byteBuffer.order(); + byteBuffer.order(ByteOrder.BIG_ENDIAN); + byteBuffer.putShort(res_id); + byteBuffer.order(originalOrder); + } + + private static boolean hasAvailableSpace(@NonNull ByteBuffer byteBuffer) { + return byteBuffer.remaining() >= STRUCT_SIZE; + } + + @Override + public String toString() { + final String familyStr = NetlinkConstants.stringForAddressFamily(nfgen_family); + + return "NfGenMsg{ " + + "nfgen_family{" + familyStr + "}, " + + "version{" + Byte.toUnsignedInt(version) + "}, " + + "res_id{" + Short.toUnsignedInt(res_id) + "} " + + "}"; + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNlAttr.java b/staticlibs/device/com/android/net/module/util/netlink/StructNlAttr.java new file mode 100644 index 0000000000..80f00579bd --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNlAttr.java @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util.netlink; + +import androidx.annotation.Nullable; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * struct nlattr + * + * see: <linux_src>/include/uapi/linux/netlink.h + * + * @hide + */ +public class StructNlAttr { + // Already aligned. + public static final int NLA_HEADERLEN = 4; + public static final int NLA_F_NESTED = (1 << 15); + + /** + * Set carries nested attributes bit. + */ + public static short makeNestedType(short type) { + return (short) (type | NLA_F_NESTED); + } + + /** + * Peek and parse the netlink attribute from {@link ByteBuffer}. + * + * Return a (length, type) object only, without consuming any bytes in + * |byteBuffer| and without copying or interpreting any value bytes. + * This is used for scanning over a packed set of struct nlattr's, + * looking for instances of a particular type. + */ + public static StructNlAttr peek(ByteBuffer byteBuffer) { + if (byteBuffer == null || byteBuffer.remaining() < NLA_HEADERLEN) { + return null; + } + final int baseOffset = byteBuffer.position(); + + final StructNlAttr struct = new StructNlAttr(); + final ByteOrder originalOrder = byteBuffer.order(); + byteBuffer.order(ByteOrder.nativeOrder()); + try { + struct.nla_len = byteBuffer.getShort(); + struct.nla_type = byteBuffer.getShort(); + } finally { + byteBuffer.order(originalOrder); + } + + byteBuffer.position(baseOffset); + if (struct.nla_len < NLA_HEADERLEN) { + // Malformed. + return null; + } + return struct; + } + + /** + * Parse a netlink attribute from a {@link ByteBuffer}. + * + * @param byteBuffer The buffer from which to parse the netlink attriute. + * @return the parsed netlink attribute, or {@code null} if the netlink attribute + * could not be parsed successfully (for example, if it was truncated). + */ + public static StructNlAttr parse(ByteBuffer byteBuffer) { + final StructNlAttr struct = peek(byteBuffer); + if (struct == null || byteBuffer.remaining() < struct.getAlignedLength()) { + return null; + } + + final int baseOffset = byteBuffer.position(); + byteBuffer.position(baseOffset + NLA_HEADERLEN); + + int valueLen = ((int) struct.nla_len) & 0xffff; + valueLen -= NLA_HEADERLEN; + if (valueLen > 0) { + struct.nla_value = new byte[valueLen]; + byteBuffer.get(struct.nla_value, 0, valueLen); + byteBuffer.position(baseOffset + struct.getAlignedLength()); + } + return struct; + } + + /** + * Find next netlink attribute with a given type from {@link ByteBuffer}. + * + * @param attrType The given netlink attribute type is requested for. + * @param byteBuffer The buffer from which to find the netlink attribute. + * @return the found netlink attribute, or {@code null} if the netlink attribute could not be + * found or parsed successfully (for example, if it was truncated). + */ + @Nullable + public static StructNlAttr findNextAttrOfType(short attrType, + @Nullable ByteBuffer byteBuffer) { + while (byteBuffer != null && byteBuffer.remaining() > 0) { + final StructNlAttr nlAttr = StructNlAttr.peek(byteBuffer); + if (nlAttr == null) { + break; + } + if (nlAttr.nla_type == attrType) { + return StructNlAttr.parse(byteBuffer); + } + if (byteBuffer.remaining() < nlAttr.getAlignedLength()) { + break; + } + byteBuffer.position(byteBuffer.position() + nlAttr.getAlignedLength()); + } + return null; + } + + public short nla_len = (short) NLA_HEADERLEN; + public short nla_type; + public byte[] nla_value; + + public StructNlAttr() {} + + public StructNlAttr(short type, byte value) { + nla_type = type; + setValue(new byte[1]); + nla_value[0] = value; + } + + public StructNlAttr(short type, short value) { + this(type, value, ByteOrder.nativeOrder()); + } + + public StructNlAttr(short type, short value, ByteOrder order) { + nla_type = type; + setValue(new byte[Short.BYTES]); + final ByteBuffer buf = getValueAsByteBuffer(); + final ByteOrder originalOrder = buf.order(); + try { + buf.order(order); + buf.putShort(value); + } finally { + buf.order(originalOrder); + } + } + + public StructNlAttr(short type, int value) { + this(type, value, ByteOrder.nativeOrder()); + } + + public StructNlAttr(short type, int value, ByteOrder order) { + nla_type = type; + setValue(new byte[Integer.BYTES]); + final ByteBuffer buf = getValueAsByteBuffer(); + final ByteOrder originalOrder = buf.order(); + try { + buf.order(order); + buf.putInt(value); + } finally { + buf.order(originalOrder); + } + } + + public StructNlAttr(short type, InetAddress ip) { + nla_type = type; + setValue(ip.getAddress()); + } + + public StructNlAttr(short type, StructNlAttr... nested) { + this(); + nla_type = makeNestedType(type); + + int payloadLength = 0; + for (StructNlAttr nla : nested) payloadLength += nla.getAlignedLength(); + setValue(new byte[payloadLength]); + + final ByteBuffer buf = getValueAsByteBuffer(); + for (StructNlAttr nla : nested) { + nla.pack(buf); + } + } + + /** + * Get aligned attribute length. + */ + public int getAlignedLength() { + return NetlinkConstants.alignedLengthOf(nla_len); + } + + /** + * Get attribute value as BE16. + */ + public short getValueAsBe16(short defaultValue) { + final ByteBuffer byteBuffer = getValueAsByteBuffer(); + if (byteBuffer == null || byteBuffer.remaining() != Short.BYTES) { + return defaultValue; + } + final ByteOrder originalOrder = byteBuffer.order(); + try { + byteBuffer.order(ByteOrder.BIG_ENDIAN); + return byteBuffer.getShort(); + } finally { + byteBuffer.order(originalOrder); + } + } + + /** + * Get attribute value as BE32. + */ + public int getValueAsBe32(int defaultValue) { + final ByteBuffer byteBuffer = getValueAsByteBuffer(); + if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) { + return defaultValue; + } + final ByteOrder originalOrder = byteBuffer.order(); + try { + byteBuffer.order(ByteOrder.BIG_ENDIAN); + return byteBuffer.getInt(); + } finally { + byteBuffer.order(originalOrder); + } + } + + /** + * Get attribute value as ByteBuffer. + */ + public ByteBuffer getValueAsByteBuffer() { + if (nla_value == null) return null; + final ByteBuffer byteBuffer = ByteBuffer.wrap(nla_value); + // By convention, all buffers in this library are in native byte order because netlink is in + // native byte order. It's the order that is used by NetlinkSocket.recvMessage and the only + // order accepted by NetlinkMessage.parse. + byteBuffer.order(ByteOrder.nativeOrder()); + return byteBuffer; + } + + /** + * Get attribute value as byte. + */ + public byte getValueAsByte(byte defaultValue) { + final ByteBuffer byteBuffer = getValueAsByteBuffer(); + if (byteBuffer == null || byteBuffer.remaining() != Byte.BYTES) { + return defaultValue; + } + return getValueAsByteBuffer().get(); + } + + /** + * Get attribute value as Integer. + */ + public int getValueAsInt(int defaultValue) { + final ByteBuffer byteBuffer = getValueAsByteBuffer(); + if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) { + return defaultValue; + } + return getValueAsByteBuffer().getInt(); + } + + /** + * Get attribute value as InetAddress. + */ + public InetAddress getValueAsInetAddress() { + if (nla_value == null) return null; + + try { + return InetAddress.getByAddress(nla_value); + } catch (UnknownHostException ignored) { + return null; + } + } + + /** + * Write the netlink attribute to {@link ByteBuffer}. + */ + public void pack(ByteBuffer byteBuffer) { + final ByteOrder originalOrder = byteBuffer.order(); + final int originalPosition = byteBuffer.position(); + + byteBuffer.order(ByteOrder.nativeOrder()); + try { + byteBuffer.putShort(nla_len); + byteBuffer.putShort(nla_type); + if (nla_value != null) byteBuffer.put(nla_value); + } finally { + byteBuffer.order(originalOrder); + } + byteBuffer.position(originalPosition + getAlignedLength()); + } + + private void setValue(byte[] value) { + nla_value = value; + nla_len = (short) (NLA_HEADERLEN + ((nla_value != null) ? nla_value.length : 0)); + } + + @Override + public String toString() { + return "StructNlAttr{ " + + "nla_len{" + nla_len + "}, " + + "nla_type{" + nla_type + "}, " + + "nla_value{" + NetlinkConstants.hexify(nla_value) + "}, " + + "}"; + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNlMsgErr.java b/staticlibs/device/com/android/net/module/util/netlink/StructNlMsgErr.java new file mode 100644 index 0000000000..b6620f3bdc --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNlMsgErr.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util.netlink; + +import java.nio.ByteBuffer; + +/** + * struct nlmsgerr + * + * see <linux_src>/include/uapi/linux/netlink.h + * + * @hide + */ +public class StructNlMsgErr { + public static final int STRUCT_SIZE = Integer.BYTES + StructNlMsgHdr.STRUCT_SIZE; + + private static boolean hasAvailableSpace(ByteBuffer byteBuffer) { + return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE; + } + + /** + * Parse a netlink error message payload from a {@link ByteBuffer}. + * + * @param byteBuffer The buffer from which to parse the netlink error message payload. + * @return the parsed netlink error message payload, or {@code null} if the netlink error + * message payload could not be parsed successfully (for example, if it was truncated). + */ + public static StructNlMsgErr parse(ByteBuffer byteBuffer) { + if (!hasAvailableSpace(byteBuffer)) return null; + + // The ByteOrder must have already been set by the caller. In most + // cases ByteOrder.nativeOrder() is correct, with the exception + // of usage within unittests. + final StructNlMsgErr struct = new StructNlMsgErr(); + struct.error = byteBuffer.getInt(); + struct.msg = StructNlMsgHdr.parse(byteBuffer); + return struct; + } + + public int error; + public StructNlMsgHdr msg; + + /** + * Write the netlink error message payload to {@link ByteBuffer}. + */ + public void pack(ByteBuffer byteBuffer) { + // The ByteOrder must have already been set by the caller. In most + // cases ByteOrder.nativeOrder() is correct, with the possible + // exception of usage within unittests. + byteBuffer.putInt(error); + if (msg != null) { + msg.pack(byteBuffer); + } + } + + @Override + public String toString() { + return "StructNlMsgErr{ " + + "error{" + error + "}, " + + "msg{" + (msg == null ? "" : msg.toString()) + "} " + + "}"; + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNlMsgHdr.java b/staticlibs/device/com/android/net/module/util/netlink/StructNlMsgHdr.java new file mode 100644 index 0000000000..ddf1562f17 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNlMsgHdr.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util.netlink; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.nio.ByteBuffer; + +/** + * struct nlmsghdr + * + * see <linux_src>/include/uapi/linux/netlink.h + * + * @hide + */ +public class StructNlMsgHdr { + // Already aligned. + public static final int STRUCT_SIZE = 16; + + public static final short NLM_F_REQUEST = 0x0001; + public static final short NLM_F_MULTI = 0x0002; + public static final short NLM_F_ACK = 0x0004; + public static final short NLM_F_ECHO = 0x0008; + // Flags for a GET request. + public static final short NLM_F_ROOT = 0x0100; + public static final short NLM_F_MATCH = 0x0200; + public static final short NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH; + // Flags for a NEW request. + public static final short NLM_F_REPLACE = 0x100; + public static final short NLM_F_EXCL = 0x200; + public static final short NLM_F_CREATE = 0x400; + public static final short NLM_F_APPEND = 0x800; + + // TODO: Probably need to distinguish the flags which have the same value. For example, + // NLM_F_MATCH (0x200) and NLM_F_EXCL (0x200). + private static String stringForNlMsgFlags(short flags) { + final StringBuilder sb = new StringBuilder(); + if ((flags & NLM_F_REQUEST) != 0) { + sb.append("NLM_F_REQUEST"); + } + if ((flags & NLM_F_MULTI) != 0) { + if (sb.length() > 0) { + sb.append("|"); + } + sb.append("NLM_F_MULTI"); + } + if ((flags & NLM_F_ACK) != 0) { + if (sb.length() > 0) { + sb.append("|"); + } + sb.append("NLM_F_ACK"); + } + if ((flags & NLM_F_ECHO) != 0) { + if (sb.length() > 0) { + sb.append("|"); + } + sb.append("NLM_F_ECHO"); + } + if ((flags & NLM_F_ROOT) != 0) { + if (sb.length() > 0) { + sb.append("|"); + } + sb.append("NLM_F_ROOT"); + } + if ((flags & NLM_F_MATCH) != 0) { + if (sb.length() > 0) { + sb.append("|"); + } + sb.append("NLM_F_MATCH"); + } + return sb.toString(); + } + + private static boolean hasAvailableSpace(ByteBuffer byteBuffer) { + return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE; + } + + /** + * Parse netlink message header from buffer. + */ + public static StructNlMsgHdr parse(ByteBuffer byteBuffer) { + if (!hasAvailableSpace(byteBuffer)) return null; + + // The ByteOrder must have already been set by the caller. In most + // cases ByteOrder.nativeOrder() is correct, with the exception + // of usage within unittests. + final StructNlMsgHdr struct = new StructNlMsgHdr(); + struct.nlmsg_len = byteBuffer.getInt(); + struct.nlmsg_type = byteBuffer.getShort(); + struct.nlmsg_flags = byteBuffer.getShort(); + struct.nlmsg_seq = byteBuffer.getInt(); + struct.nlmsg_pid = byteBuffer.getInt(); + + if (struct.nlmsg_len < STRUCT_SIZE) { + // Malformed. + return null; + } + return struct; + } + + public int nlmsg_len; + public short nlmsg_type; + public short nlmsg_flags; + public int nlmsg_seq; + public int nlmsg_pid; + + public StructNlMsgHdr() { + nlmsg_len = 0; + nlmsg_type = 0; + nlmsg_flags = 0; + nlmsg_seq = 0; + nlmsg_pid = 0; + } + + /** + * Write netlink message header to ByteBuffer. + */ + public void pack(ByteBuffer byteBuffer) { + // The ByteOrder must have already been set by the caller. In most + // cases ByteOrder.nativeOrder() is correct, with the possible + // exception of usage within unittests. + byteBuffer.putInt(nlmsg_len); + byteBuffer.putShort(nlmsg_type); + byteBuffer.putShort(nlmsg_flags); + byteBuffer.putInt(nlmsg_seq); + byteBuffer.putInt(nlmsg_pid); + } + + @Override + public String toString() { + return toString(null /* unknown netlink family */); + } + + /** + * Transform a netlink header into a string. The netlink family is required for transforming + * a netlink type integer into a string. + * @param nlFamily netlink family. Using Integer will not incur autoboxing penalties because + * family values are small, and all Integer objects between -128 and 127 are + * statically cached. See Integer.IntegerCache. + * @return A list of header elements. + */ + @NonNull + public String toString(@Nullable Integer nlFamily) { + final String typeStr = "" + nlmsg_type + + "(" + (nlFamily == null + ? "" : NetlinkConstants.stringForNlMsgType(nlmsg_type, nlFamily)) + + ")"; + final String flagsStr = "" + nlmsg_flags + + "(" + stringForNlMsgFlags(nlmsg_flags) + ")"; + return "StructNlMsgHdr{ " + + "nlmsg_len{" + nlmsg_len + "}, " + + "nlmsg_type{" + typeStr + "}, " + + "nlmsg_flags{" + flagsStr + ")}, " + + "nlmsg_seq{" + nlmsg_seq + "}, " + + "nlmsg_pid{" + nlmsg_pid + "} " + + "}"; + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java b/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java index 1bdee295d8..49d7654d3a 100644 --- a/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java +++ b/staticlibs/device/com/android/net/module/util/structs/PrefixInformationOption.java @@ -18,9 +18,10 @@ package com.android.net.module.util.structs; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_PIO; -import android.annotation.NonNull; import android.net.IpPrefix; +import androidx.annotation.NonNull; + import com.android.net.module.util.Struct; import com.android.net.module.util.Struct.Field; import com.android.net.module.util.Struct.Type; diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/ConntrackMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/ConntrackMessageTest.java new file mode 100644 index 0000000000..cea763c75c --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/ConntrackMessageTest.java @@ -0,0 +1,433 @@ +/* + * Copyright (C) 2017 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 com.android.net.module.util.netlink; + +import static com.android.net.module.util.netlink.NetlinkConstants.IPCTNL_MSG_CT_NEW; +import static com.android.net.module.util.netlink.NetlinkConstants.NFNL_SUBSYS_CTNETLINK; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +import android.system.OsConstants; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import libcore.util.HexEncoding; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class ConntrackMessageTest { + private static final boolean USING_LE = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN); + + private short makeCtType(short msgType) { + return (short) (NFNL_SUBSYS_CTNETLINK << 8 | (byte) msgType); + } + + // Example 1: TCP (192.168.43.209, 44333) -> (23.211.13.26, 443) + public static final String CT_V4UPDATE_TCP_HEX = + // struct nlmsghdr + "50000000" + // length = 80 + "0001" + // type = (1 << 8) | 0 + "0501" + // flags + "01000000" + // seqno = 1 + "00000000" + // pid = 0 + // struct nfgenmsg + "02" + // nfgen_family = AF_INET + "00" + // version = NFNETLINK_V0 + "0000" + // res_id + // struct nlattr + "3400" + // nla_len = 52 + "0180" + // nla_type = nested CTA_TUPLE_ORIG + // struct nlattr + "1400" + // nla_len = 20 + "0180" + // nla_type = nested CTA_TUPLE_IP + "0800 0100 C0A82BD1" + // nla_type=CTA_IP_V4_SRC, ip=192.168.43.209 + "0800 0200 17D30D1A" + // nla_type=CTA_IP_V4_DST, ip=23.211.13.26 + // struct nlattr + "1C00" + // nla_len = 28 + "0280" + // nla_type = nested CTA_TUPLE_PROTO + "0500 0100 06 000000" + // nla_type=CTA_PROTO_NUM, proto=6 + "0600 0200 AD2D 0000" + // nla_type=CTA_PROTO_SRC_PORT, port=44333 (big endian) + "0600 0300 01BB 0000" + // nla_type=CTA_PROTO_DST_PORT, port=443 (big endian) + // struct nlattr + "0800" + // nla_len = 8 + "0700" + // nla_type = CTA_TIMEOUT + "00069780"; // nla_value = 432000 (big endian) + public static final byte[] CT_V4UPDATE_TCP_BYTES = + HexEncoding.decode(CT_V4UPDATE_TCP_HEX.replaceAll(" ", "").toCharArray(), false); + + private byte[] makeIPv4TimeoutUpdateRequestTcp() throws Exception { + return ConntrackMessage.newIPv4TimeoutUpdateRequest( + OsConstants.IPPROTO_TCP, + (Inet4Address) InetAddress.getByName("192.168.43.209"), 44333, + (Inet4Address) InetAddress.getByName("23.211.13.26"), 443, + 432000); + } + + // Example 2: UDP (100.96.167.146, 37069) -> (216.58.197.10, 443) + public static final String CT_V4UPDATE_UDP_HEX = + // struct nlmsghdr + "50000000" + // length = 80 + "0001" + // type = (1 << 8) | 0 + "0501" + // flags + "01000000" + // seqno = 1 + "00000000" + // pid = 0 + // struct nfgenmsg + "02" + // nfgen_family = AF_INET + "00" + // version = NFNETLINK_V0 + "0000" + // res_id + // struct nlattr + "3400" + // nla_len = 52 + "0180" + // nla_type = nested CTA_TUPLE_ORIG + // struct nlattr + "1400" + // nla_len = 20 + "0180" + // nla_type = nested CTA_TUPLE_IP + "0800 0100 6460A792" + // nla_type=CTA_IP_V4_SRC, ip=100.96.167.146 + "0800 0200 D83AC50A" + // nla_type=CTA_IP_V4_DST, ip=216.58.197.10 + // struct nlattr + "1C00" + // nla_len = 28 + "0280" + // nla_type = nested CTA_TUPLE_PROTO + "0500 0100 11 000000" + // nla_type=CTA_PROTO_NUM, proto=17 + "0600 0200 90CD 0000" + // nla_type=CTA_PROTO_SRC_PORT, port=37069 (big endian) + "0600 0300 01BB 0000" + // nla_type=CTA_PROTO_DST_PORT, port=443 (big endian) + // struct nlattr + "0800" + // nla_len = 8 + "0700" + // nla_type = CTA_TIMEOUT + "000000B4"; // nla_value = 180 (big endian) + public static final byte[] CT_V4UPDATE_UDP_BYTES = + HexEncoding.decode(CT_V4UPDATE_UDP_HEX.replaceAll(" ", "").toCharArray(), false); + + private byte[] makeIPv4TimeoutUpdateRequestUdp() throws Exception { + return ConntrackMessage.newIPv4TimeoutUpdateRequest( + OsConstants.IPPROTO_UDP, + (Inet4Address) InetAddress.getByName("100.96.167.146"), 37069, + (Inet4Address) InetAddress.getByName("216.58.197.10"), 443, + 180); + } + + @Test + public void testConntrackMakeIPv4TcpTimeoutUpdate() throws Exception { + assumeTrue(USING_LE); + + final byte[] tcp = makeIPv4TimeoutUpdateRequestTcp(); + assertArrayEquals(CT_V4UPDATE_TCP_BYTES, tcp); + } + + @Test + public void testConntrackParseIPv4TcpTimeoutUpdate() throws Exception { + assumeTrue(USING_LE); + + final byte[] tcp = makeIPv4TimeoutUpdateRequestTcp(); + final ByteBuffer byteBuffer = ByteBuffer.wrap(tcp); + byteBuffer.order(ByteOrder.nativeOrder()); + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, OsConstants.NETLINK_NETFILTER); + assertNotNull(msg); + assertTrue(msg instanceof ConntrackMessage); + final ConntrackMessage conntrackMessage = (ConntrackMessage) msg; + + final StructNlMsgHdr hdr = conntrackMessage.getHeader(); + assertNotNull(hdr); + assertEquals(80, hdr.nlmsg_len); + assertEquals(makeCtType(IPCTNL_MSG_CT_NEW), hdr.nlmsg_type); + assertEquals((short) (StructNlMsgHdr.NLM_F_REPLACE | StructNlMsgHdr.NLM_F_REQUEST + | StructNlMsgHdr.NLM_F_ACK), hdr.nlmsg_flags); + assertEquals(1, hdr.nlmsg_seq); + assertEquals(0, hdr.nlmsg_pid); + + final StructNfGenMsg nfmsgHdr = conntrackMessage.nfGenMsg; + assertNotNull(nfmsgHdr); + assertEquals((byte) OsConstants.AF_INET, nfmsgHdr.nfgen_family); + assertEquals((byte) StructNfGenMsg.NFNETLINK_V0, nfmsgHdr.version); + assertEquals((short) 0, nfmsgHdr.res_id); + + assertEquals(InetAddress.parseNumericAddress("192.168.43.209"), + conntrackMessage.tupleOrig.srcIp); + assertEquals(InetAddress.parseNumericAddress("23.211.13.26"), + conntrackMessage.tupleOrig.dstIp); + assertEquals((byte) OsConstants.IPPROTO_TCP, conntrackMessage.tupleOrig.protoNum); + assertEquals((short) 44333, conntrackMessage.tupleOrig.srcPort); + assertEquals((short) 443, conntrackMessage.tupleOrig.dstPort); + + assertNull(conntrackMessage.tupleReply); + + assertEquals(0 /* absent */, conntrackMessage.status); + assertEquals(432000, conntrackMessage.timeoutSec); + } + + @Test + public void testConntrackMakeIPv4UdpTimeoutUpdate() throws Exception { + assumeTrue(USING_LE); + + final byte[] udp = makeIPv4TimeoutUpdateRequestUdp(); + assertArrayEquals(CT_V4UPDATE_UDP_BYTES, udp); + } + + @Test + public void testConntrackParseIPv4UdpTimeoutUpdate() throws Exception { + assumeTrue(USING_LE); + + final byte[] udp = makeIPv4TimeoutUpdateRequestUdp(); + final ByteBuffer byteBuffer = ByteBuffer.wrap(udp); + byteBuffer.order(ByteOrder.nativeOrder()); + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, OsConstants.NETLINK_NETFILTER); + assertNotNull(msg); + assertTrue(msg instanceof ConntrackMessage); + final ConntrackMessage conntrackMessage = (ConntrackMessage) msg; + + final StructNlMsgHdr hdr = conntrackMessage.getHeader(); + assertNotNull(hdr); + assertEquals(80, hdr.nlmsg_len); + assertEquals(makeCtType(IPCTNL_MSG_CT_NEW), hdr.nlmsg_type); + assertEquals((short) (StructNlMsgHdr.NLM_F_REPLACE | StructNlMsgHdr.NLM_F_REQUEST + | StructNlMsgHdr.NLM_F_ACK), hdr.nlmsg_flags); + assertEquals(1, hdr.nlmsg_seq); + assertEquals(0, hdr.nlmsg_pid); + + final StructNfGenMsg nfmsgHdr = conntrackMessage.nfGenMsg; + assertNotNull(nfmsgHdr); + assertEquals((byte) OsConstants.AF_INET, nfmsgHdr.nfgen_family); + assertEquals((byte) StructNfGenMsg.NFNETLINK_V0, nfmsgHdr.version); + assertEquals((short) 0, nfmsgHdr.res_id); + + assertEquals(InetAddress.parseNumericAddress("100.96.167.146"), + conntrackMessage.tupleOrig.srcIp); + assertEquals(InetAddress.parseNumericAddress("216.58.197.10"), + conntrackMessage.tupleOrig.dstIp); + assertEquals((byte) OsConstants.IPPROTO_UDP, conntrackMessage.tupleOrig.protoNum); + assertEquals((short) 37069, conntrackMessage.tupleOrig.srcPort); + assertEquals((short) 443, conntrackMessage.tupleOrig.dstPort); + + assertNull(conntrackMessage.tupleReply); + + assertEquals(0 /* absent */, conntrackMessage.status); + assertEquals(180, conntrackMessage.timeoutSec); + } + + public static final String CT_V4NEW_TCP_HEX = + // CHECKSTYLE:OFF IndentationCheck + // struct nlmsghdr + "8C000000" + // length = 140 + "0001" + // type = NFNL_SUBSYS_CTNETLINK (1) << 8 | IPCTNL_MSG_CT_NEW (0) + "0006" + // flags = NLM_F_CREATE (1 << 10) | NLM_F_EXCL (1 << 9) + "00000000" + // seqno = 0 + "00000000" + // pid = 0 + // struct nfgenmsg + "02" + // nfgen_family = AF_INET + "00" + // version = NFNETLINK_V0 + "1234" + // res_id = 0x1234 (big endian) + // struct nlattr + "3400" + // nla_len = 52 + "0180" + // nla_type = nested CTA_TUPLE_ORIG + // struct nlattr + "1400" + // nla_len = 20 + "0180" + // nla_type = nested CTA_TUPLE_IP + "0800 0100 C0A8500C" + // nla_type=CTA_IP_V4_SRC, ip=192.168.80.12 + "0800 0200 8C700874" + // nla_type=CTA_IP_V4_DST, ip=140.112.8.116 + // struct nlattr + "1C00" + // nla_len = 28 + "0280" + // nla_type = nested CTA_TUPLE_PROTO + "0500 0100 06 000000" + // nla_type=CTA_PROTO_NUM, proto=IPPROTO_TCP (6) + "0600 0200 F3F1 0000" + // nla_type=CTA_PROTO_SRC_PORT, port=62449 (big endian) + "0600 0300 01BB 0000" + // nla_type=CTA_PROTO_DST_PORT, port=443 (big endian) + // struct nlattr + "3400" + // nla_len = 52 + "0280" + // nla_type = nested CTA_TUPLE_REPLY + // struct nlattr + "1400" + // nla_len = 20 + "0180" + // nla_type = nested CTA_TUPLE_IP + "0800 0100 8C700874" + // nla_type=CTA_IP_V4_SRC, ip=140.112.8.116 + "0800 0200 6451B301" + // nla_type=CTA_IP_V4_DST, ip=100.81.179.1 + // struct nlattr + "1C00" + // nla_len = 28 + "0280" + // nla_type = nested CTA_TUPLE_PROTO + "0500 0100 06 000000" + // nla_type=CTA_PROTO_NUM, proto=IPPROTO_TCP (6) + "0600 0200 01BB 0000" + // nla_type=CTA_PROTO_SRC_PORT, port=443 (big endian) + "0600 0300 F3F1 0000" + // nla_type=CTA_PROTO_DST_PORT, port=62449 (big endian) + // struct nlattr + "0800" + // nla_len = 8 + "0300" + // nla_type = CTA_STATUS + "00000198" + // nla_value = 0b110011000 (big endian) + // IPS_CONFIRMED (1 << 3) | IPS_SRC_NAT (1 << 4) | + // IPS_SRC_NAT_DONE (1 << 7) | IPS_DST_NAT_DONE (1 << 8) + // struct nlattr + "0800" + // nla_len = 8 + "0700" + // nla_type = CTA_TIMEOUT + "00000078"; // nla_value = 120 (big endian) + // CHECKSTYLE:ON IndentationCheck + public static final byte[] CT_V4NEW_TCP_BYTES = + HexEncoding.decode(CT_V4NEW_TCP_HEX.replaceAll(" ", "").toCharArray(), false); + + @Test + public void testParseCtNew() { + assumeTrue(USING_LE); + + final ByteBuffer byteBuffer = ByteBuffer.wrap(CT_V4NEW_TCP_BYTES); + byteBuffer.order(ByteOrder.nativeOrder()); + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, OsConstants.NETLINK_NETFILTER); + assertNotNull(msg); + assertTrue(msg instanceof ConntrackMessage); + final ConntrackMessage conntrackMessage = (ConntrackMessage) msg; + + final StructNlMsgHdr hdr = conntrackMessage.getHeader(); + assertNotNull(hdr); + assertEquals(140, hdr.nlmsg_len); + assertEquals(makeCtType(IPCTNL_MSG_CT_NEW), hdr.nlmsg_type); + assertEquals((short) (StructNlMsgHdr.NLM_F_CREATE | StructNlMsgHdr.NLM_F_EXCL), + hdr.nlmsg_flags); + assertEquals(0, hdr.nlmsg_seq); + assertEquals(0, hdr.nlmsg_pid); + + final StructNfGenMsg nfmsgHdr = conntrackMessage.nfGenMsg; + assertNotNull(nfmsgHdr); + assertEquals((byte) OsConstants.AF_INET, nfmsgHdr.nfgen_family); + assertEquals((byte) StructNfGenMsg.NFNETLINK_V0, nfmsgHdr.version); + assertEquals((short) 0x1234, nfmsgHdr.res_id); + + assertEquals(InetAddress.parseNumericAddress("192.168.80.12"), + conntrackMessage.tupleOrig.srcIp); + assertEquals(InetAddress.parseNumericAddress("140.112.8.116"), + conntrackMessage.tupleOrig.dstIp); + assertEquals((byte) OsConstants.IPPROTO_TCP, conntrackMessage.tupleOrig.protoNum); + assertEquals((short) 62449, conntrackMessage.tupleOrig.srcPort); + assertEquals((short) 443, conntrackMessage.tupleOrig.dstPort); + + assertEquals(InetAddress.parseNumericAddress("140.112.8.116"), + conntrackMessage.tupleReply.srcIp); + assertEquals(InetAddress.parseNumericAddress("100.81.179.1"), + conntrackMessage.tupleReply.dstIp); + assertEquals((byte) OsConstants.IPPROTO_TCP, conntrackMessage.tupleReply.protoNum); + assertEquals((short) 443, conntrackMessage.tupleReply.srcPort); + assertEquals((short) 62449, conntrackMessage.tupleReply.dstPort); + + assertEquals(0x198, conntrackMessage.status); + assertEquals(120, conntrackMessage.timeoutSec); + } + + @Test + public void testParseTruncation() { + assumeTrue(USING_LE); + + // Expect no crash while parsing the truncated message which has been truncated to every + // length between 0 and its full length - 1. + for (int len = 0; len < CT_V4NEW_TCP_BYTES.length; len++) { + final byte[] truncated = Arrays.copyOfRange(CT_V4NEW_TCP_BYTES, 0, len); + + final ByteBuffer byteBuffer = ByteBuffer.wrap(truncated); + byteBuffer.order(ByteOrder.nativeOrder()); + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, + OsConstants.NETLINK_NETFILTER); + } + } + + @Test + public void testParseTruncationWithInvalidByte() { + assumeTrue(USING_LE); + + // Expect no crash while parsing the message which is truncated by invalid bytes. The + // message has been truncated to every length between 0 and its full length - 1. + for (byte invalid : new byte[]{(byte) 0x00, (byte) 0xff}) { + for (int len = 0; len < CT_V4NEW_TCP_BYTES.length; len++) { + final byte[] truncated = new byte[CT_V4NEW_TCP_BYTES.length]; + Arrays.fill(truncated, (byte) invalid); + System.arraycopy(CT_V4NEW_TCP_BYTES, 0, truncated, 0, len); + + final ByteBuffer byteBuffer = ByteBuffer.wrap(truncated); + byteBuffer.order(ByteOrder.nativeOrder()); + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, + OsConstants.NETLINK_NETFILTER); + } + } + } + + // Malformed conntrack messages. + public static final String CT_MALFORMED_HEX = + // CHECKSTYLE:OFF IndentationCheck + // <-- nlmsghr -->|<-nfgenmsg->|<-- CTA_TUPLE_ORIG -->| + // CTA_TUPLE_ORIG has no nla_value. + "18000000 0001 0006 00000000 00000000 02 00 0000 0400 0180" + // nested CTA_TUPLE_IP has no nla_value. + + "1C000000 0001 0006 00000000 00000000 02 00 0000 0800 0180 0400 0180" + // nested CTA_IP_V4_SRC has no nla_value. + + "20000000 0001 0006 00000000 00000000 02 00 0000 0C00 0180 0800 0180 0400 0100" + // nested CTA_TUPLE_PROTO has no nla_value. + // <-- nlmsghr -->|<-nfgenmsg->|<-- CTA_TUPLE_ORIG + + "30000000 0001 0006 00000000 00000000 02 00 0000 1C00 0180 1400 0180 0800 0100" + // -->| + + "C0A8500C 0800 0200 8C700874 0400 0280"; + // CHECKSTYLE:ON IndentationCheck + public static final byte[] CT_MALFORMED_BYTES = + HexEncoding.decode(CT_MALFORMED_HEX.replaceAll(" ", "").toCharArray(), false); + + @Test + public void testParseMalformation() { + assumeTrue(USING_LE); + + final ByteBuffer byteBuffer = ByteBuffer.wrap(CT_MALFORMED_BYTES); + byteBuffer.order(ByteOrder.nativeOrder()); + + // Expect no crash while parsing the malformed message. + int messageCount = 0; + while (byteBuffer.remaining() > 0) { + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, + OsConstants.NETLINK_NETFILTER); + messageCount++; + } + assertEquals(4, messageCount); + } + + @Test + public void testToString() { + assumeTrue(USING_LE); + + final ByteBuffer byteBuffer = ByteBuffer.wrap(CT_V4NEW_TCP_BYTES); + byteBuffer.order(ByteOrder.nativeOrder()); + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, OsConstants.NETLINK_NETFILTER); + assertNotNull(msg); + assertTrue(msg instanceof ConntrackMessage); + final ConntrackMessage conntrackMessage = (ConntrackMessage) msg; + + // Bug: "nlmsg_flags{1536(NLM_F_MATCH))" is not correct because StructNlMsgHdr + // #stringForNlMsgFlags can't convert all flags (ex: NLM_F_CREATE) and can't distinguish + // the flags which have the same value (ex: NLM_F_MATCH <0x200> and NLM_F_EXCL <0x200>). + // The flags output string should be "NLM_F_CREATE|NLM_F_EXCL" in this case. + // TODO: correct the flag converted string once #stringForNlMsgFlags does. + final String expected = "" + + "ConntrackMessage{" + + "nlmsghdr{StructNlMsgHdr{ nlmsg_len{140}, nlmsg_type{256(IPCTNL_MSG_CT_NEW)}, " + + "nlmsg_flags{1536(NLM_F_MATCH))}, nlmsg_seq{0}, nlmsg_pid{0} }}, " + + "nfgenmsg{NfGenMsg{ nfgen_family{AF_INET}, version{0}, res_id{4660} }}, " + + "tuple_orig{Tuple{IPPROTO_TCP: 192.168.80.12:62449 -> 140.112.8.116:443}}, " + + "tuple_reply{Tuple{IPPROTO_TCP: 140.112.8.116:443 -> 100.81.179.1:62449}}, " + + "status{408(IPS_CONFIRMED|IPS_SRC_NAT|IPS_SRC_NAT_DONE|IPS_DST_NAT_DONE)}, " + + "timeout_sec{120}}"; + assertEquals(expected, conntrackMessage.toString()); + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java new file mode 100644 index 0000000000..6b1482d839 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2018 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 com.android.net.module.util.netlink; + +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.IPPROTO_TCP; +import static android.system.OsConstants.IPPROTO_UDP; +import static android.system.OsConstants.NETLINK_INET_DIAG; + +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import libcore.util.HexEncoding; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class InetDiagSocketTest { + // Hexadecimal representation of InetDiagReqV2 request. + private static final String INET_DIAG_REQ_V2_UDP_INET4_HEX = + // struct nlmsghdr + "48000000" + // length = 72 + "1400" + // type = SOCK_DIAG_BY_FAMILY + "0103" + // flags = NLM_F_REQUEST | NLM_F_DUMP + "00000000" + // seqno + "00000000" + // pid (0 == kernel) + // struct inet_diag_req_v2 + "02" + // family = AF_INET + "11" + // protcol = IPPROTO_UDP + "00" + // idiag_ext + "00" + // pad + "ffffffff" + // idiag_states + // inet_diag_sockid + "a5de" + // idiag_sport = 42462 + "b971" + // idiag_dport = 47473 + "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2 + "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 + "00000000" + // idiag_if + "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE + private static final byte[] INET_DIAG_REQ_V2_UDP_INET4_BYTES = + HexEncoding.decode(INET_DIAG_REQ_V2_UDP_INET4_HEX.toCharArray(), false); + + @Test + public void testInetDiagReqV2UdpInet4() throws Exception { + InetSocketAddress local = new InetSocketAddress(InetAddress.getByName("10.0.100.2"), + 42462); + InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"), + 47473); + final byte[] msg = InetDiagMessage.inetDiagReqV2(IPPROTO_UDP, local, remote, AF_INET, + (short) (NLM_F_REQUEST | NLM_F_DUMP)); + assertArrayEquals(INET_DIAG_REQ_V2_UDP_INET4_BYTES, msg); + } + + // Hexadecimal representation of InetDiagReqV2 request. + private static final String INET_DIAG_REQ_V2_TCP_INET6_HEX = + // struct nlmsghdr + "48000000" + // length = 72 + "1400" + // type = SOCK_DIAG_BY_FAMILY + "0100" + // flags = NLM_F_REQUEST + "00000000" + // seqno + "00000000" + // pid (0 == kernel) + // struct inet_diag_req_v2 + "0a" + // family = AF_INET6 + "06" + // protcol = IPPROTO_TCP + "00" + // idiag_ext + "00" + // pad + "ffffffff" + // idiag_states + // inet_diag_sockid + "a5de" + // idiag_sport = 42462 + "b971" + // idiag_dport = 47473 + "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b + "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 + "00000000" + // idiag_if + "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE + private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_BYTES = + HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_HEX.toCharArray(), false); + + @Test + public void testInetDiagReqV2TcpInet6() throws Exception { + InetSocketAddress local = new InetSocketAddress( + InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462); + InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"), + 47473); + byte[] msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6, + NLM_F_REQUEST); + + assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg); + } + + // Hexadecimal representation of InetDiagReqV2 request with extension, INET_DIAG_INFO. + private static final String INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX = + // struct nlmsghdr + "48000000" + // length = 72 + "1400" + // type = SOCK_DIAG_BY_FAMILY + "0100" + // flags = NLM_F_REQUEST + "00000000" + // seqno + "00000000" + // pid (0 == kernel) + // struct inet_diag_req_v2 + "02" + // family = AF_INET + "06" + // protcol = IPPROTO_TCP + "02" + // idiag_ext = INET_DIAG_INFO + "00" + // pad + "ffffffff" + // idiag_states + // inet_diag_sockid + "3039" + // idiag_sport = 12345 + "d431" + // idiag_dport = 54321 + "01020304000000000000000000000000" + // idiag_src = 1.2.3.4 + "08080404000000000000000000000000" + // idiag_dst = 8.8.4.4 + "00000000" + // idiag_if + "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE + + private static final byte[] INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES = + HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX.toCharArray(), false); + private static final int TCP_ALL_STATES = 0xffffffff; + @Test + public void testInetDiagReqV2TcpInetWithExt() throws Exception { + InetSocketAddress local = new InetSocketAddress( + InetAddress.getByName("1.2.3.4"), 12345); + InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"), + 54321); + byte[] msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET, + NLM_F_REQUEST, 0 /* pad */, 2 /* idiagExt */, TCP_ALL_STATES); + + assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES, msg); + + local = new InetSocketAddress( + InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462); + remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"), + 47473); + msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6, + NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES); + + assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg); + } + + // Hexadecimal representation of InetDiagReqV2 request with no socket specified. + private static final String INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX = + // struct nlmsghdr + "48000000" + // length = 72 + "1400" + // type = SOCK_DIAG_BY_FAMILY + "0100" + // flags = NLM_F_REQUEST + "00000000" + // seqno + "00000000" + // pid (0 == kernel) + // struct inet_diag_req_v2 + "0a" + // family = AF_INET6 + "06" + // protcol = IPPROTO_TCP + "00" + // idiag_ext + "00" + // pad + "ffffffff" + // idiag_states + // inet_diag_sockid + "0000" + // idiag_sport + "0000" + // idiag_dport + "00000000000000000000000000000000" + // idiag_src + "00000000000000000000000000000000" + // idiag_dst + "00000000" + // idiag_if + "0000000000000000"; // idiag_cookie + + private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_BYTES = + HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX.toCharArray(), false); + + @Test + public void testInetDiagReqV2TcpInet6NoIdSpecified() throws Exception { + InetSocketAddress local = new InetSocketAddress( + InetAddress.getByName("fe80::fe6a:ed4b"), 12345); + InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"), + 54321); + // Verify no socket specified if either local or remote socket address is null. + byte[] msgExt = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6, + NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES); + byte[] msg; + try { + msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, null, remote, AF_INET6, + NLM_F_REQUEST); + fail("Both remote and local should be null, expected UnknownHostException"); + } catch (NullPointerException e) { + } + + try { + msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, local, null, AF_INET6, + NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES); + fail("Both remote and local should be null, expected UnknownHostException"); + } catch (NullPointerException e) { + } + + msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6, + NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES); + assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_BYTES, msg); + assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_BYTES, msgExt); + } + + // Hexadecimal representation of InetDiagReqV2 request. + private static final String INET_DIAG_MSG_HEX = + // struct nlmsghdr + "58000000" + // length = 88 + "1400" + // type = SOCK_DIAG_BY_FAMILY + "0200" + // flags = NLM_F_MULTI + "00000000" + // seqno + "f5220000" + // pid (0 == kernel) + // struct inet_diag_msg + "0a" + // family = AF_INET6 + "01" + // idiag_state + "00" + // idiag_timer + "00" + // idiag_retrans + // inet_diag_sockid + "a817" + // idiag_sport = 43031 + "960f" + // idiag_dport = 38415 + "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b + "00000000000000000000ffff08080808" + // idiag_dst = 8.8.8.8 + "00000000" + // idiag_if + "ffffffffffffffff" + // idiag_cookie = INET_DIAG_NOCOOKIE + "00000000" + // idiag_expires + "00000000" + // idiag_rqueue + "00000000" + // idiag_wqueue + "a3270000" + // idiag_uid + "A57E1900"; // idiag_inode + private static final byte[] INET_DIAG_MSG_BYTES = + HexEncoding.decode(INET_DIAG_MSG_HEX.toCharArray(), false); + + @Test + public void testParseInetDiagResponse() throws Exception { + final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_INET_DIAG); + assertNotNull(msg); + + assertTrue(msg instanceof InetDiagMessage); + final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg; + assertEquals(10147, inetDiagMsg.mStructInetDiagMsg.idiag_uid); + + final StructNlMsgHdr hdr = inetDiagMsg.getHeader(); + assertNotNull(hdr); + assertEquals(NetlinkConstants.SOCK_DIAG_BY_FAMILY, hdr.nlmsg_type); + assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags); + assertEquals(0, hdr.nlmsg_seq); + assertEquals(8949, hdr.nlmsg_pid); + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NduseroptMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NduseroptMessageTest.java new file mode 100644 index 0000000000..538c09bc50 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NduseroptMessageTest.java @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util.netlink; + +import static android.net.InetAddresses.parseNumericAddress; +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.NETLINK_ROUTE; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.net.IpPrefix; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import libcore.util.HexEncoding; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class NduseroptMessageTest { + + private static final byte ICMP_TYPE_RA = (byte) 134; + + private static final int IFINDEX1 = 15715755; + private static final int IFINDEX2 = 1431655765; + + // IPv6, 0 bytes of options, interface index 15715755, type 134 (RA), code 0, padding. + private static final String HDR_EMPTY = "0a00" + "0000" + "abcdef00" + "8600000000000000"; + + // IPv6, 16 bytes of options, interface index 1431655765, type 134 (RA), code 0, padding. + private static final String HDR_16BYTE = "0a00" + "1000" + "55555555" + "8600000000000000"; + + // IPv6, 32 bytes of options, interface index 1431655765, type 134 (RA), code 0, padding. + private static final String HDR_32BYTE = "0a00" + "2000" + "55555555" + "8600000000000000"; + + // PREF64 option, 2001:db8:3:4:5:6::/96, lifetime=10064 + private static final String OPT_PREF64 = "2602" + "2750" + "20010db80003000400050006"; + + // Length 20, NDUSEROPT_SRCADDR, fe80:2:3:4:5:6:7:8 + private static final String NLA_SRCADDR = "1400" + "0100" + "fe800002000300040005000600070008"; + + private static final InetAddress SADDR1 = parseNumericAddress("fe80:2:3:4:5:6:7:8%" + IFINDEX1); + private static final InetAddress SADDR2 = parseNumericAddress("fe80:2:3:4:5:6:7:8%" + IFINDEX2); + + private static final String MSG_EMPTY = HDR_EMPTY + NLA_SRCADDR; + private static final String MSG_PREF64 = HDR_16BYTE + OPT_PREF64 + NLA_SRCADDR; + + @Test + public void testParsing() { + NduseroptMessage msg = parseNduseroptMessage(toBuffer(MSG_EMPTY)); + assertMatches(AF_INET6, 0, IFINDEX1, ICMP_TYPE_RA, (byte) 0, SADDR1, msg); + assertNull(msg.option); + + msg = parseNduseroptMessage(toBuffer(MSG_PREF64)); + assertMatches(AF_INET6, 16, IFINDEX2, ICMP_TYPE_RA, (byte) 0, SADDR2, msg); + assertPref64Option("2001:db8:3:4:5:6::/96", msg.option); + } + + @Test + public void testParseWithinNetlinkMessage() throws Exception { + // A NduseroptMessage inside a netlink message. Ensure that it parses the same way both by + // parsing the netlink message via NetlinkMessage.parse() and by parsing the option itself + // with NduseroptMessage.parse(). + final String hexBytes = + "44000000440000000000000000000000" // len=68, RTM_NEWNDUSEROPT + + "0A0010001E0000008600000000000000" // IPv6, opt_bytes=16, ifindex=30, RA + + "260202580064FF9B0000000000000000" // pref64, prefix=64:ff9b::/96, 600 + + "14000100FE800000000000000250B6FFFEB7C499"; // srcaddr=fe80::250:b6ff:feb7:c499 + + ByteBuffer buf = toBuffer(hexBytes); + assertEquals(68, buf.limit()); + buf.order(ByteOrder.nativeOrder()); + + NetlinkMessage nlMsg = NetlinkMessage.parse(buf, NETLINK_ROUTE); + assertNotNull(nlMsg); + assertTrue(nlMsg instanceof NduseroptMessage); + + NduseroptMessage msg = (NduseroptMessage) nlMsg; + InetAddress srcaddr = InetAddress.getByName("fe80::250:b6ff:feb7:c499%30"); + assertMatches(AF_INET6, 16, 30, ICMP_TYPE_RA, (byte) 0, srcaddr, msg); + assertPref64Option("64:ff9b::/96", msg.option); + + final String hexBytesWithoutHeader = hexBytes.substring(StructNlMsgHdr.STRUCT_SIZE * 2); + ByteBuffer bufWithoutHeader = toBuffer(hexBytesWithoutHeader); + assertEquals(52, bufWithoutHeader.limit()); + msg = parseNduseroptMessage(bufWithoutHeader); + assertMatches(AF_INET6, 16, 30, ICMP_TYPE_RA, (byte) 0, srcaddr, msg); + assertPref64Option("64:ff9b::/96", msg.option); + } + + @Test + public void testParseUnknownOptionWithinNetlinkMessage() throws Exception { + final String hexBytes = + "4C0000004400000000000000000000000" + + "A0018001E0000008600000000000000" + + "1903000000001770FD123456789000000000000000000001" // RDNSS option + + "14000100FE800000000000000250B6FFFEB7C499"; + + ByteBuffer buf = toBuffer(hexBytes); + assertEquals(76, buf.limit()); + buf.order(ByteOrder.nativeOrder()); + + NetlinkMessage nlMsg = NetlinkMessage.parse(buf, NETLINK_ROUTE); + assertNotNull(nlMsg); + assertTrue(nlMsg instanceof NduseroptMessage); + + NduseroptMessage msg = (NduseroptMessage) nlMsg; + InetAddress srcaddr = InetAddress.getByName("fe80::250:b6ff:feb7:c499%30"); + assertMatches(AF_INET6, 24, 30, ICMP_TYPE_RA, (byte) 0, srcaddr, msg); + assertEquals(NdOption.UNKNOWN, msg.option); + } + + @Test + public void testUnknownOption() { + ByteBuffer buf = toBuffer(MSG_PREF64); + // Replace the PREF64 option type (38) with an unknown option number. + final int optionStart = NduseroptMessage.STRUCT_SIZE; + assertEquals(38, buf.get(optionStart)); + buf.put(optionStart, (byte) 42); + + NduseroptMessage msg = parseNduseroptMessage(buf); + assertMatches(AF_INET6, 16, IFINDEX2, ICMP_TYPE_RA, (byte) 0, SADDR2, msg); + assertEquals(NdOption.UNKNOWN, msg.option); + + buf.flip(); + assertEquals(42, buf.get(optionStart)); + buf.put(optionStart, (byte) 38); + + msg = parseNduseroptMessage(buf); + assertMatches(AF_INET6, 16, IFINDEX2, ICMP_TYPE_RA, (byte) 0, SADDR2, msg); + assertPref64Option("2001:db8:3:4:5:6::/96", msg.option); + } + + @Test + public void testZeroLengthOption() { + // Make sure an unknown option with a 0-byte length is ignored and parsing continues with + // the address, which comes after it. + final String hexString = HDR_16BYTE + "00000000000000000000000000000000" + NLA_SRCADDR; + ByteBuffer buf = toBuffer(hexString); + assertEquals(52, buf.limit()); + NduseroptMessage msg = parseNduseroptMessage(buf); + assertMatches(AF_INET6, 16, IFINDEX2, ICMP_TYPE_RA, (byte) 0, SADDR2, msg); + assertNull(msg.option); + } + + @Test + public void testTooLongOption() { + // Make sure that if an option's length is too long, it's ignored and parsing continues with + // the address, which comes after it. + final String hexString = HDR_16BYTE + "26030000000000000000000000000000" + NLA_SRCADDR; + ByteBuffer buf = toBuffer(hexString); + assertEquals(52, buf.limit()); + NduseroptMessage msg = parseNduseroptMessage(buf); + assertMatches(AF_INET6, 16, IFINDEX2, ICMP_TYPE_RA, (byte) 0, SADDR2, msg); + assertNull(msg.option); + } + + @Test + public void testOptionsTooLong() { + // Header claims 32 bytes of options. Buffer ends before options end. + String hexString = HDR_32BYTE + OPT_PREF64; + ByteBuffer buf = toBuffer(hexString); + assertEquals(32, buf.limit()); + assertNull(NduseroptMessage.parse(toBuffer(hexString), NETLINK_ROUTE)); + + // Header claims 32 bytes of options. Buffer ends at end of options with no source address. + hexString = HDR_32BYTE + OPT_PREF64 + OPT_PREF64; + buf = toBuffer(hexString); + assertEquals(48, buf.limit()); + assertNull(NduseroptMessage.parse(toBuffer(hexString), NETLINK_ROUTE)); + } + + @Test + public void testTruncation() { + final int optLen = MSG_PREF64.length() / 2; // 1 byte = 2 hex chars + for (int len = 0; len < optLen; len++) { + ByteBuffer buf = toBuffer(MSG_PREF64.substring(0, len * 2)); + NduseroptMessage msg = parseNduseroptMessage(buf); + if (len < optLen) { + assertNull(msg); + } else { + assertNotNull(msg); + assertPref64Option("2001:db8:3:4:5:6::/96", msg.option); + } + } + } + + @Test + public void testToString() { + NduseroptMessage msg = parseNduseroptMessage(toBuffer(MSG_PREF64)); + assertNotNull(msg); + assertEquals("Nduseroptmsg(10, 16, 1431655765, 134, 0, fe80:2:3:4:5:6:7:8%1431655765)", + msg.toString()); + } + + // Convenience method to parse a NduseroptMessage that's not part of a netlink message. + private NduseroptMessage parseNduseroptMessage(ByteBuffer buf) { + return NduseroptMessage.parse(null, buf); + } + + private ByteBuffer toBuffer(String hexString) { + return ByteBuffer.wrap(HexEncoding.decode(hexString)); + } + + private void assertMatches(int family, int optsLen, int ifindex, byte icmpType, + byte icmpCode, InetAddress srcaddr, NduseroptMessage msg) { + assertNotNull(msg); + assertEquals(family, msg.family); + assertEquals(ifindex, msg.ifindex); + assertEquals(optsLen, msg.opts_len); + assertEquals(icmpType, msg.icmp_type); + assertEquals(icmpCode, msg.icmp_code); + assertEquals(srcaddr, msg.srcaddr); + } + + private void assertPref64Option(String prefix, NdOption opt) { + assertNotNull(opt); + assertTrue(opt instanceof StructNdOptPref64); + StructNdOptPref64 pref64Opt = (StructNdOptPref64) opt; + assertEquals(new IpPrefix(prefix), pref64Opt.prefix); + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkConstantsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkConstantsTest.java new file mode 100644 index 0000000000..143e4d4ac5 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkConstantsTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util.netlink; + +import static android.system.OsConstants.NETLINK_INET_DIAG; +import static android.system.OsConstants.NETLINK_NETFILTER; +import static android.system.OsConstants.NETLINK_ROUTE; + +import static com.android.net.module.util.netlink.NetlinkConstants.IPCTNL_MSG_CT_DELETE; +import static com.android.net.module.util.netlink.NetlinkConstants.IPCTNL_MSG_CT_GET; +import static com.android.net.module.util.netlink.NetlinkConstants.IPCTNL_MSG_CT_GET_CTRZERO; +import static com.android.net.module.util.netlink.NetlinkConstants.IPCTNL_MSG_CT_GET_DYING; +import static com.android.net.module.util.netlink.NetlinkConstants.IPCTNL_MSG_CT_GET_STATS; +import static com.android.net.module.util.netlink.NetlinkConstants.IPCTNL_MSG_CT_GET_STATS_CPU; +import static com.android.net.module.util.netlink.NetlinkConstants.IPCTNL_MSG_CT_GET_UNCONFIRMED; +import static com.android.net.module.util.netlink.NetlinkConstants.IPCTNL_MSG_CT_NEW; +import static com.android.net.module.util.netlink.NetlinkConstants.NFNL_SUBSYS_CTNETLINK; +import static com.android.net.module.util.netlink.NetlinkConstants.NLMSG_DONE; +import static com.android.net.module.util.netlink.NetlinkConstants.NLMSG_ERROR; +import static com.android.net.module.util.netlink.NetlinkConstants.NLMSG_NOOP; +import static com.android.net.module.util.netlink.NetlinkConstants.NLMSG_OVERRUN; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_DELADDR; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_DELLINK; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_DELNEIGH; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_DELROUTE; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_DELRULE; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_GETADDR; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_GETLINK; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_GETNEIGH; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_GETROUTE; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_GETRULE; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWADDR; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWLINK; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWNDUSEROPT; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWNEIGH; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWROUTE; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWRULE; +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_SETLINK; +import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY; +import static com.android.net.module.util.netlink.NetlinkConstants.stringForNlMsgType; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class NetlinkConstantsTest { + private static final short UNKNOWN_FAMILY = 1234; + + private short makeCtType(short msgType) { + return (short) (NFNL_SUBSYS_CTNETLINK << 8 | (byte) msgType); + } + + @Test + public void testStringForNlMsgType() { + assertEquals("RTM_NEWLINK", stringForNlMsgType(RTM_NEWLINK, NETLINK_ROUTE)); + assertEquals("RTM_DELLINK", stringForNlMsgType(RTM_DELLINK, NETLINK_ROUTE)); + assertEquals("RTM_GETLINK", stringForNlMsgType(RTM_GETLINK, NETLINK_ROUTE)); + assertEquals("RTM_SETLINK", stringForNlMsgType(RTM_SETLINK, NETLINK_ROUTE)); + assertEquals("RTM_NEWADDR", stringForNlMsgType(RTM_NEWADDR, NETLINK_ROUTE)); + assertEquals("RTM_DELADDR", stringForNlMsgType(RTM_DELADDR, NETLINK_ROUTE)); + assertEquals("RTM_GETADDR", stringForNlMsgType(RTM_GETADDR, NETLINK_ROUTE)); + assertEquals("RTM_NEWROUTE", stringForNlMsgType(RTM_NEWROUTE, NETLINK_ROUTE)); + assertEquals("RTM_DELROUTE", stringForNlMsgType(RTM_DELROUTE, NETLINK_ROUTE)); + assertEquals("RTM_GETROUTE", stringForNlMsgType(RTM_GETROUTE, NETLINK_ROUTE)); + assertEquals("RTM_NEWNEIGH", stringForNlMsgType(RTM_NEWNEIGH, NETLINK_ROUTE)); + assertEquals("RTM_DELNEIGH", stringForNlMsgType(RTM_DELNEIGH, NETLINK_ROUTE)); + assertEquals("RTM_GETNEIGH", stringForNlMsgType(RTM_GETNEIGH, NETLINK_ROUTE)); + assertEquals("RTM_NEWRULE", stringForNlMsgType(RTM_NEWRULE, NETLINK_ROUTE)); + assertEquals("RTM_DELRULE", stringForNlMsgType(RTM_DELRULE, NETLINK_ROUTE)); + assertEquals("RTM_GETRULE", stringForNlMsgType(RTM_GETRULE, NETLINK_ROUTE)); + assertEquals("RTM_NEWNDUSEROPT", stringForNlMsgType(RTM_NEWNDUSEROPT, NETLINK_ROUTE)); + + assertEquals("SOCK_DIAG_BY_FAMILY", + stringForNlMsgType(SOCK_DIAG_BY_FAMILY, NETLINK_INET_DIAG)); + + assertEquals("IPCTNL_MSG_CT_NEW", + stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_NEW), NETLINK_NETFILTER)); + assertEquals("IPCTNL_MSG_CT_GET", + stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_GET), NETLINK_NETFILTER)); + assertEquals("IPCTNL_MSG_CT_DELETE", + stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_DELETE), NETLINK_NETFILTER)); + assertEquals("IPCTNL_MSG_CT_GET_CTRZERO", + stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_GET_CTRZERO), NETLINK_NETFILTER)); + assertEquals("IPCTNL_MSG_CT_GET_STATS_CPU", + stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_GET_STATS_CPU), NETLINK_NETFILTER)); + assertEquals("IPCTNL_MSG_CT_GET_STATS", + stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_GET_STATS), NETLINK_NETFILTER)); + assertEquals("IPCTNL_MSG_CT_GET_DYING", + stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_GET_DYING), NETLINK_NETFILTER)); + assertEquals("IPCTNL_MSG_CT_GET_UNCONFIRMED", + stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_GET_UNCONFIRMED), NETLINK_NETFILTER)); + } + + @Test + public void testStringForNlMsgType_ControlMessage() { + for (int family : new int[]{NETLINK_ROUTE, NETLINK_INET_DIAG, NETLINK_NETFILTER}) { + assertEquals("NLMSG_NOOP", stringForNlMsgType(NLMSG_NOOP, family)); + assertEquals("NLMSG_ERROR", stringForNlMsgType(NLMSG_ERROR, family)); + assertEquals("NLMSG_DONE", stringForNlMsgType(NLMSG_DONE, family)); + assertEquals("NLMSG_OVERRUN", stringForNlMsgType(NLMSG_OVERRUN, family)); + } + } + + @Test + public void testStringForNlMsgType_UnknownFamily() { + assertTrue(stringForNlMsgType(RTM_NEWLINK, UNKNOWN_FAMILY).startsWith("unknown")); + assertTrue(stringForNlMsgType(SOCK_DIAG_BY_FAMILY, UNKNOWN_FAMILY).startsWith("unknown")); + assertTrue(stringForNlMsgType(makeCtType(IPCTNL_MSG_CT_NEW), UNKNOWN_FAMILY) + .startsWith("unknown")); + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkErrorMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkErrorMessageTest.java new file mode 100644 index 0000000000..ab7d9cf56c --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkErrorMessageTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2015 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 com.android.net.module.util.netlink; + +import static android.system.OsConstants.NETLINK_ROUTE; + +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REPLACE; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import libcore.util.HexEncoding; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class NetlinkErrorMessageTest { + private static final String TAG = "NetlinkErrorMessageTest"; + + // Hexadecimal representation of packet capture. + public static final String NLM_ERROR_OK_HEX = + // struct nlmsghdr + "24000000" + // length = 36 + "0200" + // type = 2 (NLMSG_ERROR) + "0000" + // flags + "26350000" + // seqno + "64100000" + // pid = userspace process + // error integer + "00000000" + // "errno" (0 == OK) + // struct nlmsghdr + "30000000" + // length (48) of original request + "1C00" + // type = 28 (RTM_NEWNEIGH) + "0501" + // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE) + "26350000" + // seqno + "00000000"; // pid = kernel + public static final byte[] NLM_ERROR_OK = + HexEncoding.decode(NLM_ERROR_OK_HEX.toCharArray(), false); + + @Test + public void testParseNlmErrorOk() { + final ByteBuffer byteBuffer = ByteBuffer.wrap(NLM_ERROR_OK); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof NetlinkErrorMessage); + final NetlinkErrorMessage errorMsg = (NetlinkErrorMessage) msg; + + final StructNlMsgHdr hdr = errorMsg.getHeader(); + assertNotNull(hdr); + assertEquals(36, hdr.nlmsg_len); + assertEquals(NetlinkConstants.NLMSG_ERROR, hdr.nlmsg_type); + assertEquals(0, hdr.nlmsg_flags); + assertEquals(13606, hdr.nlmsg_seq); + assertEquals(4196, hdr.nlmsg_pid); + + final StructNlMsgErr err = errorMsg.getNlMsgError(); + assertNotNull(err); + assertEquals(0, err.error); + assertNotNull(err.msg); + assertEquals(48, err.msg.nlmsg_len); + assertEquals(NetlinkConstants.RTM_NEWNEIGH, err.msg.nlmsg_type); + assertEquals((NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE), err.msg.nlmsg_flags); + assertEquals(13606, err.msg.nlmsg_seq); + assertEquals(0, err.msg.nlmsg_pid); + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkSocketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkSocketTest.java new file mode 100644 index 0000000000..33ea602312 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkSocketTest.java @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2015 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 com.android.net.module.util.netlink; + +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.AF_UNSPEC; +import static android.system.OsConstants.EACCES; +import static android.system.OsConstants.NETLINK_ROUTE; + +import static com.android.net.module.util.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.content.Context; +import android.system.ErrnoException; +import android.system.NetlinkSocketAddress; +import android.system.Os; + +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.modules.utils.build.SdkLevel; +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import libcore.io.IoUtils; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.FileDescriptor; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class NetlinkSocketTest { + private static final String TAG = "NetlinkSocketTest"; + private static final int TEST_SEQNO = 5; + private static final int TEST_TIMEOUT_MS = 500; + + @Test + public void testGetNeighborsQuery() throws Exception { + final FileDescriptor fd = NetlinkSocket.forProto(NETLINK_ROUTE); + assertNotNull(fd); + + NetlinkSocket.connectToKernel(fd); + + final NetlinkSocketAddress localAddr = (NetlinkSocketAddress) Os.getsockname(fd); + assertNotNull(localAddr); + assertEquals(0, localAddr.getGroupsMask()); + assertTrue(0 != localAddr.getPortId()); + + final byte[] req = RtNetlinkNeighborMessage.newGetNeighborsRequest(TEST_SEQNO); + assertNotNull(req); + + final Context ctx = InstrumentationRegistry.getInstrumentation().getContext(); + final int targetSdk = + ctx.getPackageManager() + .getApplicationInfo(ctx.getPackageName(), 0) + .targetSdkVersion; + + // Apps targeting an SDK version > S are not allowed to send RTM_GETNEIGH{TBL} messages + if (SdkLevel.isAtLeastT() && targetSdk > 31) { + try { + NetlinkSocket.sendMessage(fd, req, 0, req.length, TEST_TIMEOUT_MS); + fail("RTM_GETNEIGH is not allowed for apps targeting SDK > 31 on T+ platforms," + + " target SDK version: " + targetSdk); + } catch (ErrnoException e) { + // Expected + assertEquals(e.errno, EACCES); + return; + } + } + + // Check that apps targeting lower API levels / running on older platforms succeed + assertEquals(req.length, + NetlinkSocket.sendMessage(fd, req, 0, req.length, TEST_TIMEOUT_MS)); + + int neighMessageCount = 0; + int doneMessageCount = 0; + + while (doneMessageCount == 0) { + ByteBuffer response = + NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TEST_TIMEOUT_MS); + assertNotNull(response); + assertTrue(StructNlMsgHdr.STRUCT_SIZE <= response.limit()); + assertEquals(0, response.position()); + assertEquals(ByteOrder.nativeOrder(), response.order()); + + // Verify the messages at least appears minimally reasonable. + while (response.remaining() > 0) { + final NetlinkMessage msg = NetlinkMessage.parse(response, NETLINK_ROUTE); + assertNotNull(msg); + final StructNlMsgHdr hdr = msg.getHeader(); + assertNotNull(hdr); + + if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) { + doneMessageCount++; + continue; + } + + assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type); + assertTrue(msg instanceof RtNetlinkNeighborMessage); + assertTrue((hdr.nlmsg_flags & StructNlMsgHdr.NLM_F_MULTI) != 0); + assertEquals(TEST_SEQNO, hdr.nlmsg_seq); + assertEquals(localAddr.getPortId(), hdr.nlmsg_pid); + + neighMessageCount++; + } + } + + assertEquals(1, doneMessageCount); + // TODO: make sure this test passes sanely in airplane mode. + assertTrue(neighMessageCount > 0); + + IoUtils.closeQuietly(fd); + } + + @Test + public void testBasicWorkingGetAddrQuery() throws Exception { + final FileDescriptor fd = NetlinkSocket.forProto(NETLINK_ROUTE); + assertNotNull(fd); + + NetlinkSocket.connectToKernel(fd); + + final NetlinkSocketAddress localAddr = (NetlinkSocketAddress) Os.getsockname(fd); + assertNotNull(localAddr); + assertEquals(0, localAddr.getGroupsMask()); + assertTrue(0 != localAddr.getPortId()); + + final int testSeqno = 8; + final byte[] req = newGetAddrRequest(testSeqno); + assertNotNull(req); + + final long timeout = 500; + assertEquals(req.length, NetlinkSocket.sendMessage(fd, req, 0, req.length, timeout)); + + int addrMessageCount = 0; + + while (true) { + ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, timeout); + assertNotNull(response); + assertTrue(StructNlMsgHdr.STRUCT_SIZE <= response.limit()); + assertEquals(0, response.position()); + assertEquals(ByteOrder.nativeOrder(), response.order()); + + final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(response); + assertNotNull(nlmsghdr); + + if (nlmsghdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) { + break; + } + + assertEquals(NetlinkConstants.RTM_NEWADDR, nlmsghdr.nlmsg_type); + assertTrue((nlmsghdr.nlmsg_flags & StructNlMsgHdr.NLM_F_MULTI) != 0); + assertEquals(testSeqno, nlmsghdr.nlmsg_seq); + assertEquals(localAddr.getPortId(), nlmsghdr.nlmsg_pid); + addrMessageCount++; + + final IfaddrMsg ifaMsg = Struct.parse(IfaddrMsg.class, response); + assertTrue( + "Non-IP address family: " + ifaMsg.family, + ifaMsg.family == AF_INET || ifaMsg.family == AF_INET6); + } + + assertTrue(addrMessageCount > 0); + + IoUtils.closeQuietly(fd); + } + + /** A convenience method to create an RTM_GETADDR request message. */ + private static byte[] newGetAddrRequest(int seqNo) { + final int length = StructNlMsgHdr.STRUCT_SIZE + Struct.getSize(RtgenMsg.class); + final byte[] bytes = new byte[length]; + final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); + byteBuffer.order(ByteOrder.nativeOrder()); + + final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); + nlmsghdr.nlmsg_len = length; + nlmsghdr.nlmsg_type = NetlinkConstants.RTM_GETADDR; + nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + nlmsghdr.nlmsg_seq = seqNo; + nlmsghdr.pack(byteBuffer); + + final RtgenMsg rtgenMsg = new RtgenMsg(); + rtgenMsg.family = (byte) AF_UNSPEC; + rtgenMsg.writeToByteBuffer(byteBuffer); + + return bytes; + } + + /** From uapi/linux/rtnetlink.h */ + private static class RtgenMsg extends Struct { + @Field(order = 0, type = Type.U8) + public short family; + } + + /** + * From uapi/linux/ifaddr.h + * + * Public ensures visibility to Struct class + */ + public static class IfaddrMsg extends Struct { + @Field(order = 0, type = Type.U8) + public short family; + + @Field(order = 1, type = Type.U8) + public short prefixlen; + + @Field(order = 2, type = Type.U8) + public short flags; + + @Field(order = 3, type = Type.U8) + public short scope; + + @Field(order = 4, type = Type.U32) + public long index; + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkNeighborMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkNeighborMessageTest.java new file mode 100644 index 0000000000..4d8900cdbd --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkNeighborMessageTest.java @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util.netlink; + +import static android.system.OsConstants.NETLINK_ROUTE; + +import static com.android.net.module.util.netlink.StructNdMsg.NUD_STALE; +import static com.android.testutils.NetlinkTestUtils.makeDelNeighMessage; +import static com.android.testutils.NetlinkTestUtils.makeNewNeighMessage; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import android.net.InetAddresses; +import android.system.OsConstants; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import libcore.util.HexEncoding; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class RtNetlinkNeighborMessageTest { + private static final String TAG = "RtNetlinkNeighborMessageTest"; + + public static final byte[] RTM_DELNEIGH = makeDelNeighMessage( + InetAddresses.parseNumericAddress("192.168.159.254"), NUD_STALE); + + public static final byte[] RTM_NEWNEIGH = makeNewNeighMessage( + InetAddresses.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), NUD_STALE); + + // An example of the full response from an RTM_GETNEIGH query. + private static final String RTM_GETNEIGH_RESPONSE_HEX = + // <-- struct nlmsghr -->|<-- struct ndmsg -->|<-- struct nlattr: NDA_DST -->|<-- NDA_LLADDR -->|<-- NDA_PROBES -->|<-- NDA_CACHEINFO -->| + "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000001 0a00 0200 333300000001 0000 0800 0400 00000000 1400 0300 a2280000 32110000 32110000 01000000" + + "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff000001 0a00 0200 3333ff000001 0000 0800 0400 00000000 1400 0300 0d280000 9d100000 9d100000 00000000" + + "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 0400 80 01 1400 0100 20010db800040ca00000000000000001 0a00 0200 84c9b26aed4b 0000 0800 0400 04000000 1400 0300 90100000 90100000 90080000 01000000" + + "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff47da19 0a00 0200 3333ff47da19 0000 0800 0400 00000000 1400 0300 a1280000 31110000 31110000 01000000" + + "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff020000000000000000000000000016 0a00 0200 333300000016 0000 0800 0400 00000000 1400 0300 912a0000 21130000 21130000 00000000" + + "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff0200000000000000000001ffeace3b 0a00 0200 3333ffeace3b 0000 0800 0400 00000000 1400 0300 922a0000 22130000 22130000 00000000" + + "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff5c2a83 0a00 0200 3333ff5c2a83 0000 0800 0400 00000000 1400 0300 391c0000 c9040000 c9040000 01000000" + + "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 01000000 4000 00 02 1400 0100 00000000000000000000000000000000 0a00 0200 000000000000 0000 0800 0400 00000000 1400 0300 cd180200 5d010200 5d010200 08000000" + + "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000002 0a00 0200 333300000002 0000 0800 0400 00000000 1400 0300 352a0000 c5120000 c5120000 00000000" + + "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000016 0a00 0200 333300000016 0000 0800 0400 00000000 1400 0300 982a0000 28130000 28130000 00000000" + + "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 0800 80 01 1400 0100 fe8000000000000086c9b2fffe6aed4b 0a00 0200 84c9b26aed4b 0000 0800 0400 00000000 1400 0300 23000000 24000000 57000000 13000000" + + "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ffeace3b 0a00 0200 3333ffeace3b 0000 0800 0400 00000000 1400 0300 992a0000 29130000 29130000 01000000" + + "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff020000000000000000000000000002 0a00 0200 333300000002 0000 0800 0400 00000000 1400 0300 2e2a0000 be120000 be120000 00000000" + + "44000000 1c00 0200 00000000 3e2b0000 02 00 0000 18000000 4000 00 03 0800 0100 00000000 0400 0200 0800 0400 00000000 1400 0300 75280000 05110000 05110000 22000000"; + public static final byte[] RTM_GETNEIGH_RESPONSE = + HexEncoding.decode(RTM_GETNEIGH_RESPONSE_HEX.replaceAll(" ", "").toCharArray(), false); + + @Test + public void testParseRtmDelNeigh() { + final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_DELNEIGH); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkNeighborMessage); + final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg; + + final StructNlMsgHdr hdr = neighMsg.getHeader(); + assertNotNull(hdr); + assertEquals(76, hdr.nlmsg_len); + assertEquals(NetlinkConstants.RTM_DELNEIGH, hdr.nlmsg_type); + assertEquals(0, hdr.nlmsg_flags); + assertEquals(0, hdr.nlmsg_seq); + assertEquals(0, hdr.nlmsg_pid); + + final StructNdMsg ndmsgHdr = neighMsg.getNdHeader(); + assertNotNull(ndmsgHdr); + assertEquals((byte) OsConstants.AF_INET, ndmsgHdr.ndm_family); + assertEquals(21, ndmsgHdr.ndm_ifindex); + assertEquals(NUD_STALE, ndmsgHdr.ndm_state); + final InetAddress destination = neighMsg.getDestination(); + assertNotNull(destination); + assertEquals(InetAddress.parseNumericAddress("192.168.159.254"), destination); + } + + @Test + public void testParseRtmNewNeigh() { + final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_NEWNEIGH); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkNeighborMessage); + final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg; + + final StructNlMsgHdr hdr = neighMsg.getHeader(); + assertNotNull(hdr); + assertEquals(88, hdr.nlmsg_len); + assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type); + assertEquals(0, hdr.nlmsg_flags); + assertEquals(0, hdr.nlmsg_seq); + assertEquals(0, hdr.nlmsg_pid); + + final StructNdMsg ndmsgHdr = neighMsg.getNdHeader(); + assertNotNull(ndmsgHdr); + assertEquals((byte) OsConstants.AF_INET6, ndmsgHdr.ndm_family); + assertEquals(21, ndmsgHdr.ndm_ifindex); + assertEquals(NUD_STALE, ndmsgHdr.ndm_state); + final InetAddress destination = neighMsg.getDestination(); + assertNotNull(destination); + assertEquals(InetAddress.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), destination); + } + + @Test + public void testParseRtmGetNeighResponse() { + final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_GETNEIGH_RESPONSE); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + + int messageCount = 0; + while (byteBuffer.remaining() > 0) { + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkNeighborMessage); + final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg; + + final StructNlMsgHdr hdr = neighMsg.getHeader(); + assertNotNull(hdr); + assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type); + assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags); + assertEquals(0, hdr.nlmsg_seq); + assertEquals(11070, hdr.nlmsg_pid); + + final int probes = neighMsg.getProbes(); + assertTrue("Unexpected number of probes. Got " + probes + ", max=5", + probes < 5); + final int ndm_refcnt = neighMsg.getCacheInfo().ndm_refcnt; + assertTrue("nda_cacheinfo has unexpectedly high ndm_refcnt: " + ndm_refcnt, + ndm_refcnt < 0x100); + + messageCount++; + } + // TODO: add more detailed spot checks. + assertEquals(14, messageCount); + } + + @Test + public void testCreateRtmNewNeighMessage() { + final int seqNo = 2635; + final int ifIndex = 14; + final byte[] llAddr = + new byte[] { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6 }; + + // Hexadecimal representation of our created packet. + final String expectedNewNeighHex = + // struct nlmsghdr + "30000000" + // length = 48 + "1c00" + // type = 28 (RTM_NEWNEIGH) + "0501" + // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE) + "4b0a0000" + // seqno + "00000000" + // pid (0 == kernel) + // struct ndmsg + "02" + // family + "00" + // pad1 + "0000" + // pad2 + "0e000000" + // interface index (14) + "0800" + // NUD state (0x08 == NUD_DELAY) + "00" + // flags + "00" + // type + // struct nlattr: NDA_DST + "0800" + // length = 8 + "0100" + // type (1 == NDA_DST, for neighbor messages) + "7f000001" + // IPv4 address (== 127.0.0.1) + // struct nlattr: NDA_LLADDR + "0a00" + // length = 10 + "0200" + // type (2 == NDA_LLADDR, for neighbor messages) + "010203040506" + // MAC Address (== 01:02:03:04:05:06) + "0000"; // padding, for 4 byte alignment + final byte[] expectedNewNeigh = + HexEncoding.decode(expectedNewNeighHex.toCharArray(), false); + + final byte[] bytes = RtNetlinkNeighborMessage.newNewNeighborMessage( + seqNo, Inet4Address.LOOPBACK, StructNdMsg.NUD_DELAY, ifIndex, llAddr); + if (!Arrays.equals(expectedNewNeigh, bytes)) { + assertEquals(expectedNewNeigh.length, bytes.length); + for (int i = 0; i < Math.min(expectedNewNeigh.length, bytes.length); i++) { + assertEquals(expectedNewNeigh[i], bytes[i]); + } + } + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java new file mode 100644 index 0000000000..57248eada6 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util.netlink; + +import static com.android.net.module.util.netlink.StructNdOptPref64.getScaledLifetimePlc; +import static com.android.net.module.util.netlink.StructNdOptPref64.plcToPrefixLength; +import static com.android.net.module.util.netlink.StructNdOptPref64.prefixLengthToPlc; +import static com.android.testutils.MiscAsserts.assertThrows; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import android.net.IpPrefix; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import libcore.util.HexEncoding; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.nio.ByteBuffer; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class StructNdOptPref64Test { + + private static final String PREFIX1 = "64:ff9b::"; + private static final String PREFIX2 = "2001:db8:1:2:3:64::"; + + private static byte[] prefixBytes(String addrString) throws Exception { + InetAddress addr = InetAddress.getByName(addrString); + byte[] prefixBytes = new byte[12]; + System.arraycopy(addr.getAddress(), 0, prefixBytes, 0, 12); + return prefixBytes; + } + + private static IpPrefix prefix(String addrString, int prefixLength) throws Exception { + return new IpPrefix(InetAddress.getByName(addrString), prefixLength); + } + + private void assertPref64OptMatches(int lifetime, IpPrefix prefix, StructNdOptPref64 opt) { + assertEquals(StructNdOptPref64.TYPE, opt.type); + assertEquals(2, opt.length); + assertEquals(lifetime, opt.lifetime); + assertEquals(prefix, opt.prefix); + } + + private void assertToByteBufferMatches(StructNdOptPref64 opt, String expected) { + String actual = HexEncoding.encodeToString(opt.toByteBuffer().array()); + assertEquals(expected, actual); + } + + private ByteBuffer makeNdOptPref64(int lifetime, byte[] prefix, int prefixLengthCode) { + if (prefix.length != 12) throw new IllegalArgumentException("Prefix must be 12 bytes"); + + ByteBuffer buf = ByteBuffer.allocate(16) + .put((byte) StructNdOptPref64.TYPE) + .put((byte) StructNdOptPref64.LENGTH) + .putShort(getScaledLifetimePlc(lifetime, prefixLengthCode)) + .put(prefix, 0, 12); + + buf.flip(); + return buf; + } + + @Test + public void testParseCannedOption() throws Exception { + String hexBytes = "2602" // type=38, len=2 (16 bytes) + + "0088" // lifetime=136, PLC=0 (/96) + + "20010DB80003000400050006"; // 2001:db8:3:4:5:6/96 + byte[] rawBytes = HexEncoding.decode(hexBytes); + StructNdOptPref64 opt = StructNdOptPref64.parse(ByteBuffer.wrap(rawBytes)); + assertPref64OptMatches(136, prefix("2001:DB8:3:4:5:6::", 96), opt); + assertToByteBufferMatches(opt, hexBytes); + + hexBytes = "2602" // type=38, len=2 (16 bytes) + + "2752" // lifetime=10064, PLC=2 (/56) + + "0064FF9B0000000000000000"; // 64:ff9b::/56 + rawBytes = HexEncoding.decode(hexBytes); + opt = StructNdOptPref64.parse(ByteBuffer.wrap(rawBytes)); + assertPref64OptMatches(10064, prefix("64:FF9B::", 56), opt); + assertToByteBufferMatches(opt, hexBytes); + } + + @Test + public void testParsing() throws Exception { + // Valid. + ByteBuffer buf = makeNdOptPref64(600, prefixBytes(PREFIX1), 0); + StructNdOptPref64 opt = StructNdOptPref64.parse(buf); + assertPref64OptMatches(600, prefix(PREFIX1, 96), opt); + + // Valid, zero lifetime, /64. + buf = makeNdOptPref64(0, prefixBytes(PREFIX1), 1); + opt = StructNdOptPref64.parse(buf); + assertPref64OptMatches(0, prefix(PREFIX1, 64), opt); + + // Valid, low lifetime, /56. + buf = makeNdOptPref64(8, prefixBytes(PREFIX2), 2); + opt = StructNdOptPref64.parse(buf); + assertPref64OptMatches(8, prefix(PREFIX2, 56), opt); + assertEquals(new IpPrefix("2001:db8:1::/56"), opt.prefix); // Prefix is truncated. + + // Valid, maximum lifetime, /32. + buf = makeNdOptPref64(65528, prefixBytes(PREFIX2), 5); + opt = StructNdOptPref64.parse(buf); + assertPref64OptMatches(65528, prefix(PREFIX2, 32), opt); + assertEquals(new IpPrefix("2001:db8::/32"), opt.prefix); // Prefix is truncated. + + // Lifetime not divisible by 8. + buf = makeNdOptPref64(300, prefixBytes(PREFIX2), 0); + opt = StructNdOptPref64.parse(buf); + assertPref64OptMatches(296, prefix(PREFIX2, 96), opt); + + // Invalid prefix length codes. + buf = makeNdOptPref64(600, prefixBytes(PREFIX1), 6); + assertNull(StructNdOptPref64.parse(buf)); + buf = makeNdOptPref64(600, prefixBytes(PREFIX1), 7); + assertNull(StructNdOptPref64.parse(buf)); + + // Truncated to varying lengths... + buf = makeNdOptPref64(600, prefixBytes(PREFIX1), 3); + final int len = buf.limit(); + for (int i = 0; i < buf.limit() - 1; i++) { + buf.flip(); + buf.limit(i); + assertNull("Option truncated to " + i + " bytes, should have returned null", + StructNdOptPref64.parse(buf)); + } + buf.flip(); + buf.limit(len); + // ... but otherwise OK. + opt = StructNdOptPref64.parse(buf); + assertPref64OptMatches(600, prefix(PREFIX1, 48), opt); + } + + @Test + public void testToString() throws Exception { + ByteBuffer buf = makeNdOptPref64(600, prefixBytes(PREFIX1), 4); + StructNdOptPref64 opt = StructNdOptPref64.parse(buf); + assertPref64OptMatches(600, prefix(PREFIX1, 40), opt); + assertEquals("NdOptPref64(64:ff9b::/40, 600)", opt.toString()); + } + + private void assertInvalidPlc(int plc) { + assertThrows(IllegalArgumentException.class, () -> plcToPrefixLength(plc)); + } + + @Test + public void testPrefixLengthToPlc() { + for (int i = 0; i < 6; i++) { + assertEquals(i, prefixLengthToPlc(plcToPrefixLength(i))); + } + assertInvalidPlc(-1); + assertInvalidPlc(6); + assertInvalidPlc(7); + assertEquals(0, prefixLengthToPlc(96)); + } + + + private void assertInvalidParameters(IpPrefix prefix, int lifetime) { + assertThrows(IllegalArgumentException.class, () -> new StructNdOptPref64(prefix, lifetime)); + } + + @Test + public void testToByteBuffer() throws Exception { + final IpPrefix prefix1 = prefix(PREFIX1, 56); + final IpPrefix prefix2 = prefix(PREFIX2, 96); + + StructNdOptPref64 opt = new StructNdOptPref64(prefix1, 600); + assertToByteBufferMatches(opt, "2602025A0064FF9B0000000000000000"); + assertEquals(new IpPrefix("64:ff9b::/56"), opt.prefix); + assertEquals(600, opt.lifetime); + + opt = new StructNdOptPref64(prefix2, 65519); + assertToByteBufferMatches(opt, "2602FFE820010DB80001000200030064"); + assertEquals(new IpPrefix("2001:db8:1:2:3:64::/96"), opt.prefix); + assertEquals(65512, opt.lifetime); + + assertInvalidParameters(prefix1, 65535); + assertInvalidParameters(prefix2, -1); + assertInvalidParameters(prefix("1.2.3.4", 32), 600); + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlMsgHdrTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlMsgHdrTest.java new file mode 100644 index 0000000000..b7f68c6236 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlMsgHdrTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util.netlink; + +import static org.junit.Assert.fail; + +import android.system.OsConstants; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class StructNlMsgHdrTest { + + public static final short TEST_NLMSG_LEN = 16; + public static final short TEST_NLMSG_FLAGS = StructNlMsgHdr.NLM_F_REQUEST + | StructNlMsgHdr.NLM_F_MULTI | StructNlMsgHdr.NLM_F_ACK | StructNlMsgHdr.NLM_F_ECHO; + public static final short TEST_NLMSG_SEQ = 1234; + public static final short TEST_NLMSG_PID = 5678; + + // Checking the header string nlmsg_{len, ..} of the number can make sure that the checking + // number comes from the expected element. + // TODO: Verify more flags once StructNlMsgHdr can distinguish the flags which have the same + // value. For example, NLM_F_MATCH (0x200) and NLM_F_EXCL (0x200) can't be distinguished. + // See StructNlMsgHdrTest#stringForNlMsgFlags. + public static final String TEST_NLMSG_LEN_STR = "nlmsg_len{16}"; + public static final String TEST_NLMSG_FLAGS_STR = + "NLM_F_REQUEST|NLM_F_MULTI|NLM_F_ACK|NLM_F_ECHO"; + public static final String TEST_NLMSG_SEQ_STR = "nlmsg_seq{1234}"; + public static final String TEST_NLMSG_PID_STR = "nlmsg_pid{5678}"; + + private StructNlMsgHdr makeStructNlMsgHdr(short type) { + final StructNlMsgHdr struct = new StructNlMsgHdr(); + struct.nlmsg_len = TEST_NLMSG_LEN; + struct.nlmsg_type = type; + struct.nlmsg_flags = TEST_NLMSG_FLAGS; + struct.nlmsg_seq = TEST_NLMSG_SEQ; + struct.nlmsg_pid = TEST_NLMSG_PID; + return struct; + } + + private static void assertContains(String actualValue, String expectedSubstring) { + if (actualValue.contains(expectedSubstring)) return; + fail("\"" + actualValue + "\" does not contain \"" + expectedSubstring + "\""); + } + + @Test + public void testToString() { + StructNlMsgHdr struct = makeStructNlMsgHdr(NetlinkConstants.RTM_NEWADDR); + String s = struct.toString(); + assertContains(s, TEST_NLMSG_LEN_STR); + assertContains(s, TEST_NLMSG_FLAGS_STR); + assertContains(s, TEST_NLMSG_SEQ_STR); + assertContains(s, TEST_NLMSG_PID_STR); + assertContains(s, "nlmsg_type{20()}"); + + struct = makeStructNlMsgHdr(NetlinkConstants.SOCK_DIAG_BY_FAMILY); + s = struct.toString(); + assertContains(s, TEST_NLMSG_LEN_STR); + assertContains(s, TEST_NLMSG_FLAGS_STR); + assertContains(s, TEST_NLMSG_SEQ_STR); + assertContains(s, TEST_NLMSG_PID_STR); + assertContains(s, "nlmsg_type{20()}"); + } + + @Test + public void testToStringWithNetlinkFamily() { + StructNlMsgHdr struct = makeStructNlMsgHdr(NetlinkConstants.RTM_NEWADDR); + String s = struct.toString(OsConstants.NETLINK_ROUTE); + assertContains(s, TEST_NLMSG_LEN_STR); + assertContains(s, TEST_NLMSG_FLAGS_STR); + assertContains(s, TEST_NLMSG_SEQ_STR); + assertContains(s, TEST_NLMSG_PID_STR); + assertContains(s, "nlmsg_type{20(RTM_NEWADDR)}"); + + struct = makeStructNlMsgHdr(NetlinkConstants.SOCK_DIAG_BY_FAMILY); + s = struct.toString(OsConstants.NETLINK_INET_DIAG); + assertContains(s, TEST_NLMSG_LEN_STR); + assertContains(s, TEST_NLMSG_FLAGS_STR); + assertContains(s, TEST_NLMSG_SEQ_STR); + assertContains(s, TEST_NLMSG_PID_STR); + assertContains(s, "nlmsg_type{20(SOCK_DIAG_BY_FAMILY)}"); + } +} diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index 6d9414f8aa..89aa136214 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -32,6 +32,7 @@ java_library { "libnanohttpd", "net-tests-utils-host-device-common", "net-utils-device-common", + "net-utils-device-common-netlink", "modules-utils-build_system", ], } diff --git a/staticlibs/testutils/devicetests/com/android/testutils/NetlinkTestUtils.kt b/staticlibs/testutils/devicetests/com/android/testutils/NetlinkTestUtils.kt new file mode 100644 index 0000000000..ccfe710471 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/NetlinkTestUtils.kt @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2020 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. + */ + +@file:JvmName("NetlinkTestUtils") + +package com.android.testutils + +import com.android.net.module.util.netlink.NetlinkConstants.RTM_DELNEIGH +import com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWNEIGH +import libcore.util.HexEncoding +import libcore.util.HexEncoding.encodeToString +import java.net.Inet6Address +import java.net.InetAddress + +/** + * Make a RTM_NEWNEIGH netlink message. + */ +fun makeNewNeighMessage( + neighAddr: InetAddress, + nudState: Short +) = makeNeighborMessage( + neighAddr = neighAddr, + type = RTM_NEWNEIGH, + nudState = nudState +) + +/** + * Make a RTM_DELNEIGH netlink message. + */ +fun makeDelNeighMessage( + neighAddr: InetAddress, + nudState: Short +) = makeNeighborMessage( + neighAddr = neighAddr, + type = RTM_DELNEIGH, + nudState = nudState +) + +private fun makeNeighborMessage( + neighAddr: InetAddress, + type: Short, + nudState: Short +) = HexEncoding.decode( + /* ktlint-disable indent */ + // -- struct nlmsghdr -- + // length = 88 or 76: + (if (neighAddr is Inet6Address) "58000000" else "4c000000") + + type.toLEHex() + // type + "0000" + // flags + "00000000" + // seqno + "00000000" + // pid (0 == kernel) + // struct ndmsg + // family (AF_INET6 or AF_INET) + (if (neighAddr is Inet6Address) "0a" else "02") + + "00" + // pad1 + "0000" + // pad2 + "15000000" + // interface index (21 == wlan0, on test device) + nudState.toLEHex() + // NUD state + "00" + // flags + "01" + // type + // -- struct nlattr: NDA_DST -- + // length = 20 or 8: + (if (neighAddr is Inet6Address) "1400" else "0800") + + "0100" + // type (1 == NDA_DST, for neighbor messages) + // IP address: + encodeToString(neighAddr.address) + + // -- struct nlattr: NDA_LLADDR -- + "0a00" + // length = 10 + "0200" + // type (2 == NDA_LLADDR, for neighbor messages) + "00005e000164" + // MAC Address (== 00:00:5e:00:01:64) + "0000" + // padding, for 4 byte alignment + // -- struct nlattr: NDA_PROBES -- + "0800" + // length = 8 + "0400" + // type (4 == NDA_PROBES, for neighbor messages) + "01000000" + // number of probes + // -- struct nlattr: NDA_CACHEINFO -- + "1400" + // length = 20 + "0300" + // type (3 == NDA_CACHEINFO, for neighbor messages) + "05190000" + // ndm_used, as "clock ticks ago" + "05190000" + // ndm_confirmed, as "clock ticks ago" + "190d0000" + // ndm_updated, as "clock ticks ago" + "00000000", // ndm_refcnt + false /* allowSingleChar */) + /* ktlint-enable indent */ + +/** + * Convert a [Short] to a little-endian hex string. + */ +private fun Short.toLEHex() = String.format("%04x", java.lang.Short.reverseBytes(this)) From da2904c7d169057579b4926c4a73e6b46b8c17cb Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 6 Aug 2021 01:33:04 +0000 Subject: [PATCH 239/777] Append link-layer address parameter in makeNewNeighborMessage. Append link-layer address parameter in makeNewNeighMessage, the caller can assign different link-layer address as netlink attributes, which is helpful for testing and simulating the case although the neighbor is still reachable, the link-layer address has changed. If no special link layer address is assigned, just use the default constant MAC address. Bug: 162944199 Test: atest NetworkStaticLibsTest NetworkStackTests Change-Id: I49de035075fa97655358be0089f0fbee293823a0 --- .../com/android/testutils/NetlinkTestUtils.kt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/NetlinkTestUtils.kt b/staticlibs/testutils/devicetests/com/android/testutils/NetlinkTestUtils.kt index ccfe710471..3f5460bf97 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/NetlinkTestUtils.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/NetlinkTestUtils.kt @@ -25,16 +25,21 @@ import libcore.util.HexEncoding.encodeToString import java.net.Inet6Address import java.net.InetAddress +private const val VRRP_MAC_ADDR = "00005e000164" + /** * Make a RTM_NEWNEIGH netlink message. */ +@JvmOverloads fun makeNewNeighMessage( neighAddr: InetAddress, - nudState: Short + nudState: Short, + linkLayerAddr: String = VRRP_MAC_ADDR ) = makeNeighborMessage( neighAddr = neighAddr, type = RTM_NEWNEIGH, - nudState = nudState + nudState = nudState, + linkLayerAddr = linkLayerAddr ) /** @@ -52,7 +57,8 @@ fun makeDelNeighMessage( private fun makeNeighborMessage( neighAddr: InetAddress, type: Short, - nudState: Short + nudState: Short, + linkLayerAddr: String = VRRP_MAC_ADDR ) = HexEncoding.decode( /* ktlint-disable indent */ // -- struct nlmsghdr -- @@ -80,7 +86,7 @@ private fun makeNeighborMessage( // -- struct nlattr: NDA_LLADDR -- "0a00" + // length = 10 "0200" + // type (2 == NDA_LLADDR, for neighbor messages) - "00005e000164" + // MAC Address (== 00:00:5e:00:01:64) + linkLayerAddr + // MAC Address(default == 00:00:5e:00:01:64) "0000" + // padding, for 4 byte alignment // -- struct nlattr: NDA_PROBES -- "0800" + // length = 8 From 3be7e9b37099cd3386b46f64a33f280e25116016 Mon Sep 17 00:00:00 2001 From: Nate Jiang Date: Wed, 11 Aug 2021 00:09:16 -0700 Subject: [PATCH 240/777] Remove NetUtils from filegroup to avoid dulicate As framework-wifi already include NetUtils by net-utils-framework-wifi-common-srcs, remove this from net-utils-wifi-service-common-srcs to avoid Duplicated class in Wifi Apex Bug: 195965491 Test: build module Change-Id: Id8b1c76f6120c02c93225f0b25970b217d88c295 --- staticlibs/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 4e7a9da7d0..a7a027cb38 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -223,7 +223,6 @@ filegroup { "device/android/net/NetworkFactoryImpl.java", "device/android/net/NetworkFactoryLegacyImpl.java", "device/android/net/NetworkFactoryShim.java", - "framework/com/android/net/module/util/NetUtils.java", ], visibility: [ "//frameworks/opt/net/wifi/service", From 32327fd7b82811e5da04a9d44c3e54036bb94418 Mon Sep 17 00:00:00 2001 From: Nate Jiang Date: Tue, 10 Aug 2021 12:12:25 -0700 Subject: [PATCH 241/777] Remove NetUtils from filegroup to avoid duplicate As framework-wifi already include NetUtils by net-utils-framework-wifi-common-srcs, remove this from net-utils-wifi-service-common-srcs to avoid Duplicated class in Wifi Apex Bug: 195965491 Test: build module Original-Change: https://android-review.googlesource.com/1793288 Merged-In: Id8b1c76f6120c02c93225f0b25970b217d88c295 Change-Id: Ic713b2ab36a58a8411e80a857a5770891149de12 --- staticlibs/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 1371c8ccf3..ea6dd9013c 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -189,7 +189,6 @@ filegroup { "device/android/net/NetworkFactoryImpl.java", "device/android/net/NetworkFactoryLegacyImpl.java", "device/android/net/NetworkFactoryShim.java", - "framework/com/android/net/module/util/NetUtils.java", ], visibility: [ "//frameworks/opt/net/wifi/service", From 843740592c698e217dde9c46af50b515178d0cae Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 16 Aug 2021 18:06:57 +0900 Subject: [PATCH 242/777] Add the ConnectivityModuleTest annotation The annotation will be used to mark tests cases that are part of MTS modules used by multiple modules, to indicate that the test case should only be run if the MTS suite should cover an updated Connectivity (tethering) module. This allows tests to verify new behavior in the Connectivity module, without failing if that module is not updated. Bug: 196755836 Test: mts-tradefed run mts-network with exclude-annotation in the config Change-Id: I05d2200c7ab68042e4e48029e045f164c26b8037 --- .../testutils/ConnectivityModuleTest.kt | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 staticlibs/testutils/hostdevice/com/android/testutils/ConnectivityModuleTest.kt diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/ConnectivityModuleTest.kt b/staticlibs/testutils/hostdevice/com/android/testutils/ConnectivityModuleTest.kt new file mode 100644 index 0000000000..ec485fea55 --- /dev/null +++ b/staticlibs/testutils/hostdevice/com/android/testutils/ConnectivityModuleTest.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 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 com.android.testutils + +/** + * Indicates that the test covers functionality that was rolled out in a connectivity module update. + * + * Annotated MTS tests will typically only be run in Connectivity/Tethering module MTS, and not when + * only other modules (such as NetworkStack) have been updated. + * Annotated CTS tests will always be run, as the Connectivity module should be at least newer than + * the CTS suite. + */ +annotation class ConnectivityModuleTest From ee9a1bad35ac42f685cac42163f46865a0e8a010 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Fri, 20 Aug 2021 18:35:34 +0800 Subject: [PATCH 243/777] Add CollectionUtils.contains for short Test: atest NetworkStaticLibTests Change-Id: I0ed29cc5dad20a3c52df8e1643aed65f6b2f50c7 --- .../android/net/module/util/CollectionUtils.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index 0696cca897..9eb2c22754 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -120,6 +120,19 @@ public final class CollectionUtils { return false; } + /** + * @return true if the array contains the specified value. + */ + public static boolean contains(@Nullable short[] array, short value) { + if (array == null) return false; + for (int i = 0; i < array.length; i++) { + if (array[i] == value) { + return true; + } + } + return false; + } + /** * @return true if the array contains the specified value. */ From 0ab5f70868fe61a724754f8b3615313cebe9b498 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Fri, 27 Aug 2021 16:51:21 +0800 Subject: [PATCH 244/777] Refactor CollectionUtils.contains for short Keep the consistent style as CollectionUtils.contains for int because the compiler already does the optimization. Test: atest NetworkStaticLibTests Change-Id: Ide49c3761c552e8e184889a2f8d9f1aa8a130d60 --- .../com/android/net/module/util/CollectionUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index 9eb2c22754..6e1af557f1 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -125,8 +125,8 @@ public final class CollectionUtils { */ public static boolean contains(@Nullable short[] array, short value) { if (array == null) return false; - for (int i = 0; i < array.length; i++) { - if (array[i] == value) { + for (int element : array) { + if (element == value) { return true; } } From 8ce72e25186434a8112a948735ace7558d8fa8f2 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Thu, 26 Aug 2021 16:34:36 +0800 Subject: [PATCH 245/777] Test CollectionUtils.contains Test: atest NetworkStaticLibTests Change-Id: I5a4426001a4ff7c4ca65be92085e9af3a21267e5 --- .../net/module/util/CollectionUtilsTest.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt index 0886426577..96648a59c0 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt @@ -61,4 +61,20 @@ class CollectionUtilsTest { assertTrue(CollectionUtils.all(listOf(1)) { true }) assertFalse(CollectionUtils.all(listOf(1)) { false }) } + + @Test + fun testContains() { + assertTrue(CollectionUtils.contains(shortArrayOf(10, 20, 30), 10)) + assertTrue(CollectionUtils.contains(shortArrayOf(10, 20, 30), 30)) + assertFalse(CollectionUtils.contains(shortArrayOf(10, 20, 30), 40)) + assertFalse(CollectionUtils.contains(null, 10.toShort())) + assertTrue(CollectionUtils.contains(intArrayOf(10, 20, 30), 10)) + assertTrue(CollectionUtils.contains(intArrayOf(10, 20, 30), 30)) + assertFalse(CollectionUtils.contains(intArrayOf(10, 20, 30), 40)) + assertFalse(CollectionUtils.contains(null, 10.toInt())) + assertTrue(CollectionUtils.contains(arrayOf("A", "B", "C"), "A")) + assertTrue(CollectionUtils.contains(arrayOf("A", "B", "C"), "C")) + assertFalse(CollectionUtils.contains(arrayOf("A", "B", "C"), "D")) + assertFalse(CollectionUtils.contains(null, "A")) + } } From 3fe08ae6263004525c5b0eb138f0ccfdd99f35a4 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Mon, 26 Jul 2021 03:17:27 +0000 Subject: [PATCH 246/777] Add StructNdOptRdnss class to parse RDNSS option from netlink message. Bug: 163492391 Test: atest NetworkStaticlibTests Change-Id: I64059ce3576a3ce9467bd89a9dfcfc7b0498726d --- .../net/module/util/netlink/NdOption.java | 3 + .../module/util/netlink/StructNdOptRdnss.java | 134 ++++++++++++ .../net/module/util/structs/RdnssOption.java | 3 +- .../util/netlink/NduseroptMessageTest.java | 42 +++- .../util/netlink/StructNdOptRdnssTest.java | 200 ++++++++++++++++++ 5 files changed, 378 insertions(+), 4 deletions(-) create mode 100644 staticlibs/device/com/android/net/module/util/netlink/StructNdOptRdnss.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptRdnssTest.java diff --git a/staticlibs/device/com/android/net/module/util/netlink/NdOption.java b/staticlibs/device/com/android/net/module/util/netlink/NdOption.java index 50a3496660..67554978a9 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NdOption.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NdOption.java @@ -62,6 +62,9 @@ public class NdOption { case StructNdOptPref64.TYPE: return StructNdOptPref64.parse(buf); + case StructNdOptRdnss.TYPE: + return StructNdOptRdnss.parse(buf); + default: int newPosition = Math.min(buf.limit(), buf.position() + length * 8); buf.position(newPosition); diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNdOptRdnss.java b/staticlibs/device/com/android/net/module/util/netlink/StructNdOptRdnss.java new file mode 100644 index 0000000000..6dee0c496b --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNdOptRdnss.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.netlink; + +import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN; + +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.structs.RdnssOption; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * The Recursive DNS Server Option. RFC 8106. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * : Addresses of IPv6 Recursive DNS Servers : + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class StructNdOptRdnss extends NdOption { + private static final String TAG = StructNdOptRdnss.class.getSimpleName(); + public static final int TYPE = 25; + // Length in 8-byte units, only if one IPv6 address included. + public static final byte MIN_OPTION_LEN = 3; + + public final RdnssOption header; + @NonNull + public final Inet6Address[] servers; + + public StructNdOptRdnss(@NonNull final Inet6Address[] servers, long lifetime) { + super((byte) TYPE, servers.length * 2 + 1); + + Objects.requireNonNull(servers, "Recursive DNS Servers address array must not be null"); + if (servers.length == 0) { + throw new IllegalArgumentException("DNS server address array must not be empty"); + } + + this.header = new RdnssOption((byte) TYPE, (byte) (servers.length * 2 + 1), + (short) 0 /* reserved */, lifetime); + this.servers = servers.clone(); + } + + /** + * Parses an RDNSS option from a {@link ByteBuffer}. + * + * @param buf The buffer from which to parse the option. The buffer's byte order must be + * {@link java.nio.ByteOrder#BIG_ENDIAN}. + * @return the parsed option, or {@code null} if the option could not be parsed successfully. + */ + public static StructNdOptRdnss parse(@NonNull ByteBuffer buf) { + if (buf == null || buf.remaining() < MIN_OPTION_LEN * 8) return null; + try { + final RdnssOption header = Struct.parse(RdnssOption.class, buf); + if (header.type != TYPE) { + throw new IllegalArgumentException("Invalid type " + header.type); + } + if (header.length < MIN_OPTION_LEN || (header.length % 2 == 0)) { + throw new IllegalArgumentException("Invalid length " + header.length); + } + + final int numOfDnses = (header.length - 1) / 2; + final Inet6Address[] servers = new Inet6Address[numOfDnses]; + for (int i = 0; i < numOfDnses; i++) { + byte[] rawAddress = new byte[IPV6_ADDR_LEN]; + buf.get(rawAddress); + servers[i] = (Inet6Address) InetAddress.getByAddress(rawAddress); + } + return new StructNdOptRdnss(servers, header.lifetime); + } catch (IllegalArgumentException | BufferUnderflowException | UnknownHostException e) { + // Not great, but better than throwing an exception that might crash the caller. + // Convention in this package is that null indicates that the option was truncated + // or malformed, so callers must already handle it. + Log.d(TAG, "Invalid RDNSS option: " + e); + return null; + } + } + + protected void writeToByteBuffer(ByteBuffer buf) { + header.writeToByteBuffer(buf); + for (int i = 0; i < servers.length; i++) { + buf.put(servers[i].getAddress()); + } + } + + /** Outputs the wire format of the option to a new big-endian ByteBuffer. */ + public ByteBuffer toByteBuffer() { + final ByteBuffer buf = ByteBuffer.allocate(Struct.getSize(RdnssOption.class) + + servers.length * IPV6_ADDR_LEN); + writeToByteBuffer(buf); + buf.flip(); + return buf; + } + + @Override + @NonNull + public String toString() { + final StringJoiner sj = new StringJoiner(",", "[", "]"); + for (int i = 0; i < servers.length; i++) { + sj.add(servers[i].getHostAddress()); + } + return String.format("NdOptRdnss(%s,servers:%s)", header.toString(), sj.toString()); + } +} diff --git a/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java b/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java index b7c2b0c11a..4a5bd7e9f8 100644 --- a/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java +++ b/staticlibs/device/com/android/net/module/util/structs/RdnssOption.java @@ -53,7 +53,8 @@ public class RdnssOption extends Struct { @Field(order = 3, type = Type.U32) public final long lifetime; - RdnssOption(final byte type, final byte length, final short reserved, final long lifetime) { + public RdnssOption(final byte type, final byte length, final short reserved, + final long lifetime) { this.type = type; this.length = length; this.reserved = reserved; diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NduseroptMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NduseroptMessageTest.java index 538c09bc50..f297108561 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NduseroptMessageTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NduseroptMessageTest.java @@ -20,11 +20,13 @@ import static android.net.InetAddresses.parseNumericAddress; import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.NETLINK_ROUTE; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import android.net.InetAddresses; import android.net.IpPrefix; import androidx.test.filters.SmallTest; @@ -35,6 +37,7 @@ import libcore.util.HexEncoding; import org.junit.Test; import org.junit.runner.RunWith; +import java.net.Inet6Address; import java.net.InetAddress; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -112,12 +115,35 @@ public class NduseroptMessageTest { assertPref64Option("64:ff9b::/96", msg.option); } + @Test + public void testParseRdnssOptionWithinNetlinkMessage() throws Exception { + final String hexBytes = + "4C000000440000000000000000000000" + + "0A0018001E0000008600000000000000" + + "1903000000001770FD123456789000000000000000000001" // RDNSS option + + "14000100FE800000000000000250B6FFFEB7C499"; + + ByteBuffer buf = toBuffer(hexBytes); + assertEquals(76, buf.limit()); + buf.order(ByteOrder.nativeOrder()); + + NetlinkMessage nlMsg = NetlinkMessage.parse(buf, NETLINK_ROUTE); + assertNotNull(nlMsg); + assertTrue(nlMsg instanceof NduseroptMessage); + + NduseroptMessage msg = (NduseroptMessage) nlMsg; + InetAddress srcaddr = InetAddress.getByName("fe80::250:b6ff:feb7:c499%30"); + assertMatches(AF_INET6, 24, 30, ICMP_TYPE_RA, (byte) 0, srcaddr, msg); + assertRdnssOption(msg.option, 6000 /* lifetime */, + (Inet6Address) InetAddresses.parseNumericAddress("fd12:3456:7890::1")); + } + @Test public void testParseUnknownOptionWithinNetlinkMessage() throws Exception { final String hexBytes = - "4C0000004400000000000000000000000" - + "A0018001E0000008600000000000000" - + "1903000000001770FD123456789000000000000000000001" // RDNSS option + "4C000000440000000000000000000000" + + "0A0018001E0000008600000000000000" + + "310300000000177006676F6F676C652E03636F6D00000000" // DNSSL option: "google.com" + "14000100FE800000000000000250B6FFFEB7C499"; ByteBuffer buf = toBuffer(hexBytes); @@ -243,4 +269,14 @@ public class NduseroptMessageTest { StructNdOptPref64 pref64Opt = (StructNdOptPref64) opt; assertEquals(new IpPrefix(prefix), pref64Opt.prefix); } + + private void assertRdnssOption(NdOption opt, long lifetime, Inet6Address... servers) { + assertNotNull(opt); + assertTrue(opt instanceof StructNdOptRdnss); + StructNdOptRdnss rdnss = (StructNdOptRdnss) opt; + assertEquals(StructNdOptRdnss.TYPE, rdnss.type); + assertEquals((byte) (servers.length * 2 + 1), rdnss.header.length); + assertEquals(lifetime, rdnss.header.lifetime); + assertArrayEquals(servers, rdnss.servers); + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptRdnssTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptRdnssTest.java new file mode 100644 index 0000000000..7df8fa77a5 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptRdnssTest.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.netlink; + +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_RDNSS; +import static com.android.testutils.MiscAsserts.assertThrows; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import android.net.InetAddresses; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.net.module.util.structs.RdnssOption; + +import libcore.util.HexEncoding; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet6Address; +import java.nio.ByteBuffer; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class StructNdOptRdnssTest { + private static final String DNS_SERVER1 = "2001:4860:4860::64"; + private static final String DNS_SERVER2 = "2001:4860:4860::6464"; + + private static final Inet6Address[] DNS_SERVER_ADDRESSES = new Inet6Address[] { + (Inet6Address) InetAddresses.parseNumericAddress(DNS_SERVER1), + (Inet6Address) InetAddresses.parseNumericAddress(DNS_SERVER2), + }; + + private static final String RDNSS_OPTION_BYTES = + "1905" // type=25, len=5 (40 bytes) + + "0000" // reserved + + "00000E10" // lifetime=3600 + + "20014860486000000000000000000064" // 2001:4860:4860::64 + + "20014860486000000000000000006464"; // 2001:4860:4860::6464 + + private static final String RDNSS_INFINITY_LIFETIME_OPTION_BYTES = + "1905" // type=25, len=3 (24 bytes) + + "0000" // reserved + + "FFFFFFFF" // lifetime=0xffffffff + + "20014860486000000000000000000064" // 2001:4860:4860::64 + + "20014860486000000000000000006464"; // 2001:4860:4860::6464 + + private void assertRdnssOptMatches(final StructNdOptRdnss opt, int length, long lifetime, + final Inet6Address[] servers) { + assertEquals(StructNdOptRdnss.TYPE, opt.type); + assertEquals(length, opt.length); + assertEquals(lifetime, opt.header.lifetime); + assertEquals(servers, opt.servers); + } + + private ByteBuffer makeRdnssOption(byte type, byte length, long lifetime, String... servers) + throws Exception { + final ByteBuffer buf = ByteBuffer.allocate(8 + servers.length * 16) + .put(type) + .put(length) + .putShort((short) 0) // Reserved + .putInt((int) (lifetime & 0xFFFFFFFFL)); + for (int i = 0; i < servers.length; i++) { + final byte[] rawBytes = + ((Inet6Address) InetAddresses.parseNumericAddress(servers[i])).getAddress(); + buf.put(rawBytes); + } + buf.flip(); + return buf; + } + + private void assertToByteBufferMatches(StructNdOptRdnss opt, String expected) { + String actual = HexEncoding.encodeToString(opt.toByteBuffer().array()); + assertEquals(expected, actual); + } + + private void doRdnssOptionParsing(final String optionHexString, int length, long lifetime, + final Inet6Address[] servers) { + final byte[] rawBytes = HexEncoding.decode(optionHexString); + final StructNdOptRdnss opt = StructNdOptRdnss.parse(ByteBuffer.wrap(rawBytes)); + assertRdnssOptMatches(opt, length, lifetime, servers); + assertToByteBufferMatches(opt, optionHexString); + } + + @Test + public void testParsing() throws Exception { + doRdnssOptionParsing(RDNSS_OPTION_BYTES, 5 /* length */, 3600 /* lifetime */, + DNS_SERVER_ADDRESSES); + } + + @Test + public void testParsing_infinityLifetime() throws Exception { + doRdnssOptionParsing(RDNSS_INFINITY_LIFETIME_OPTION_BYTES, 5 /* length */, + 0xffffffffL /* lifetime */, DNS_SERVER_ADDRESSES); + } + + @Test + public void testToByteBuffer() { + final StructNdOptRdnss rdnss = new StructNdOptRdnss(DNS_SERVER_ADDRESSES, 3600); + assertToByteBufferMatches(rdnss, RDNSS_OPTION_BYTES); + } + + @Test + public void testToByteBuffer_infinityLifetime() { + final StructNdOptRdnss rdnss = new StructNdOptRdnss(DNS_SERVER_ADDRESSES, 0xffffffffL); + assertToByteBufferMatches(rdnss, RDNSS_INFINITY_LIFETIME_OPTION_BYTES); + } + + @Test + public void testParsing_invalidType() throws Exception { + final ByteBuffer buf = makeRdnssOption((byte) 38, (byte) 5 /* length */, + 3600 /* lifetime */, DNS_SERVER1, DNS_SERVER2); + assertNull(StructNdOptRdnss.parse(buf)); + } + + @Test + public void testParsing_smallOptionLength() throws Exception { + final ByteBuffer buf = makeRdnssOption((byte) ICMPV6_ND_OPTION_RDNSS, + (byte) 2 /* length */, 3600 /* lifetime */, DNS_SERVER1, DNS_SERVER2); + assertNull(StructNdOptRdnss.parse(buf)); + } + + @Test + public void testParsing_oddOptionLength() throws Exception { + final ByteBuffer buf = makeRdnssOption((byte) ICMPV6_ND_OPTION_RDNSS, + (byte) 6 /* length */, 3600 /* lifetime */, DNS_SERVER1, DNS_SERVER2); + assertNull(StructNdOptRdnss.parse(buf)); + } + + @Test + public void testParsing_truncatedByteBuffer() throws Exception { + ByteBuffer buf = makeRdnssOption((byte) ICMPV6_ND_OPTION_RDNSS, + (byte) 5 /* length */, 3600 /* lifetime */, DNS_SERVER1, DNS_SERVER2); + final int len = buf.limit(); + for (int i = 0; i < buf.limit() - 1; i++) { + buf.flip(); + buf.limit(i); + assertNull("Option truncated to " + i + " bytes, should have returned null", + StructNdOptRdnss.parse(buf)); + } + buf.flip(); + buf.limit(len); + + final StructNdOptRdnss opt = StructNdOptRdnss.parse(buf); + assertRdnssOptMatches(opt, 5 /* length */, 3600 /* lifetime */, DNS_SERVER_ADDRESSES); + } + + @Test + public void testParsing_nullByteBuffer() { + assertNull(StructNdOptRdnss.parse(null)); + } + + @Test + public void testParsing_invalidByteBufferLength() throws Exception { + final ByteBuffer buf = makeRdnssOption((byte) ICMPV6_ND_OPTION_RDNSS, + (byte) 5 /* length */, 3600 /* lifetime */, DNS_SERVER1, DNS_SERVER2); + buf.limit(20); // less than MIN_OPT_LEN * 8 + assertNull(StructNdOptRdnss.parse(buf)); + } + + @Test + public void testConstructor_nullDnsServerAddressArray() { + assertThrows(NullPointerException.class, + () -> new StructNdOptRdnss(null /* servers */, 3600 /* lifetime */)); + } + + @Test + public void testConstructor_emptyDnsServerAddressArray() { + assertThrows(IllegalArgumentException.class, + () -> new StructNdOptRdnss(new Inet6Address[0] /* empty server array */, + 3600 /* lifetime*/)); + } + + @Test + public void testToString() { + final ByteBuffer buf = RdnssOption.build(3600 /* lifetime */, DNS_SERVER1, DNS_SERVER2); + final StructNdOptRdnss opt = StructNdOptRdnss.parse(buf); + final String expected = "NdOptRdnss(type: 25, length: 5, reserved: 0, lifetime: 3600," + + "servers:[2001:4860:4860::64,2001:4860:4860::6464])"; + assertRdnssOptMatches(opt, 5 /* length */, 3600 /* lifetime */, DNS_SERVER_ADDRESSES); + assertEquals(expected, opt.toString()); + } +} From 4d6cafb5ca4934f101a44b8d5c89773b57e8cb8c Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Mon, 26 Jul 2021 04:08:42 +0000 Subject: [PATCH 247/777] Parse ND options in netlink message as an ByteBuffer slice. Parsing ND options as an ByteBuffer slice provides more reliable way to read raw data from buffer no matter of the option might be malformed, truncated or options with correct length and value, which doesn't affect the buffer pointer advances to deal with the remaining data such as attribute fields even if parsing ND options return null. Bug: 163492391 Test: atest NetworkStaticLibsTest Change-Id: Ic348abe6b5d1ceddfde47f19dcaec324927798d1 --- .../net/module/util/netlink/NdOption.java | 6 ++-- .../module/util/netlink/NduseroptMessage.java | 28 +++++++++++-------- .../util/netlink/StructNdOptPref64.java | 2 +- .../util/netlink/NduseroptMessageTest.java | 13 +++++++++ .../util/netlink/StructNdOptRdnssTest.java | 5 ---- 5 files changed, 35 insertions(+), 19 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/NdOption.java b/staticlibs/device/com/android/net/module/util/netlink/NdOption.java index 67554978a9..defc88a765 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NdOption.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NdOption.java @@ -16,6 +16,8 @@ package com.android.net.module.util.netlink; +import androidx.annotation.NonNull; + import java.nio.ByteBuffer; /** @@ -50,8 +52,8 @@ public class NdOption { * @param buf the buffer to parse. * @return a subclass of {@link NdOption}, or {@code null} for an unknown or malformed option. */ - public static NdOption parse(ByteBuffer buf) { - if (buf == null || buf.remaining() < STRUCT_SIZE) return null; + public static NdOption parse(@NonNull ByteBuffer buf) { + if (buf.remaining() < STRUCT_SIZE) return null; // Peek the type without advancing the buffer. byte type = buf.get(buf.position()); diff --git a/staticlibs/device/com/android/net/module/util/netlink/NduseroptMessage.java b/staticlibs/device/com/android/net/module/util/netlink/NduseroptMessage.java index 4e3b9f2da6..9d2402da5d 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NduseroptMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NduseroptMessage.java @@ -19,6 +19,7 @@ package com.android.net.module.util.netlink; import static android.system.OsConstants.AF_INET6; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.net.Inet6Address; import java.net.InetAddress; @@ -56,6 +57,7 @@ public class NduseroptMessage extends NetlinkMessage { * But if it does, we can simply update this code, since userspace is typically newer than the * kernel. */ + @Nullable public final NdOption option; /** The IP address that sent the packet containing the option. */ @@ -80,22 +82,26 @@ public class NduseroptMessage extends NetlinkMessage { // Ensure we don't read past opts_len even if the option length is invalid. // Note that this check is not really necessary since if the option length is not valid, // this struct won't be very useful to the caller. + // + // It's safer to pass the slice of original ByteBuffer to just parse the ND option field, + // although parsing ND option might throw exception or return null, it won't break the + // original ByteBuffer position. buf.order(ByteOrder.BIG_ENDIAN); - int oldLimit = buf.limit(); - buf.limit(start + STRUCT_SIZE + opts_len); try { - option = NdOption.parse(buf); + final ByteBuffer slice = buf.slice(); + slice.limit(opts_len); + option = NdOption.parse(slice); } finally { - buf.limit(oldLimit); + // Advance buffer position according to opts_len in the header. ND option length might + // be incorrect in the malformed packet. + int newPosition = start + STRUCT_SIZE + opts_len; + if (newPosition >= buf.limit()) { + throw new IllegalArgumentException("ND option extends past end of buffer"); + } + buf.position(newPosition); } - // The source address. - int newPosition = start + STRUCT_SIZE + opts_len; - if (newPosition >= buf.limit()) { - throw new IllegalArgumentException("ND options extend past end of buffer"); - } - buf.position(newPosition); - + // The source address attribute. StructNlAttr nla = StructNlAttr.parse(buf); if (nla == null || nla.nla_type != NDUSEROPT_SRCADDR || nla.nla_value == null) { throw new IllegalArgumentException("Invalid source address in ND useropt"); diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java b/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java index bde6983187..f6b2e0e504 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java @@ -135,7 +135,7 @@ public class StructNdOptPref64 extends NdOption { * (for example, if it was truncated, or if the prefix length code was wrong). */ public static StructNdOptPref64 parse(@NonNull ByteBuffer buf) { - if (buf == null || buf.remaining() < STRUCT_SIZE) return null; + if (buf.remaining() < STRUCT_SIZE) return null; try { return new StructNdOptPref64(buf); } catch (IllegalArgumentException e) { diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NduseroptMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NduseroptMessageTest.java index f297108561..4fc5ec2e2b 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NduseroptMessageTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NduseroptMessageTest.java @@ -138,6 +138,19 @@ public class NduseroptMessageTest { (Inet6Address) InetAddresses.parseNumericAddress("fd12:3456:7890::1")); } + @Test + public void testParseTruncatedRdnssOptionWithinNetlinkMessage() throws Exception { + final String truncatedHexBytes = + "38000000440000000000000000000000" + + "0A0018001E0000008600000000000000" + + "1903000000001770FD123456789000000000000000000001"; // RDNSS option + + ByteBuffer buf = toBuffer(truncatedHexBytes); + buf.order(ByteOrder.nativeOrder()); + NetlinkMessage nlMsg = NetlinkMessage.parse(buf, NETLINK_ROUTE); + assertNull(nlMsg); + } + @Test public void testParseUnknownOptionWithinNetlinkMessage() throws Exception { final String hexBytes = diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptRdnssTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptRdnssTest.java index 7df8fa77a5..1dcb9b59fc 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptRdnssTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptRdnssTest.java @@ -162,11 +162,6 @@ public class StructNdOptRdnssTest { assertRdnssOptMatches(opt, 5 /* length */, 3600 /* lifetime */, DNS_SERVER_ADDRESSES); } - @Test - public void testParsing_nullByteBuffer() { - assertNull(StructNdOptRdnss.parse(null)); - } - @Test public void testParsing_invalidByteBufferLength() throws Exception { final ByteBuffer buf = makeRdnssOption((byte) ICMPV6_ND_OPTION_RDNSS, From 14f746c07ab591763458e03294fb798e72f893b2 Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 26 Aug 2021 19:46:35 +0800 Subject: [PATCH 248/777] Add initTestNetwork with a list of LinkAddress To support setup test network with both ipv4 and ipv6. Add overloading function for initTestNetwork to allow specify mutiple addresses. Also allow to get TestNetworkInterface from this test network, so the caller can use it to send and write packets. Test: atest EthernetTetheringTest Change-Id: Ic7626582c021dee824f95900e4de8efee861a9ea --- .../android/testutils/TestNetworkTracker.kt | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt index 36c09ce645..40731eae2f 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt @@ -31,17 +31,35 @@ import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit /** - * Create a test network based on a TUN interface. + * Create a test network based on a TUN interface with a LinkAddress. * * This method will block until the test network is available. Requires * [android.Manifest.permission.CHANGE_NETWORK_STATE] and * [android.Manifest.permission.MANAGE_TEST_NETWORKS]. */ -fun initTestNetwork(context: Context, interfaceAddr: LinkAddress, setupTimeoutMs: Long = 10_000L): - TestNetworkTracker { +fun initTestNetwork( + context: Context, + interfaceAddr: LinkAddress, + setupTimeoutMs: Long = 10_000L +): TestNetworkTracker { + return initTestNetwork(context, listOf(interfaceAddr), setupTimeoutMs) +} + +/** + * Create a test network based on a TUN interface with giving LinkAddress list. + * + * This method will block until the test network is available. Requires + * [android.Manifest.permission.CHANGE_NETWORK_STATE] and + * [android.Manifest.permission.MANAGE_TEST_NETWORKS]. + */ +fun initTestNetwork( + context: Context, + linkAddrs: List, + setupTimeoutMs: Long = 10_000L +): TestNetworkTracker { val tnm = context.getSystemService(TestNetworkManager::class.java) - val iface = if (isAtLeastS()) tnm.createTunInterface(listOf(interfaceAddr)) - else tnm.createTunInterface(arrayOf(interfaceAddr)) + val iface = if (isAtLeastS()) tnm.createTunInterface(linkAddrs) + else tnm.createTunInterface(linkAddrs.toTypedArray()) return TestNetworkTracker(context, iface, tnm, setupTimeoutMs) } @@ -61,6 +79,7 @@ class TestNetworkTracker internal constructor( private val networkCallback: NetworkCallback val network: Network + val testIface: TestNetworkInterface init { val networkFuture = CompletableFuture() @@ -85,6 +104,8 @@ class TestNetworkTracker internal constructor( teardown() throw e } + + testIface = iface } fun teardown() { From 190f81d8d34e2d4e3d71e1780f8fcedd4da963cc Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 20 Jul 2021 17:41:11 +0800 Subject: [PATCH 249/777] Fix type confusion in createRandomUnicastAddress In createRandomUnicastAddress, it compare the mac with the DEFAULT_MAC_ADDRESS. However, the DEFAULT_MAC_ADDRESS is defined as a string, so the MacAddress equals check always return false. This patch corrects the wrong String definition to MacAddress. Bug: 182165856 Test: NetworkStaticLibTests Change-Id: Ia0905bfa7a4dd723f42903f77f9d925349ce193e --- .../framework/com/android/net/module/util/MacAddressUtils.java | 3 ++- .../tests/unit/src/android/net/util/MacAddressUtilsTest.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/MacAddressUtils.java b/staticlibs/framework/com/android/net/module/util/MacAddressUtils.java index bc11fa2a7c..ab0040c01e 100644 --- a/staticlibs/framework/com/android/net/module/util/MacAddressUtils.java +++ b/staticlibs/framework/com/android/net/module/util/MacAddressUtils.java @@ -41,7 +41,8 @@ public final class MacAddressUtils { private static final long NIC_MASK = longAddrFromByteAddr( MacAddress.fromString("0:0:0:ff:ff:ff").toByteArray()); // Matches WifiInfo.DEFAULT_MAC_ADDRESS - private static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00"; + private static final MacAddress DEFAULT_MAC_ADDRESS = + MacAddress.fromString("02:00:00:00:00:00"); private static final int ETHER_ADDR_LEN = 6; /** diff --git a/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java index 66d89ffd1d..8988571d3e 100644 --- a/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java @@ -33,7 +33,8 @@ import org.junit.runner.RunWith; public final class MacAddressUtilsTest { // Matches WifiInfo.DEFAULT_MAC_ADDRESS - private static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00"; + private static final MacAddress DEFAULT_MAC_ADDRESS = + MacAddress.fromString("02:00:00:00:00:00"); @Test public void testIsMulticastAddress() { From 5872cb8dbd8fba4e7dd63ea68470eb8eafa88181 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 8 Sep 2021 17:56:57 +0900 Subject: [PATCH 250/777] Add a new utility to improve stack traces from automatic testing A common pattern in tests is to use try-finally to make sure cleanup is executed. This is necessary in CTS in particular to make sure the test does not leave the device in a bad state. The problem with using try-finally in this manner is that any exception thrown in the finally{} block will override any thrown in the try{} block. If the exception in finally{} is caused by the one from try{}, then the stack trace reported by the tools is the consequence and not the cause, making it difficult to interpret the stack trace of automated tests. So today, code has to make sure that either the code in finally{} can't throw, or can't be affected by any code in try{}, and both of these are really difficult to ensure in presence in finally{} of code the tester does not control. What we'd want ideally is a structure like try-finally, that guaratees the code in finally{} is executed in all cases, but that bubbles up the exception from try{} if any, and will still bubble up any exception from finally{} if the try{} block hasn't thrown. That's what this new tool does. Usage from Kotlin is like try-finally : tryTest { testing code } cleanup { cleanup code } Usage from Java can't be made as nice, but it's relatively okay : testAndCleanup(() -> { testing code }, () -> { cleanup code }); Bugs listed below are some tests that have been affected by this issue and have unhelpful traces. Test: new test for this code Bug: 198586720 Bug: 198998862 Change-Id: I54b30a7d53772feeade99274b6120a79707ad1c9 --- .../android/net/module/util/CleanupTest.kt | 102 ++++++++++++++++++ .../net/module/util/CleanupTestJava.java | 94 ++++++++++++++++ staticlibs/testutils/Android.bp | 3 + .../com/android/testutils/Cleanup.kt | 95 ++++++++++++++++ 4 files changed, 294 insertions(+) create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/CleanupTestJava.java create mode 100644 staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt new file mode 100644 index 0000000000..f4a7d10385 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util + +import android.util.Log +import com.android.testutils.tryTest +import kotlin.test.assertFailsWith +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import kotlin.test.fail + +private val TAG = CleanupTest::class.toString() + +@RunWith(JUnit4::class) +class CleanupTest { + class TestException1 : Exception() + class TestException2 : Exception() + + @Test + fun testNotThrow() { + var x = 1 + tryTest { + x = 2 + Log.e(TAG, "Do nothing") + } cleanup { + assert(x == 2) + x = 3 + Log.e(TAG, "Do nothing") + } + assert(x == 3) + } + + @Test + fun testThrowTry() { + var x = 1 + assertFailsWith { + tryTest { + x = 2 + throw TestException1() + x = 4 + } cleanup { + assert(x == 2) + x = 3 + Log.e(TAG, "Do nothing") + } + } + assert(x == 3) + } + + @Test + fun testThrowCleanup() { + var x = 1 + assertFailsWith { + tryTest { + x = 2 + Log.e(TAG, "Do nothing") + } cleanup { + assert(x == 2) + x = 3 + throw TestException2() + x = 4 + } + } + assert(x == 3) + } + + @Test + fun testThrowBoth() { + var x = 1 + try { + tryTest { + x = 2 + throw TestException1() + x = 3 + } cleanup { + assert(x == 2) + x = 4 + throw TestException2() + x = 5 + } + fail("Expected failure with TestException1") + } catch (e: TestException1) { + assert(e.suppressedExceptions[0] is TestException2) + } + assert(x == 4) + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTestJava.java b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTestJava.java new file mode 100644 index 0000000000..ba4e679eb1 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTestJava.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util; + +import static com.android.testutils.Cleanup.testAndCleanup; +import static com.android.testutils.MiscAsserts.assertThrows; + +import static org.junit.Assert.assertEquals; + +import android.util.Log; + +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicInteger; + +public class CleanupTestJava { + private static final String TAG = CleanupTestJava.class.getSimpleName(); + private static final class TestException1 extends Exception {} + private static final class TestException2 extends Exception {} + + @Test + public void testNotThrow() { + final AtomicInteger x = new AtomicInteger(1); + testAndCleanup(() -> { + x.compareAndSet(1, 2); + Log.e(TAG, "Do nothing"); + }, () -> { + x.compareAndSet(2, 3); + Log.e(TAG, "Do nothing"); + }); + assertEquals(3, x.get()); + } + + @Test + public void testThrowTry() { + final AtomicInteger x = new AtomicInteger(1); + assertThrows(TestException1.class, () -> + testAndCleanup(() -> { + x.compareAndSet(1, 2); + throw new TestException1(); + // Java refuses to call x.set(3) here because this line is unreachable + }, () -> { + x.compareAndSet(2, 3); + Log.e(TAG, "Do nothing"); + }) + ); + assertEquals(3, x.get()); + } + + @Test + public void testThrowCleanup() { + final AtomicInteger x = new AtomicInteger(1); + assertThrows(TestException2.class, () -> + testAndCleanup(() -> { + x.compareAndSet(1, 2); + Log.e(TAG, "Do nothing"); + }, () -> { + x.compareAndSet(2, 3); + throw new TestException2(); + // Java refuses to call x.set(4) here because this line is unreachable + }) + ); + assertEquals(3, x.get()); + } + + @Test + public void testThrowBoth() { + final AtomicInteger x = new AtomicInteger(1); + assertThrows(TestException1.class, () -> + testAndCleanup(() -> { + x.compareAndSet(1, 2); + throw new TestException1(); + }, () -> { + x.compareAndSet(2, 3); + throw new TestException2(); + }) + ); + assertEquals(3, x.get()); + } +} diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index 89aa136214..153285ba40 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -51,6 +51,9 @@ java_library { "//frameworks/libs/net/common/tests:__subpackages__", "//frameworks/libs/net/client-libs/tests:__subpackages__", ], + libs: [ + "jsr305", + ], static_libs: [ "kotlin-test" ] diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt new file mode 100644 index 0000000000..769d98068c --- /dev/null +++ b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2021 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. + */ + +@file:JvmName("Cleanup") + +package com.android.testutils + +import com.android.testutils.ExceptionUtils.ThrowingRunnable +import javax.annotation.CheckReturnValue + +/** + * Utility to do cleanup in tests without replacing exceptions with those from a finally block. + * + * This utility is meant for tests that want to do cleanup after they execute their test + * logic, whether the test fails (and throws) or not. + * + * The usual way of doing this is to have a try{}finally{} block and put cleanup in finally{}. + * However, if any code in finally{} throws, the exception thrown in finally{} is thrown before + * any thrown in try{} ; that means errors reported from tests are from finally{} even if they + * have been caused by errors in try{}. This is unhelpful in tests, because it results in a + * stacktrace for a symptom rather than a stacktrace for a cause. + * + * To alleviate this, tests are encouraged to make sure the code in finally{} can't throw, or + * that the code in try{} can't cause it to fail. This is not always realistic ; not only does + * it require the developer thinks about complex interactions of code, test code often relies + * on bricks provided by other teams, not controlled by the team writing the test, which may + * start throwing with an update (see b/198998862 for an example). + * + * This utility allows a different approach : it offers a new construct, tryTest{}cleanup{} similar + * to try{}finally{}, but that will always throw the first exception that happens. In other words, + * if only tryTest{} throws or only cleanup{} throws, that exception will be thrown, but contrary + * to the standard try{}finally{}, if both throws, the construct throws the exception that happened + * in tryTest{} rather than the one that happened in cleanup{}. + * + * Kotlin usage is as try{}finally{} : + * tryTest { + * testing code + * } cleanup { + * cleanup code + * } + * + * Java doesn't allow this kind of syntax, so instead a function taking 2 lambdas is provided. + * testAndCleanup(() -> { + * testing code + * }, () -> { + * cleanup code + * }); + */ +class ExceptionCleanupBlock(val originalException: Exception?) { + inline infix fun cleanup(block: () -> Unit) { + try { + block() + if (null != originalException) throw originalException + } catch (e: Exception) { + if (null == originalException) { + throw e + } else { + originalException.addSuppressed(e) + throw originalException + } + } + } +} + +@CheckReturnValue +inline fun tryTest(block: () -> Unit): ExceptionCleanupBlock { + try { + block() + } catch (e: Exception) { + return ExceptionCleanupBlock(e) + } + return ExceptionCleanupBlock(null) +} + +// Java support +fun testAndCleanup(tryBlock: ThrowingRunnable, cleanupBlock: ThrowingRunnable) { + tryTest { + tryBlock.run() + } cleanup { + cleanupBlock.run() + } +} From c2a28e049054aaad675337748f3ce53ea6d3bae7 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 16 Sep 2021 20:29:45 +0900 Subject: [PATCH 251/777] Implement DevSdkIgnoreRule with SdkLevel DevSdkIgnoreRule currently considers a build with SDK 30, version code T as being S, but it is generally considered as being T for development that happens in that branch. Change the implementation of DevSdkIgnoreRule to be consistent with the SdkLevel utility. Test: tests using DevSdkIgnoreRule Change-Id: Ie81b84dff8fef8eac2cfe9694f0265e5bf11b3e6 --- .../com/android/testutils/DevSdkIgnoreRule.kt | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt index 4a83f6fa1a..201bf2d2e8 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt @@ -17,6 +17,7 @@ package com.android.testutils import android.os.Build +import com.android.modules.utils.build.SdkLevel import org.junit.Assume.assumeTrue import org.junit.rules.TestRule import org.junit.runner.Description @@ -29,14 +30,32 @@ import org.junit.runners.model.Statement * [Build.VERSION.SDK_INT]. */ fun isDevSdkInRange(minExclusive: Int?, maxInclusive: Int?): Boolean { - // In-development API n+1 will have SDK_INT == n and CODENAME != REL. - // Stable API n has SDK_INT == n and CODENAME == REL. - val release = "REL" == Build.VERSION.CODENAME - val sdkInt = Build.VERSION.SDK_INT - val devApiLevel = sdkInt + if (release) 0 else 1 + return (minExclusive == null || isDevSdkAfter(minExclusive)) && + (maxInclusive == null || isDevSdkUpTo(maxInclusive)) +} - return (minExclusive == null || devApiLevel > minExclusive) && - (maxInclusive == null || devApiLevel <= maxInclusive) +private fun isDevSdkAfter(minExclusive: Int): Boolean { + // A development build for T typically has SDK_INT = 30 (R) or SDK_INT = 31 (S), so SDK_INT + // alone cannot be used to check the SDK version. + // For recent SDKs that still have development builds used for testing, use SdkLevel utilities + // instead of SDK_INT. + return when (minExclusive) { + // TODO: use Build.VERSION_CODES.S when it is not CURRENT_DEVELOPMENT + 31 -> SdkLevel.isAtLeastT() + Build.VERSION_CODES.R -> SdkLevel.isAtLeastS() + // Development builds of SDK versions <= R are not used anymore + else -> Build.VERSION.SDK_INT > minExclusive + } +} + +private fun isDevSdkUpTo(maxInclusive: Int): Boolean { + return when (maxInclusive) { + // TODO: use Build.VERSION_CODES.S when it is not CURRENT_DEVELOPMENT + 31 -> !SdkLevel.isAtLeastT() + Build.VERSION_CODES.R -> !SdkLevel.isAtLeastS() + // Development builds of SDK versions <= R are not used anymore + else -> Build.VERSION.SDK_INT <= maxInclusive + } } /** From de6f90ddbdaba570332d13c5e8d03ae6aed4622e Mon Sep 17 00:00:00 2001 From: Taras Antoshchuk Date: Thu, 21 Jan 2021 12:44:30 +0100 Subject: [PATCH 252/777] Zero out the non-prefix bits in NetUtilsTest Bug: 186082280 Test: atest NetworkStaticLibTests:NetUtilsTest Change-Id: Ia6e1546b579fccc4fdf969031b389e64b8bb88c5 --- .../unit/src/android/net/util/NetUtilsTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java index 338d1c80fe..d523e14955 100644 --- a/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java +++ b/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java @@ -71,18 +71,18 @@ public final class NetUtilsTest { route = NetUtils.selectBestRoute(routes, v4_dest); assertEquals(null, route); - final RouteInfo v4_expected = new RouteInfo(new IpPrefix("75.208.8.10/24"), + final RouteInfo v4_expected = new RouteInfo(new IpPrefix("75.208.8.0/24"), V4_GATEWAY, "wlan0"); routes.add(v4_expected); - // "75.208.8.10/16" is not an expected result since it is not the longest prefix. - routes.add(new RouteInfo(new IpPrefix("75.208.8.10/16"), V4_GATEWAY, "wlan0")); - routes.add(new RouteInfo(new IpPrefix("75.208.7.32/24"), V4_GATEWAY, "wlan0")); + // "75.208.0.0/16" is not an expected result since it is not the longest prefix. + routes.add(new RouteInfo(new IpPrefix("75.208.0.0/16"), V4_GATEWAY, "wlan0")); + routes.add(new RouteInfo(new IpPrefix("75.208.7.0/24"), V4_GATEWAY, "wlan0")); final RouteInfo v6_expected = new RouteInfo(new IpPrefix("2001:db8:cafe::/64"), V6_GATEWAY, "wlan0"); routes.add(v6_expected); - // "2001:db8:cafe::123/32" is not an expected result since it is not the longest prefix. - routes.add(new RouteInfo(new IpPrefix("2001:db8:cafe::123/32"), V6_GATEWAY, "wlan0")); + // "2001:db8::/32" is not an expected result since it is not the longest prefix. + routes.add(new RouteInfo(new IpPrefix("2001:db8::/32"), V6_GATEWAY, "wlan0")); routes.add(new RouteInfo(new IpPrefix("2001:db8:beef::/64"), V6_GATEWAY, "wlan0")); // Verify expected v4 route is selected From a7d235a89ce871929db59431d7a35d1aad1e1ead Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 29 Sep 2021 12:19:44 +0800 Subject: [PATCH 253/777] Move netd AIDL to frameworks/lib/net Clean move system/netd/server/aidl_api/ and system/netd/server/binder/ $ diff -qr frameworks/libs/net/common/binder/netd/aidl_api/ system/netd/server/aidl_api/ $ diff -qr frameworks/libs/net/common/binder/netd/src/ system/netd/server/binder/ Only in system/netd/server/binder/: com Bug: 201488997 Test: atest netd_integration_test atest netd_unit_test Ignore-AOSP-First: the netd change(same topic) would not automerger from aosp. No-Typo-Check: this is a simple code move with no other changes. BYPASS_INCLUSIVE_LANGUAGE_REASON=this is a simple code move with no other changes and these files are frozen anyway Change-Id: Id5bb63794aff4025355c587b372c3ff5b1054da6 --- staticlibs/netd/Android.bp | 155 ++ .../netd/aidl_api/netd_aidl_interface/1/.hash | 1 + .../1/android/net/INetd.aidl | 132 ++ .../net/INetdUnsolicitedEventListener.aidl | 14 + .../net/InterfaceConfigurationParcel.aidl | 8 + .../1/android/net/TetherStatsParcel.aidl | 8 + .../1/android/net/UidRangeParcel.aidl | 5 + .../netd/aidl_api/netd_aidl_interface/2/.hash | 1 + .../2/android/net/INetd.aidl | 153 ++ .../net/INetdUnsolicitedEventListener.aidl | 31 + .../net/InterfaceConfigurationParcel.aidl | 25 + .../2/android/net/TetherStatsParcel.aidl | 25 + .../2/android/net/UidRangeParcel.aidl | 22 + .../netd/aidl_api/netd_aidl_interface/3/.hash | 1 + .../3/android/net/INetd.aidl | 161 ++ .../net/INetdUnsolicitedEventListener.aidl | 32 + .../net/InterfaceConfigurationParcel.aidl | 26 + .../3/android/net/MarkMaskParcel.aidl | 23 + .../3/android/net/RouteInfoParcel.aidl | 24 + .../3/android/net/TetherConfigParcel.aidl | 23 + .../android/net/TetherOffloadRuleParcel.aidl | 27 + .../3/android/net/TetherStatsParcel.aidl | 26 + .../3/android/net/UidRangeParcel.aidl | 23 + .../netd/aidl_api/netd_aidl_interface/4/.hash | 1 + .../4/android/net/INetd.aidl | 164 ++ .../net/INetdUnsolicitedEventListener.aidl | 32 + .../net/InterfaceConfigurationParcel.aidl | 26 + .../4/android/net/MarkMaskParcel.aidl | 23 + .../4/android/net/RouteInfoParcel.aidl | 24 + .../4/android/net/TetherConfigParcel.aidl | 23 + .../android/net/TetherOffloadRuleParcel.aidl | 28 + .../4/android/net/TetherStatsParcel.aidl | 27 + .../4/android/net/UidRangeParcel.aidl | 23 + .../netd/aidl_api/netd_aidl_interface/5/.hash | 1 + .../5/android/net/INetd.aidl | 167 ++ .../net/INetdUnsolicitedEventListener.aidl | 32 + .../net/InterfaceConfigurationParcel.aidl | 26 + .../5/android/net/MarkMaskParcel.aidl | 23 + .../5/android/net/RouteInfoParcel.aidl | 24 + .../5/android/net/TetherConfigParcel.aidl | 23 + .../android/net/TetherOffloadRuleParcel.aidl | 28 + .../5/android/net/TetherStatsParcel.aidl | 27 + .../5/android/net/UidRangeParcel.aidl | 24 + .../netd/aidl_api/netd_aidl_interface/6/.hash | 1 + .../6/android/net/INetd.aidl | 198 +++ .../net/INetdUnsolicitedEventListener.aidl | 48 + .../net/InterfaceConfigurationParcel.aidl | 42 + .../6/android/net/MarkMaskParcel.aidl | 39 + .../6/android/net/NativeNetworkConfig.aidl | 43 + .../6/android/net/NativeNetworkType.aidl | 39 + .../6/android/net/NativeVpnType.aidl | 41 + .../6/android/net/RouteInfoParcel.aidl | 40 + .../6/android/net/TetherConfigParcel.aidl | 39 + .../android/net/TetherOffloadRuleParcel.aidl | 44 + .../6/android/net/TetherStatsParcel.aidl | 43 + .../6/android/net/UidRangeParcel.aidl | 40 + .../netd/aidl_api/netd_aidl_interface/7/.hash | 1 + .../7/android/net/INetd.aidl | 200 +++ .../net/INetdUnsolicitedEventListener.aidl | 48 + .../net/InterfaceConfigurationParcel.aidl | 42 + .../7/android/net/MarkMaskParcel.aidl | 39 + .../7/android/net/NativeNetworkConfig.aidl | 43 + .../7/android/net/NativeNetworkType.aidl | 39 + .../7/android/net/NativeVpnType.aidl | 41 + .../7/android/net/RouteInfoParcel.aidl | 40 + .../7/android/net/TetherConfigParcel.aidl | 39 + .../android/net/TetherOffloadRuleParcel.aidl | 44 + .../7/android/net/TetherStatsParcel.aidl | 43 + .../7/android/net/UidRangeParcel.aidl | 40 + .../net/netd/aidl/NativeUidRangeConfig.aidl | 41 + .../current/android/net/INetd.aidl | 200 +++ .../net/INetdUnsolicitedEventListener.aidl | 48 + .../net/InterfaceConfigurationParcel.aidl | 42 + .../current/android/net/MarkMaskParcel.aidl | 39 + .../android/net/NativeNetworkConfig.aidl | 43 + .../android/net/NativeNetworkType.aidl | 39 + .../current/android/net/NativeVpnType.aidl | 41 + .../current/android/net/RouteInfoParcel.aidl | 40 + .../android/net/TetherConfigParcel.aidl | 39 + .../android/net/TetherOffloadRuleParcel.aidl | 44 + .../android/net/TetherStatsParcel.aidl | 43 + .../current/android/net/UidRangeParcel.aidl | 40 + .../net/netd/aidl/NativeUidRangeConfig.aidl | 41 + .../netd_event_listener_interface/1/.hash | 1 + .../net/metrics/INetdEventListener.aidl | 34 + .../net/metrics/INetdEventListener.aidl | 35 + staticlibs/netd/binder/android/net/INetd.aidl | 1380 +++++++++++++++++ .../net/INetdUnsolicitedEventListener.aidl | 145 ++ .../net/InterfaceConfigurationParcel.aidl | 33 + .../binder/android/net/MarkMaskParcel.aidl | 29 + .../android/net/NativeNetworkConfig.aidl | 52 + .../binder/android/net/NativeNetworkType.aidl | 30 + .../binder/android/net/NativeVpnType.aidl | 40 + .../binder/android/net/RouteInfoParcel.aidl | 28 + .../android/net/TetherConfigParcel.aidl | 32 + .../android/net/TetherOffloadRuleParcel.aidl | 45 + .../binder/android/net/TetherStatsParcel.aidl | 55 + .../binder/android/net/UidRangeParcel.aidl | 28 + .../net/metrics/INetdEventListener.aidl | 128 ++ .../net/netd/aidl/NativeUidRangeConfig.aidl | 41 + 100 files changed, 5884 insertions(+) create mode 100644 staticlibs/netd/Android.bp create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/1/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/2/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeVpnType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeVpnType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/netd/aidl/NativeUidRangeConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeVpnType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_event_listener_interface/1/.hash create mode 100644 staticlibs/netd/aidl_api/netd_event_listener_interface/1/android/net/metrics/INetdEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_event_listener_interface/current/android/net/metrics/INetdEventListener.aidl create mode 100644 staticlibs/netd/binder/android/net/INetd.aidl create mode 100644 staticlibs/netd/binder/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/binder/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/binder/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/binder/android/net/NativeNetworkConfig.aidl create mode 100644 staticlibs/netd/binder/android/net/NativeNetworkType.aidl create mode 100644 staticlibs/netd/binder/android/net/NativeVpnType.aidl create mode 100644 staticlibs/netd/binder/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/binder/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/binder/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/binder/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/binder/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/binder/android/net/metrics/INetdEventListener.aidl create mode 100644 staticlibs/netd/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp new file mode 100644 index 0000000000..c93c2fc485 --- /dev/null +++ b/staticlibs/netd/Android.bp @@ -0,0 +1,155 @@ +// Copyright (C) 2021 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. + +java_library { + name: "netd_aidl_interface-lateststable-java", + sdk_version: "system_current", + min_sdk_version: "29", + static_libs: [ + "netd_aidl_interface-V7-java", + ], + apex_available: [ + "//apex_available:platform", // used from services.net + "com.android.bluetooth.updatable", + "com.android.tethering", + "com.android.wifi", + ], +} + +cc_library_static { + name: "netd_event_listener_interface-lateststable-ndk", + whole_static_libs: [ + "netd_event_listener_interface-V1-ndk", + ], + apex_available: [ + "com.android.resolv", + ], + min_sdk_version: "29", +} + +cc_library_static { + name: "netd_aidl_interface-lateststable-ndk", + whole_static_libs: [ + "netd_aidl_interface-V7-ndk", + ], + apex_available: [ + "com.android.resolv", + ], + min_sdk_version: "29", +} + +cc_library_static { + name: "netd_aidl_interface-lateststable-cpp", + whole_static_libs: [ + "netd_aidl_interface-V7-cpp", + ], +} + +aidl_interface { + name: "netd_aidl_interface", + local_include_dir: "binder", + srcs: [ + "binder/android/net/INetd.aidl", + // AIDL interface that callers can implement to receive networking events from netd. + "binder/android/net/INetdUnsolicitedEventListener.aidl", + "binder/android/net/InterfaceConfigurationParcel.aidl", + "binder/android/net/MarkMaskParcel.aidl", + "binder/android/net/NativeNetworkConfig.aidl", + "binder/android/net/NativeNetworkType.aidl", + "binder/android/net/NativeVpnType.aidl", + "binder/android/net/RouteInfoParcel.aidl", + "binder/android/net/TetherConfigParcel.aidl", + "binder/android/net/TetherOffloadRuleParcel.aidl", + "binder/android/net/TetherStatsParcel.aidl", + "binder/android/net/UidRangeParcel.aidl", + // Add new AIDL classes in android.net.netd.aidl to consist with other network modules. + "binder/android/net/netd/aidl/**/*.aidl", + ], + backend: { + cpp: { + gen_log: true, + }, + java: { + // TODO: Remove apex_available and restrict visibility to only mainline modules that are + // either outside the system server or use jarjar to rename the generated AIDL classes. + apex_available: [ + "//apex_available:platform", // used from services.net + "com.android.bluetooth.updatable", + "com.android.tethering", + "com.android.wifi", + ], + // this is part of updatable modules(NetworkStack) which targets 29(Q) + min_sdk_version: "29", + }, + ndk: { + apex_available: [ + "//apex_available:platform", + ], + // This is necessary for the DnsResovler tests to run in Android Q. + // Soong would recognize this value and produce the Q compatible aidl library. + min_sdk_version: "29", + }, + }, + versions: [ + "1", + "2", + "3", + "4", + "5", + "6", + "7", + ], +} + +java_library { + name: "netd_event_listener_interface-lateststable-java", + sdk_version: "system_current", + min_sdk_version: "29", + static_libs: [ + "netd_event_listener_interface-V1-java", + ], + apex_available: [ + "//apex_available:platform", + "com.android.bluetooth.updatable", + "com.android.wifi", + "com.android.tethering", + ], +} + +aidl_interface { + name: "netd_event_listener_interface", + local_include_dir: "binder", + srcs: [ + "binder/android/net/metrics/INetdEventListener.aidl", + ], + versions: ["1"], + backend: { + ndk: { + apex_available: [ + "//apex_available:platform", + "com.android.resolv", + ], + min_sdk_version: "29", + }, + java: { + apex_available: [ + "//apex_available:platform", + "com.android.bluetooth.updatable", + "com.android.wifi", + "com.android.tethering", + ], + min_sdk_version: "29", + }, + }, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/1/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/1/.hash new file mode 100644 index 0000000000..d33e90387b --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/1/.hash @@ -0,0 +1 @@ +69c2ac134efbb31e9591d7e5c3640fb839e23bdb diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/INetd.aidl new file mode 100644 index 0000000000..664c643fb2 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/INetd.aidl @@ -0,0 +1,132 @@ +package android.net; +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + void networkCreatePhysical(int netId, int permission); + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..18631ffa1a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,14 @@ +package android.net; +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..93407dcb90 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,8 @@ +package android.net; +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..d1782bb0cf --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/TetherStatsParcel.aidl @@ -0,0 +1,8 @@ +package android.net; +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..d3bc7edfd0 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/UidRangeParcel.aidl @@ -0,0 +1,5 @@ +package android.net; +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/2/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/2/.hash new file mode 100644 index 0000000000..5fc5b2d7ed --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/2/.hash @@ -0,0 +1 @@ +e395d63302c47e7d2dac0d503045779029ff598b diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/INetd.aidl new file mode 100644 index 0000000000..0e2d5f4365 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/INetd.aidl @@ -0,0 +1,153 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not +// try to edit this file. It looks like you are doing that because you have +// modified an AIDL interface in a backward-incompatible way, e.g., deleting a +// function from an interface or a field from a parcelable and it broke the +// build. That breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + void networkCreatePhysical(int netId, int permission); + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..621f1cf865 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,31 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not +// try to edit this file. It looks like you are doing that because you have +// modified an AIDL interface in a backward-incompatible way, e.g., deleting a +// function from an interface or a field from a parcelable and it broke the +// build. That breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..18de61f32f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not +// try to edit this file. It looks like you are doing that because you have +// modified an AIDL interface in a backward-incompatible way, e.g., deleting a +// function from an interface or a field from a parcelable and it broke the +// build. That breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..c0ba67666a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/TetherStatsParcel.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not +// try to edit this file. It looks like you are doing that because you have +// modified an AIDL interface in a backward-incompatible way, e.g., deleting a +// function from an interface or a field from a parcelable and it broke the +// build. That breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..c2c35db2d3 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/UidRangeParcel.aidl @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not +// try to edit this file. It looks like you are doing that because you have +// modified an AIDL interface in a backward-incompatible way, e.g., deleting a +// function from an interface or a field from a parcelable and it broke the +// build. That breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/3/.hash new file mode 100644 index 0000000000..59cf70898d --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/.hash @@ -0,0 +1 @@ +e17c1f9b2068b539b22e3a4a447edea3c80aee4b diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/INetd.aidl new file mode 100644 index 0000000000..135b738508 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/INetd.aidl @@ -0,0 +1,161 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + void networkCreatePhysical(int netId, int permission); + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..4459363217 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,32 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..01e0f95541 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..62be838420 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/MarkMaskParcel.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5e0ee62a0f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/RouteInfoParcel.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..b13645450a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherConfigParcel.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..3abf0f89a3 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..71ffb9b964 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherStatsParcel.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..84ff4572dd --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/UidRangeParcel.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/4/.hash new file mode 100644 index 0000000000..0c3f810e67 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/.hash @@ -0,0 +1 @@ +63adaa5098e4d8621e90c5a84f7cb93505c79311 diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/INetd.aidl new file mode 100644 index 0000000000..47e2931d7c --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/INetd.aidl @@ -0,0 +1,164 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + void networkCreatePhysical(int netId, int permission); + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..4459363217 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,32 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..01e0f95541 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..62be838420 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/MarkMaskParcel.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5e0ee62a0f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/RouteInfoParcel.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..b13645450a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherConfigParcel.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..c9d845808e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,28 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..0b0960efc5 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherStatsParcel.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..84ff4572dd --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/UidRangeParcel.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/5/.hash new file mode 100644 index 0000000000..a6ced4538a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/.hash @@ -0,0 +1 @@ +d97c56dd789cee9eeb5cdcec43a99df0a01873a5 diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/INetd.aidl new file mode 100644 index 0000000000..b30748a3c8 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/INetd.aidl @@ -0,0 +1,167 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + void networkCreatePhysical(int netId, int permission); + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + const @JavaPassthrough(annotation="@Deprecated") int FIREWALL_WHITELIST = 0; + const int FIREWALL_ALLOWLIST = 0; + const @JavaPassthrough(annotation="@Deprecated") int FIREWALL_BLACKLIST = 1; + const int FIREWALL_DENYLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const int FIREWALL_CHAIN_RESTRICTED = 4; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..4459363217 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,32 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..01e0f95541 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..62be838420 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/MarkMaskParcel.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5e0ee62a0f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/RouteInfoParcel.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..b13645450a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherConfigParcel.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..c9d845808e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,28 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..0b0960efc5 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherStatsParcel.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..debc6be2d3 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/UidRangeParcel.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/6/.hash new file mode 100644 index 0000000000..f5acf5d1ee --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/.hash @@ -0,0 +1 @@ +b08451d9673b09cba84f1fd8740e1fdac64ff7be diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/INetd.aidl new file mode 100644 index 0000000000..a7952f28df --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/INetd.aidl @@ -0,0 +1,198 @@ +/** + * Copyright (c) 2016, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreatePhysical(int netId, int permission); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + void networkCreate(in android.net.NativeNetworkConfig config); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const int DUMMY_NET_ID = 51; + const int UNREACHABLE_NET_ID = 52; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + /** + * @deprecated use FIREWALL_ALLOWLIST. + */ + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_ALLOWLIST = 0; + /** + * @deprecated use FIREWALL_DENYLIST. + */ + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_DENYLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const int FIREWALL_CHAIN_RESTRICTED = 4; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..31775dfd11 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2018, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..1869d8d49e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..8ea20d118f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/MarkMaskParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkConfig.aidl new file mode 100644 index 0000000000..76562b294a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkConfig.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeNetworkConfig { + int netId; + android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL; + int permission; + boolean secure; + android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkType.aidl new file mode 100644 index 0000000000..06c8979d51 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkType.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeNetworkType { + PHYSICAL = 0, + VIRTUAL = 1, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeVpnType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeVpnType.aidl new file mode 100644 index 0000000000..8a8be83958 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeVpnType.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeVpnType { + SERVICE = 1, + PLATFORM = 2, + LEGACY = 3, + OEM = 4, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5ef95e67ca --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/RouteInfoParcel.aidl @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2020, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..7b39c22e4e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherConfigParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..983e9860ea --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..5f1b722690 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherStatsParcel.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..72e987a2af --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/UidRangeParcel.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/7/.hash new file mode 100644 index 0000000000..cad59dfd74 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/.hash @@ -0,0 +1 @@ +850353de5d19a0dd718f8fd20791f0532e6a34c7 diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/INetd.aidl new file mode 100644 index 0000000000..ec03d86b6c --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/INetd.aidl @@ -0,0 +1,200 @@ +/** + * Copyright (c) 2016, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreatePhysical(int netId, int permission); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + void networkCreate(in android.net.NativeNetworkConfig config); + void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const int DUMMY_NET_ID = 51; + const int UNREACHABLE_NET_ID = 52; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + /** + * @deprecated use FIREWALL_ALLOWLIST. + */ + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_ALLOWLIST = 0; + /** + * @deprecated use FIREWALL_DENYLIST. + */ + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_DENYLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const int FIREWALL_CHAIN_RESTRICTED = 4; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..31775dfd11 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2018, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..1869d8d49e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..8ea20d118f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/MarkMaskParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkConfig.aidl new file mode 100644 index 0000000000..76562b294a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkConfig.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeNetworkConfig { + int netId; + android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL; + int permission; + boolean secure; + android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkType.aidl new file mode 100644 index 0000000000..06c8979d51 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkType.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeNetworkType { + PHYSICAL = 0, + VIRTUAL = 1, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeVpnType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeVpnType.aidl new file mode 100644 index 0000000000..8a8be83958 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeVpnType.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeVpnType { + SERVICE = 1, + PLATFORM = 2, + LEGACY = 3, + OEM = 4, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5ef95e67ca --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/RouteInfoParcel.aidl @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2020, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..7b39c22e4e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherConfigParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..983e9860ea --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..5f1b722690 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherStatsParcel.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..72e987a2af --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/UidRangeParcel.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/netd/aidl/NativeUidRangeConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/netd/aidl/NativeUidRangeConfig.aidl new file mode 100644 index 0000000000..9bb679f1c1 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/netd/aidl/NativeUidRangeConfig.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.netd.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeUidRangeConfig { + int netId; + android.net.UidRangeParcel[] uidRanges; + int subPriority; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl new file mode 100644 index 0000000000..ec03d86b6c --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl @@ -0,0 +1,200 @@ +/** + * Copyright (c) 2016, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreatePhysical(int netId, int permission); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + void networkCreate(in android.net.NativeNetworkConfig config); + void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const int DUMMY_NET_ID = 51; + const int UNREACHABLE_NET_ID = 52; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + /** + * @deprecated use FIREWALL_ALLOWLIST. + */ + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_ALLOWLIST = 0; + /** + * @deprecated use FIREWALL_DENYLIST. + */ + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_DENYLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const int FIREWALL_CHAIN_RESTRICTED = 4; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..31775dfd11 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2018, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..1869d8d49e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..8ea20d118f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl new file mode 100644 index 0000000000..76562b294a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeNetworkConfig { + int netId; + android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL; + int permission; + boolean secure; + android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl new file mode 100644 index 0000000000..06c8979d51 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeNetworkType { + PHYSICAL = 0, + VIRTUAL = 1, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeVpnType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeVpnType.aidl new file mode 100644 index 0000000000..8a8be83958 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeVpnType.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeVpnType { + SERVICE = 1, + PLATFORM = 2, + LEGACY = 3, + OEM = 4, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5ef95e67ca --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2020, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..7b39c22e4e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..983e9860ea --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..5f1b722690 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..72e987a2af --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl new file mode 100644 index 0000000000..9bb679f1c1 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.netd.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeUidRangeConfig { + int netId; + android.net.UidRangeParcel[] uidRanges; + int subPriority; +} diff --git a/staticlibs/netd/aidl_api/netd_event_listener_interface/1/.hash b/staticlibs/netd/aidl_api/netd_event_listener_interface/1/.hash new file mode 100644 index 0000000000..f39f730fe5 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_event_listener_interface/1/.hash @@ -0,0 +1 @@ +8e27594d285ca7c567d87e8cf74766c27647e02b diff --git a/staticlibs/netd/aidl_api/netd_event_listener_interface/1/android/net/metrics/INetdEventListener.aidl b/staticlibs/netd/aidl_api/netd_event_listener_interface/1/android/net/metrics/INetdEventListener.aidl new file mode 100644 index 0000000000..9898a67403 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_event_listener_interface/1/android/net/metrics/INetdEventListener.aidl @@ -0,0 +1,34 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not +// try to edit this file. It looks like you are doing that because you have +// modified an AIDL interface in a backward-incompatible way, e.g., deleting a +// function from an interface or a field from a parcelable and it broke the +// build. That breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.metrics; +interface INetdEventListener { + oneway void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs, @utf8InCpp String hostname, in @utf8InCpp String[] ipAddresses, int ipAddressesCount, int uid); + oneway void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname, boolean validated); + oneway void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port, int uid); + oneway void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader, in byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs); + oneway void onTcpSocketStatsEvent(in int[] networkIds, in int[] sentPackets, in int[] lostPackets, in int[] rttUs, in int[] sentAckDiffMs); + oneway void onNat64PrefixEvent(int netId, boolean added, @utf8InCpp String prefixString, int prefixLength); + const int EVENT_GETADDRINFO = 1; + const int EVENT_GETHOSTBYNAME = 2; + const int EVENT_GETHOSTBYADDR = 3; + const int EVENT_RES_NSEND = 4; + const int REPORTING_LEVEL_NONE = 0; + const int REPORTING_LEVEL_METRICS = 1; + const int REPORTING_LEVEL_FULL = 2; + const int DNS_REPORTED_IP_ADDRESSES_LIMIT = 10; +} diff --git a/staticlibs/netd/aidl_api/netd_event_listener_interface/current/android/net/metrics/INetdEventListener.aidl b/staticlibs/netd/aidl_api/netd_event_listener_interface/current/android/net/metrics/INetdEventListener.aidl new file mode 100644 index 0000000000..d71c3f29b5 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_event_listener_interface/current/android/net/metrics/INetdEventListener.aidl @@ -0,0 +1,35 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.metrics; +/* @hide */ +interface INetdEventListener { + oneway void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs, @utf8InCpp String hostname, in @utf8InCpp String[] ipAddresses, int ipAddressesCount, int uid); + oneway void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname, boolean validated); + oneway void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port, int uid); + oneway void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader, in byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs); + oneway void onTcpSocketStatsEvent(in int[] networkIds, in int[] sentPackets, in int[] lostPackets, in int[] rttUs, in int[] sentAckDiffMs); + oneway void onNat64PrefixEvent(int netId, boolean added, @utf8InCpp String prefixString, int prefixLength); + const int EVENT_GETADDRINFO = 1; + const int EVENT_GETHOSTBYNAME = 2; + const int EVENT_GETHOSTBYADDR = 3; + const int EVENT_RES_NSEND = 4; + const int REPORTING_LEVEL_NONE = 0; + const int REPORTING_LEVEL_METRICS = 1; + const int REPORTING_LEVEL_FULL = 2; + const int DNS_REPORTED_IP_ADDRESSES_LIMIT = 10; +} diff --git a/staticlibs/netd/binder/android/net/INetd.aidl b/staticlibs/netd/binder/android/net/INetd.aidl new file mode 100644 index 0000000000..d6398c1222 --- /dev/null +++ b/staticlibs/netd/binder/android/net/INetd.aidl @@ -0,0 +1,1380 @@ +/** + * Copyright (c) 2016, 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 android.net.INetdUnsolicitedEventListener; +import android.net.InterfaceConfigurationParcel; +import android.net.MarkMaskParcel; +import android.net.NativeNetworkConfig; +import android.net.RouteInfoParcel; +import android.net.TetherConfigParcel; +import android.net.TetherOffloadRuleParcel; +import android.net.TetherStatsParcel; +import android.net.UidRangeParcel; +import android.net.netd.aidl.NativeUidRangeConfig; + +/** {@hide} */ +interface INetd { + /** + * Returns true if the service is responding. + */ + boolean isAlive(); + + /** + * Replaces the contents of the specified UID-based firewall chain. + * + * The chain may be an allowlist chain or a denylist chain. A denylist chain contains DROP + * rules for the specified UIDs and a RETURN rule at the end. An allowlist chain contains RETURN + * rules for the system UID range (0 to {@code UID_APP} - 1), RETURN rules for for the specified + * UIDs, and a DROP rule at the end. The chain will be created if it does not exist. + * + * @param chainName The name of the chain to replace. + * @param isAllowlist Whether this is an allowlist or denylist chain. + * @param uids The list of UIDs to allow/deny. + * @return true if the chain was successfully replaced, false otherwise. + */ + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, + boolean isAllowlist, + in int[] uids); + + /** + * Enables or disables data saver mode on costly network interfaces. + * + * - When disabled, all packets to/from apps in the penalty box chain are rejected on costly + * interfaces. Traffic to/from other apps or on other network interfaces is allowed. + * - When enabled, only apps that are in the happy box chain and not in the penalty box chain + * are allowed network connectivity on costly interfaces. All other packets on these + * interfaces are rejected. The happy box chain always contains all system UIDs; to disallow + * traffic from system UIDs, place them in the penalty box chain. + * + * By default, data saver mode is disabled. This command has no effect but might still return an + * error) if {@code enable} is the same as the current value. + * + * @param enable whether to enable or disable data saver mode. + * @return true if the if the operation was successful, false otherwise. + */ + boolean bandwidthEnableDataSaver(boolean enable); + + /** + * Creates a physical network (i.e., one containing physical interfaces. + * @deprecated use networkCreate() instead. + * + * @param netId the networkId to create. + * @param permission the permission necessary to use the network. Must be one of + * PERMISSION_NONE/PERMISSION_NETWORK/PERMISSION_SYSTEM. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkCreatePhysical(int netId, int permission); + + /** + * Creates a VPN network. + * @deprecated use networkCreate() instead. + * + * @param netId the network to create. + * @param secure whether unprivileged apps are allowed to bypass the VPN. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkCreateVpn(int netId, boolean secure); + + /** + * Destroys a network. Any interfaces added to the network are removed, and the network ceases + * to be the default network. + * + * @param netId the network to destroy. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkDestroy(int netId); + + /** + * Adds an interface to a network. The interface must not be assigned to any network, including + * the specified network. + * + * @param netId the network to add the interface to. + * @param interface the name of the interface to add. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkAddInterface(int netId, in @utf8InCpp String iface); + + /** + * Adds an interface to a network. The interface must be assigned to the specified network. + * + * @param netId the network to remove the interface from. + * @param interface the name of the interface to remove. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + + /** + * Adds the specified UID ranges to the specified network. The network can be physical or + * virtual. Traffic from the UID ranges will be routed to the network by default. + * + * @param netId the network ID of the network to add the ranges to. + * @param uidRanges a set of non-overlapping ranges of UIDs to add. These exact ranges + * must not overlap with existing ranges assigned to this network. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkAddUidRanges(int netId, in UidRangeParcel[] uidRanges); + + /** + * Remove the specified UID ranges from the specified network. The network can be physical or + * virtual. Traffic from the UID ranges will no longer be routed to the network by default. + * + * @param netId the network ID of the network to remove the ranges from. + * @param uidRanges a set of non-overlapping ranges of UIDs to remove. These exact ranges + * must already be assigned to this network. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkRemoveUidRanges(int netId, in UidRangeParcel[] uidRanges); + + /** + * Adds or removes one rule for each supplied UID range to prohibit all network activity outside + * of secure VPN. + * + * When a UID is covered by one of these rules, traffic sent through any socket that is not + * protected or explicitly overriden by the system will be rejected. The kernel will respond + * with an ICMP prohibit message. + * + * Initially, there are no such rules. Any rules that are added will only last until the next + * restart of netd or the device. + * + * @param add {@code true} if the specified UID ranges should be denied access to any network + * which is not secure VPN by adding rules, {@code false} to remove existing rules. + * @param uidRanges a set of non-overlapping, contiguous ranges of UIDs to which to apply or + * remove this restriction. + *

Added rules should not overlap with existing rules. Likewise, removed rules should + * each correspond to an existing rule. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkRejectNonSecureVpn(boolean add, in UidRangeParcel[] uidRanges); + + /** + * Administratively closes sockets belonging to the specified UIDs. + */ + void socketDestroy(in UidRangeParcel[] uidRanges, in int[] exemptUids); + + /** + * Instruct the tethering DNS server to reevaluated serving interfaces. + * This is needed to for the DNS server to observe changes in the set + * of potential listening IP addresses. (Listening on wildcard addresses + * can turn the device into an open resolver; b/7530468) + * + * TODO: Return something richer than just a boolean. + */ + boolean tetherApplyDnsInterfaces(); + + /** + * Return tethering statistics. + * + * @return an array of TetherStatsParcel, where each entry contains the upstream interface + * name and its tethering statistics since netd startup. + * There will only ever be one entry for a given interface. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + TetherStatsParcel[] tetherGetStats(); + + /** + * Add/Remove and IP address from an interface. + * + * @param ifName the interface name + * @param addrString the IP address to add/remove as a string literal + * @param prefixLength the prefix length associated with this IP address + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, + int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, + int prefixLength); + + /** + * Set and get /proc/sys/net interface configuration parameters. + * + * @param ipversion One of IPV4/IPV6 integers, indicating the desired IP version directory. + * @param which One of CONF/NEIGH integers, indicating the desired parameter category directory. + * @param ifname The interface name portion of the path; may also be "all" or "default". + * @param parameter The parameter name portion of the path. + * @param value The value string to be written into the assembled path. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, + in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, + in @utf8InCpp String parameter, in @utf8InCpp String value); + + /** + * Sets owner of socket ParcelFileDescriptor to the new UID, checking to ensure that the caller's + * uid is that of the old owner's, and that this is a UDP-encap socket + * + * @param ParcelFileDescriptor socket Socket file descriptor + * @param int newUid UID of the new socket fd owner + */ + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + + /** + * Reserve an SPI from the kernel + * + * @param transformId a unique identifier for allocated resources + * @param sourceAddress InetAddress as string for the sending endpoint + * @param destinationAddress InetAddress as string for the receiving endpoint + * @param spi a requested 32-bit unique ID or 0 to request random allocation + * @return the SPI that was allocated or 0 if failed + */ + int ipSecAllocateSpi( + int transformId, + in @utf8InCpp String sourceAddress, + in @utf8InCpp String destinationAddress, + int spi); + + /** + * Create an IpSec Security Association describing how ip(v6) traffic will be encrypted + * or decrypted. + * + * @param transformId a unique identifier for allocated resources + * @param mode either Transport or Tunnel mode + * @param sourceAddress InetAddress as string for the sending endpoint + * @param destinationAddress InetAddress as string for the receiving endpoint + * @param underlyingNetId the netId of the network to which the SA is applied. Only accepted for + * tunnel mode SAs. + * @param spi a 32-bit unique ID allocated to the user + * @param markValue a 32-bit unique ID chosen by the user + * @param markMask a 32-bit mask chosen by the user + * @param authAlgo a string identifying the authentication algorithm to be used + * @param authKey a byte array containing the authentication key + * @param authTruncBits the truncation length of the MAC produced by the authentication algorithm + * @param cryptAlgo a string identifying the encryption algorithm to be used + * @param cryptKey a byte arrray containing the encryption key + * @param cryptTruncBits unused parameter + * @param aeadAlgo a string identifying the authenticated encryption algorithm to be used + * @param aeadKey a byte arrray containing the key to be used in authenticated encryption + * @param aeadIcvBits the truncation length of the ICV produced by the authentication algorithm + * (similar to authTruncBits in function) + * @param encapType encapsulation type used (if any) for the udp encap socket + * @param encapLocalPort the port number on the host to be used in encap packets + * @param encapRemotePort the port number of the remote to be used for encap packets + * @param interfaceId the identifier for the IPsec tunnel interface. + * Only accepted for tunnel mode SAs. + */ + void ipSecAddSecurityAssociation( + int transformId, + int mode, + in @utf8InCpp String sourceAddress, + in @utf8InCpp String destinationAddress, + int underlyingNetId, + int spi, + int markValue, + int markMask, + in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, + in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, + in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, + int encapType, + int encapLocalPort, + int encapRemotePort, + int interfaceId); + + /** + * Delete a previously created security association identified by the provided parameters + * + * @param transformId a unique identifier for allocated resources + * @param sourceAddress InetAddress as string for the sending endpoint + * @param destinationAddress InetAddress as string for the receiving endpoint + * @param spi a requested 32-bit unique ID allocated to the user + * @param markValue a 32-bit unique ID chosen by the user + * @param markMask a 32-bit mask chosen by the user + * @param interfaceId the identifier for the IPsec tunnel interface. + */ + void ipSecDeleteSecurityAssociation( + int transformId, + in @utf8InCpp String sourceAddress, + in @utf8InCpp String destinationAddress, + int spi, + int markValue, + int markMask, + int interfaceId); + + /** + * Apply a previously created SA to a specified socket, starting IPsec on that socket + * + * @param socket a user-provided socket that will have IPsec applied + * @param transformId a unique identifier for allocated resources + * @param direction DIRECTION_IN or DIRECTION_OUT + * @param sourceAddress InetAddress as string for the sending endpoint + * @param destinationAddress InetAddress as string for the receiving endpoint + * @param spi a 32-bit unique ID allocated to the user (socket owner) + */ + void ipSecApplyTransportModeTransform( + in ParcelFileDescriptor socket, + int transformId, + int direction, + in @utf8InCpp String sourceAddress, + in @utf8InCpp String destinationAddress, + int spi); + + /** + * Remove an IPsec SA from a given socket. This will allow unencrypted traffic to flow + * on that socket if a transform had been previously applied. + * + * @param socket a user-provided socket from which to remove any IPsec configuration + */ + void ipSecRemoveTransportModeTransform( + in ParcelFileDescriptor socket); + + /** + * Adds an IPsec global policy. + * + * @param transformId a unique identifier for allocated resources + * @param selAddrFamily the address family identifier for the selector + * @param direction DIRECTION_IN or DIRECTION_OUT + * @param tmplSrcAddress InetAddress as string for the sending endpoint + * @param tmplDstAddress InetAddress as string for the receiving endpoint + * @param spi a 32-bit unique ID allocated to the user + * @param markValue a 32-bit unique ID chosen by the user + * @param markMask a 32-bit mask chosen by the user + * @param interfaceId the identifier for the IPsec tunnel interface. + */ + void ipSecAddSecurityPolicy( + int transformId, + int selAddrFamily, + int direction, + in @utf8InCpp String tmplSrcAddress, + in @utf8InCpp String tmplDstAddress, + int spi, + int markValue, + int markMask, + int interfaceId); + + /** + * Updates an IPsec global policy. + * + * @param transformId a unique identifier for allocated resources + * @param selAddrFamily the address family identifier for the selector + * @param direction DIRECTION_IN or DIRECTION_OUT + * @param tmplSrcAddress InetAddress as string for the sending endpoint + * @param tmplDstAddress InetAddress as string for the receiving endpoint + * @param spi a 32-bit unique ID allocated to the user + * @param markValue a 32-bit unique ID chosen by the user + * @param markMask a 32-bit mask chosen by the user + * @param interfaceId the identifier for the IPsec tunnel interface. + */ + void ipSecUpdateSecurityPolicy( + int transformId, + int selAddrFamily, + int direction, + in @utf8InCpp String tmplSrcAddress, + in @utf8InCpp String tmplDstAddress, + int spi, + int markValue, + int markMask, + int interfaceId); + + /** + * Deletes an IPsec global policy. + * + * Deletion of global policies does not do any matching based on the templates, thus + * template source/destination addresses are not needed (as opposed to add/update). + * + * @param transformId a unique identifier for allocated resources + * @param selAddrFamily the address family identifier for the selector + * @param direction DIRECTION_IN or DIRECTION_OUT + * @param markValue a 32-bit unique ID chosen by the user + * @param markMask a 32-bit mask chosen by the user + * @param interfaceId the identifier for the IPsec tunnel interface. + */ + void ipSecDeleteSecurityPolicy( + int transformId, + int selAddrFamily, + int direction, + int markValue, + int markMask, + int interfaceId); + + // This could not be declared as @uft8InCpp; thus, when used in native code it must be + // converted from a UTF-16 string to an ASCII string. + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + + /** + * Add a IPsec Tunnel Interface. + * + * @param devName a unique identifier that represents the name of the device + * @param localAddress InetAddress as string for the local endpoint + * @param remoteAddress InetAddress as string for the remote endpoint + * @param iKey, to match Policies and SAs for input packets. + * @param oKey, to match Policies and SAs for output packets. + * @param interfaceId the identifier for the IPsec tunnel interface. + */ + void ipSecAddTunnelInterface( + in @utf8InCpp String deviceName, + in @utf8InCpp String localAddress, + in @utf8InCpp String remoteAddress, + int iKey, + int oKey, + int interfaceId); + + /** + * Update a IPsec Tunnel Interface. + * + * @param devName a unique identifier that represents the name of the device + * @param localAddress InetAddress as string for the local endpoint + * @param remoteAddress InetAddress as string for the remote endpoint + * @param iKey, to match Policies and SAs for input packets. + * @param oKey, to match Policies and SAs for output packets. + * @param interfaceId the identifier for the IPsec tunnel interface. + */ + void ipSecUpdateTunnelInterface( + in @utf8InCpp String deviceName, + in @utf8InCpp String localAddress, + in @utf8InCpp String remoteAddress, + int iKey, + int oKey, + int interfaceId); + + /** + * Removes a IPsec Tunnel Interface. + * + * @param devName a unique identifier that represents the name of the device + */ + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + + /** + * Request notification of wakeup packets arriving on an interface. Notifications will be + * delivered to INetdEventListener.onWakeupEvent(). + * + * @param ifName the interface + * @param prefix arbitrary string used to identify wakeup sources in onWakeupEvent + */ + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + + /** + * Stop notification of wakeup packets arriving on an interface. + * + * @param ifName the interface + * @param prefix arbitrary string used to identify wakeup sources in onWakeupEvent + */ + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + /** + * Set IPv6 address generation mode. IPv6 should be disabled before changing mode. + * + * @param mode SLAAC address generation mechanism to use + */ + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + + /** + * Add idletimer for specific interface + * + * @param ifName Name of target interface + * @param timeout The time in seconds that will trigger idletimer + * @param classLabel The unique identifier for this idletimer + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void idletimerAddInterface( + in @utf8InCpp String ifName, + int timeout, + in @utf8InCpp String classLabel); + + /** + * Remove idletimer for specific interface + * + * @param ifName Name of target interface + * @param timeout The time in seconds that will trigger idletimer + * @param classLabel The unique identifier for this idletimer + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void idletimerRemoveInterface( + in @utf8InCpp String ifName, + int timeout, + in @utf8InCpp String classLabel); + + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + + /** + * Offers to detect sockets sending data not wrapped inside a layer of SSL/TLS encryption. + * + * @param uid Uid of the app + * @param policyPenalty The penalty policy of the app + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void strictUidCleartextPenalty(int uid, int policyPenalty); + + /** + * Start clatd + * + * @param ifName interface name to start clatd + * @param nat64Prefix the NAT64 prefix, e.g., "2001:db8:64::/96". + * @return a string, the IPv6 address that will be used for 464xlat. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + + /** + * Stop clatd + * + * @param ifName interface name to stop clatd + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void clatdStop(in @utf8InCpp String ifName); + + /** + * Get status of IP forwarding + * + * @return true if IP forwarding is enabled, false otherwise. + */ + boolean ipfwdEnabled(); + + /** + * Get requester list of IP forwarding + * + * @return An array of strings containing requester list of IP forwarding + */ + @utf8InCpp String[] ipfwdGetRequesterList(); + + /** + * Enable IP forwarding for specific requester + * + * @param requester requester name to enable IP forwarding. It is a unique name which will be + * stored in Netd to make sure if any requester needs IP forwarding. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void ipfwdEnableForwarding(in @utf8InCpp String requester); + + /** + * Disable IP forwarding for specific requester + * + * @param requester requester name to disable IP forwarding. This name should match the + * names which are set by ipfwdEnableForwarding. + * IP forwarding would be disabled if it is the last requester. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void ipfwdDisableForwarding(in @utf8InCpp String requester); + + /** + * Add forwarding ip rule + * + * @param fromIface interface name to add forwarding ip rule + * @param toIface interface name to add forwarding ip rule + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + + /** + * Remove forwarding ip rule + * + * @param fromIface interface name to remove forwarding ip rule + * @param toIface interface name to remove forwarding ip rule + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + + /** + * Set quota for interface + * + * @param ifName Name of target interface + * @param bytes Quota value in bytes + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + + /** + * Remove quota for interface + * + * @param ifName Name of target interface + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + + /** + * Set alert for interface + * + * @param ifName Name of target interface + * @param bytes Alert value in bytes + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + + /** + * Remove alert for interface + * + * @param ifName Name of target interface + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + + /** + * Set global alert + * + * @param bytes Alert value in bytes + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthSetGlobalAlert(long bytes); + + /** + * Add naughty app bandwidth rule for specific app + * + * @param uid uid of target app + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthAddNaughtyApp(int uid); + + /** + * Remove naughty app bandwidth rule for specific app + * + * @param uid uid of target app + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthRemoveNaughtyApp(int uid); + + /** + * Add nice app bandwidth rule for specific app + * + * @param uid uid of target app + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthAddNiceApp(int uid); + + /** + * Remove nice app bandwidth rule for specific app + * + * @param uid uid of target app + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthRemoveNiceApp(int uid); + + /** + * Start tethering + * + * @param dhcpRanges dhcp ranges to set. + * dhcpRanges might contain many addresss {addr1, addr2, aadr3, addr4...} + * Netd splits them into ranges: addr1-addr2, addr3-addr4, etc. + * An odd number of addrs will fail. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherStart(in @utf8InCpp String[] dhcpRanges); + + /** + * Stop tethering + * + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherStop(); + + /** + * Get status of tethering + * + * @return true if tethering is enabled, false otherwise. + */ + boolean tetherIsEnabled(); + + /** + * Setup interface for tethering + * + * @param ifName interface name to add + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherInterfaceAdd(in @utf8InCpp String ifName); + + /** + * Reset interface for tethering + * + * @param ifName interface name to remove + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherInterfaceRemove(in @utf8InCpp String ifName); + + /** + * Get the interface list which is stored in netd + * The list contains the interfaces managed by tetherInterfaceAdd/tetherInterfaceRemove + * + * @return An array of strings containing interface list result + */ + @utf8InCpp String[] tetherInterfaceList(); + + /** + * Set DNS forwarder server + * + * @param netId the upstream network to forward DNS queries to + * @param dnsAddrs DNS server address to set + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + + /** + * Return the DNS list set by tetherDnsSet + * + * @return An array of strings containing the list of DNS servers + */ + @utf8InCpp String[] tetherDnsList(); + + const int LOCAL_NET_ID = 99; + + /** + * Constant net ID for the "dummy" network. + * + * The dummy network is used to blackhole or reject traffic. Any attempt to use it will + * either drop the packets or fail with ENETUNREACH. + */ + const int DUMMY_NET_ID = 51; + + /** + * Constant net ID for the "unreachable" network. + * + * The unreachable network is used to reject traffic. Any attempt to use it will fail + * with ENETUNREACH. + */ + const int UNREACHABLE_NET_ID = 52; + + // Route does not specify a next hop + const String NEXTHOP_NONE = ""; + // Route next hop is unreachable + const String NEXTHOP_UNREACHABLE = "unreachable"; + // Route next hop is throw + const String NEXTHOP_THROW = "throw"; + + /** + * Add a route for specific network + * + * @param netId the network to add the route to + * @param ifName the name of interface of the route. + * This interface should be assigned to the netID. + * @param destination the destination of the route + * @param nextHop The route's next hop address, + * or it could be either NEXTHOP_NONE, NEXTHOP_UNREACHABLE, NEXTHOP_THROW. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkAddRoute( + int netId, + in @utf8InCpp String ifName, + in @utf8InCpp String destination, + in @utf8InCpp String nextHop); + + /** + * Remove a route for specific network + * + * @param netId the network to remove the route from + * @param ifName the name of interface of the route. + * This interface should be assigned to the netID. + * @param destination the destination of the route + * @param nextHop The route's next hop address, + * or it could be either NEXTHOP_NONE, NEXTHOP_UNREACHABLE, NEXTHOP_THROW. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkRemoveRoute( + int netId, + in @utf8InCpp String ifName, + in @utf8InCpp String destination, + in @utf8InCpp String nextHop); + + /** + * Add a route to legacy routing table for specific network + * + * @param netId the network to add the route to + * @param ifName the name of interface of the route. + * This interface should be assigned to the netID. + * @param destination the destination of the route + * @param nextHop The route's next hop address, + * or it could be either NEXTHOP_NONE, NEXTHOP_UNREACHABLE, NEXTHOP_THROW. + * @param uid uid of the user + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkAddLegacyRoute( + int netId, + in @utf8InCpp String ifName, + in @utf8InCpp String destination, + in @utf8InCpp String nextHop, + int uid); + + /** + * Remove a route from legacy routing table for specific network + * + * @param netId the network to remove the route from + * @param ifName the name of interface of the route. + * This interface should be assigned to the netID. + * @param destination the destination of the route + * @param nextHop The route's next hop address, + * or it could be either NEXTHOP_NONE, NEXTHOP_UNREACHABLE, NEXTHOP_THROW. + * @param uid uid of the user + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkRemoveLegacyRoute( + int netId, + in @utf8InCpp String ifName, + in @utf8InCpp String destination, + in @utf8InCpp String nextHop, + int uid); + + /** + * Get default network + * + * @return netId of default network + */ + int networkGetDefault(); + + /** + * Set network as default network + * + * @param netId the network to set as the default + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkSetDefault(int netId); + + /** + * Clear default network + * + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkClearDefault(); + + /** + * PERMISSION_NONE is used for regular networks and apps. TODO: use PERMISSION_INTERNET + * for this instead, and use PERMISSION_NONE to indicate no network permissions at all. + */ + const int PERMISSION_NONE = 0; + + /** + * PERMISSION_NETWORK represents the CHANGE_NETWORK_STATE permission. + */ + const int PERMISSION_NETWORK = 1; + + /** + * PERMISSION_SYSTEM represents the ability to use restricted networks. This is mostly + * equivalent to the CONNECTIVITY_USE_RESTRICTED_NETWORKS permission. + */ + const int PERMISSION_SYSTEM = 2; + + /** + * NO_PERMISSIONS indicates that this app is installed and doesn't have either + * PERMISSION_INTERNET or PERMISSION_UPDATE_DEVICE_STATS. + * TODO: use PERMISSION_NONE to represent this case + */ + const int NO_PERMISSIONS = 0; + + /** + * PERMISSION_INTERNET indicates that the app can create AF_INET and AF_INET6 sockets + */ + const int PERMISSION_INTERNET = 4; + + /** + * PERMISSION_UPDATE_DEVICE_STATS is used for system UIDs and privileged apps + * that have the UPDATE_DEVICE_STATS permission + */ + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + + /** + * PERMISSION_UNINSTALLED is used when an app is uninstalled from the device. All internet + * related permissions need to be cleaned + */ + const int PERMISSION_UNINSTALLED = -1; + + + /** + * Sets the permission required to access a specific network. + * + * @param netId the network to set + * @param permission network permission to use + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkSetPermissionForNetwork(int netId, int permission); + + /** + * Assigns network access permissions to the specified users. + * + * @param permission network permission to use + * @param uids uid of users to set permission + */ + void networkSetPermissionForUser(int permission, in int[] uids); + + /** + * Clears network access permissions for the specified users. + * + * @param uids uid of users to clear permission + */ + void networkClearPermissionForUser(in int[] uids); + + /** + * Assigns android.permission.INTERNET and/or android.permission.UPDATE_DEVICE_STATS to the uids + * specified. Or remove all permissions from the uids. + * + * @param permission The permission to grant, it could be either PERMISSION_INTERNET and/or + * PERMISSION_UPDATE_DEVICE_STATS. If the permission is NO_PERMISSIONS, then + * revoke all permissions for the uids. + * @param uids uid of users to grant permission + */ + void trafficSetNetPermForUids(int permission, in int[] uids); + + /** + * Gives the specified user permission to protect sockets from VPNs. + * Typically used by VPN apps themselves, to ensure that the sockets + * they use to communicate with the VPN server aren't routed through + * the VPN network. + * + * @param uid uid of user to set + */ + void networkSetProtectAllow(int uid); + + /** + * Removes the permission to protect sockets from VPN. + * + * @param uid uid of user to set + */ + void networkSetProtectDeny(int uid); + + /** + * Get the status of network protect for user + * + * @param uids uid of user + * @return true if the user can protect sockets from VPN, false otherwise. + */ + boolean networkCanProtect(int uid); + + /** Only allows packets from specific UID/Interface. + @deprecated use FIREWALL_ALLOWLIST. */ + const int FIREWALL_WHITELIST = 0; + + /** Only allows packets from specific UID/Interface. */ + const int FIREWALL_ALLOWLIST = 0; + + /** Blocks packets from specific UID/Interface. + @deprecated use FIREWALL_DENYLIST. */ + const int FIREWALL_BLACKLIST = 1; + + /** Blocks packets from specific UID/Interface. */ + const int FIREWALL_DENYLIST = 1; + + /** + * Set type of firewall + * Type allowlist only allows packets from specific UID/Interface + * Type denylist blocks packets from specific UID/Interface + * + * @param firewalltype type of firewall, either FIREWALL_ALLOWLIST or FIREWALL_DENYLIST + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void firewallSetFirewallType(int firewalltype); + + // Specify allow Rule which allows packets + const int FIREWALL_RULE_ALLOW = 1; + // Specify deny Rule which drops packets + const int FIREWALL_RULE_DENY = 2; + + // No specific chain is chosen, use general firewall chain(fw_input, fw_output) + const int FIREWALL_CHAIN_NONE = 0; + // Specify DOZABLE chain(fw_dozable) which is used in dozable mode + const int FIREWALL_CHAIN_DOZABLE = 1; + // Specify STANDBY chain(fw_standby) which is used in standby mode + const int FIREWALL_CHAIN_STANDBY = 2; + // Specify POWERSAVE chain(fw_powersave) which is used in power save mode + const int FIREWALL_CHAIN_POWERSAVE = 3; + // Specify RESTRICTED chain(fw_restricted) which is used in restricted + // networking mode + const int FIREWALL_CHAIN_RESTRICTED = 4; + + /** + * Set firewall rule for interface + * + * @param ifName the interface to allow/deny + * @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + + /** + * Set firewall rule for uid + * + * @param childChain target chain + * @param uid uid to allow/deny + * @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void firewallSetUidRule(int childChain, int uid, int firewallRule); + + /** + * Enable/Disable target firewall child chain + * + * @param childChain target chain to enable + * @param enable whether to enable or disable child chain. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void firewallEnableChildChain(int childChain, boolean enable); + + /** + * Get interface list + * + * @return An array of strings containing all the interfaces on the system. + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + @utf8InCpp String[] interfaceGetList(); + + // Must be kept in sync with constant in InterfaceConfiguration.java + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; + + /** + * Get interface configuration + * + * @param ifName interface name + * @return An InterfaceConfigurationParcel for the specified interface. + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + + /** + * Set interface configuration + * + * @param cfg Interface configuration to set + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void interfaceSetCfg(in InterfaceConfigurationParcel cfg); + + /** + * Set interface IPv6 privacy extensions + * + * @param ifName interface name + * @param enable whether to enable or disable this setting. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + + /** + * Clear all IP addresses on the given interface + * + * @param ifName interface name + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * POSIX errno. + */ + void interfaceClearAddrs(in @utf8InCpp String ifName); + + /** + * Enable or disable IPv6 on the given interface + * + * @param ifName interface name + * @param enable whether to enable or disable this setting. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + + /** + * Set interface MTU + * + * @param ifName interface name + * @param mtu MTU value + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + + /** + * Add forwarding rule/stats on given interface. + * + * @param intIface downstream interface + * @param extIface upstream interface + */ + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + + /** + * Remove forwarding rule/stats on given interface. + * + * @param intIface downstream interface + * @param extIface upstream interface + */ + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + + /** + * Set the values of tcp_{rmem,wmem}. + * + * @param rmemValues the target values of tcp_rmem, each value is separated by spaces + * @param wmemValues the target values of tcp_wmem, each value is separated by spaces + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + + /** + * Register unsolicited event listener + * Netd supports multiple unsolicited event listeners. + * + * @param listener unsolicited event listener to register + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void registerUnsolicitedEventListener(INetdUnsolicitedEventListener listener); + + /** + * 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 + * allowed interface and loopback to be sent to the list of UIDs. + * + * Calling this method on one or more UIDs with an existing filtering rule but a different + * interface name will result in the filtering rule being updated to allow the new interface + * instead. Otherwise calling this method will not affect existing rules set on other UIDs. + * + * @param ifName the name of the interface on which the filtering rules will allow packets to + be received. + * @param uids an array of UIDs which the filtering rules will be set + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + + /** + * Remove ingress interface filtering rules from a list of UIDs + * + * Clear the ingress interface filtering rules from the list of UIDs which were previously set + * by firewallAddUidInterfaceRules(). Ignore any uid which does not have filtering rule. + * + * @param uids an array of UIDs from which the filtering rules will be removed + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void firewallRemoveUidInterfaceRules(in int[] uids); + + /** + * Request netd to change the current active network stats map. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void trafficSwapActiveStatsMap(); + + /** + * Retrieves OEM netd listener interface + * + * @return a IBinder object, it could be casted to oem specific interface. + */ + IBinder getOemNetd(); + + /** + * Start tethering with given configuration + * + * @param config config to start tethering. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherStartWithConfiguration(in TetherConfigParcel config); + + + /** + * Get the fwmark and its net id mask for the given network id. + * + * @param netId the network to get the fwmark and mask for. + * @return A MarkMaskParcel of the given network id. + */ + MarkMaskParcel getFwmarkForNetwork(int netId); + + /** + * Add a route for specific network + * + * @param netId the network to add the route to + * @param routeInfo parcelable with route information + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + + /** + * Update a route for specific network + * + * @param routeInfo parcelable with route information + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + + /** + * Remove a route for specific network + * + * @param routeInfo parcelable with route information + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + + /** + * Adds a tethering offload rule, or updates it if it already exists. + * + * Currently, only downstream /128 IPv6 entries are supported. An existing rule will be updated + * if the input interface and destination prefix match. Otherwise, a new rule will be created. + * + * @param rule The rule to add or update. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherOffloadRuleAdd(in TetherOffloadRuleParcel rule); + + /** + * Deletes a tethering offload rule. + * + * Currently, only downstream /128 IPv6 entries are supported. An existing rule will be deleted + * if the destination IP address and the source interface match. It is not an error if there is + * no matching rule to delete. + * + * @param rule The rule to delete. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherOffloadRuleRemove(in TetherOffloadRuleParcel rule); + + /** + * Return BPF tethering offload statistics. + * + * @return an array of TetherStatsParcel's, where each entry contains the upstream interface + * index and its tethering statistics since tethering was first started. + * There will only ever be one entry for a given interface index. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + TetherStatsParcel[] tetherOffloadGetStats(); + + /** + * Set a per-interface quota for tethering offload. + * + * @param ifIndex Index of upstream interface + * @param quotaBytes The quota defined as the number of bytes, starting from zero and counting + * from *now*. A value of QUOTA_UNLIMITED (-1) indicates there is no limit. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + + /** + * Return BPF tethering offload statistics and clear the stats for a given upstream. + * + * Must only be called once all offload rules have already been deleted for the given upstream + * interface. The existing stats will be fetched and returned. The stats and the limit for the + * given upstream interface will be deleted as well. + * + * The stats and limit for a given upstream interface must be initialized (using + * tetherOffloadSetInterfaceQuota) before any offload will occur on that interface. + * + * @param ifIndex Index of upstream interface. + * @return TetherStatsParcel, which contains the given upstream interface index and its + * tethering statistics since tethering was first started on that upstream interface. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + + /** + * Creates a network. + * + * @param config the configuration of network. + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkCreate(in NativeNetworkConfig config); + + /** + * Adds the specified UID ranges to the specified network. The network can be physical or + * virtual. Traffic from the UID ranges will be routed to the network by default. The possible + * value of subsidiary priority for physical and unreachable networks is 0-999. 0 is the highest + * priority. 0 is also the default value. Virtual network supports only the default value. + * + * @param NativeUidRangeConfig a parcel contains netId, UID ranges, subsidiary priority, etc. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkAddUidRangesParcel(in NativeUidRangeConfig uidRangesConfig); + + /** + * Removes the specified UID ranges from the specified network. The network can be physical or + * virtual. Traffic from the UID ranges will no longer be routed to the network by default. The + * possible value of subsidiary priority for physical and unreachable networks is 0-999. 0 is + * the highest priority. 0 is also the default value. Virtual network supports only the default + * value. + * + * @param NativeUidRangeConfig a parcel contains netId, UID ranges, subsidiary priority, etc. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkRemoveUidRangesParcel(in NativeUidRangeConfig uidRangesConfig); +} diff --git a/staticlibs/netd/binder/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/binder/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..652a79cb68 --- /dev/null +++ b/staticlibs/netd/binder/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,145 @@ +/** + * Copyright (c) 2018, 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; + +/** + * Unsolicited netd events which are reported by the kernel via netlink. + * This one-way interface groups asynchronous notifications sent + * by netd to any process that registered itself via INetd.registerUnsolEventListener. + * + * {@hide} + */ +oneway interface INetdUnsolicitedEventListener { + + /** + * Notifies that an interface has been idle/active for a certain period of time. + * It is the event for idletimer. + * + * @param isActive true for active status, false for idle + * @param timerLabel unique identifier of the idletimer. + * Since NMS only set the identifier as int, only report event with int label. + * @param timestampNs kernel timestamp of this event, 0 for no timestamp + * @param uid uid of this event, -1 for no uid. + * It represents the uid that was responsible for waking the radio. + */ + void onInterfaceClassActivityChanged( + boolean isActive, + int timerLabel, + long timestampNs, + int uid); + + /** + * Notifies that a specific interface reached its quota limit. + * + * @param alertName alert name of the quota limit + * @param ifName interface which reached the limit + */ + void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + + /** + * Provides information on IPv6 DNS servers on a specific interface. + * + * @param ifName interface name + * @param lifetimeS lifetime for the DNS servers in seconds + * @param servers the address of servers. + * e.g. IpV6: "2001:4860:4860::6464" + * + */ + void onInterfaceDnsServerInfo( + @utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + + /** + * Notifies that an address has updated on a specific interface. + * + * @param addr address that is being updated + * @param ifName the name of the interface on which the address is configured + * @param flags address flags, see ifa_flags in if_addr.h + * @param scope current scope of the address + */ + void onInterfaceAddressUpdated( + @utf8InCpp String addr, + @utf8InCpp String ifName, + int flags, + int scope); + + /** + * Notifies that an address has been removed on a specific interface. + * + * @param addr address of this change + * @param ifName the name of the interface that changed addresses + * @param flags address flags, see ifa_flags in if_addr.h + * @param scope address address scope + */ + void onInterfaceAddressRemoved( + @utf8InCpp String addr, + @utf8InCpp String ifName, + int flags, + int scope); + + /** + * Notifies that an interface has been added. + * + * @param ifName the name of the added interface + */ + void onInterfaceAdded(@utf8InCpp String ifName); + + /** + * Notifies that an interface has been removed. + * + * @param ifName the name of the removed interface + */ + void onInterfaceRemoved(@utf8InCpp String ifName); + + /** + * Notifies that the status of the specific interface has changed. + * + * @param ifName the name of the interface that changed status + * @param up true for interface up, false for down + */ + void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + + /** + * Notifies that the link state of the specific interface has changed. + * + * @param ifName the name of the interface whose link state has changed + * @param up true for interface link state up, false for link state down + */ + void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + + /** + * Notifies that an IP route has changed. + * + * @param updated true for update, false for remove + * @param route destination prefix of this route, e.g., "2001:db8::/64" + * @param gateway address of gateway, empty string for no gateway + * @param ifName interface name of this route, empty string for no interface + */ + void onRouteChanged( + boolean updated, + @utf8InCpp String route, + @utf8InCpp String gateway, + @utf8InCpp String ifName); + + /** + * Notifies that kernel has detected a socket sending data not wrapped + * inside a layer of SSL/TLS encryption. + * + * @param uid uid of this event + * @param hex packet content in hex format + */ + void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/binder/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/binder/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..c20792c0df --- /dev/null +++ b/staticlibs/netd/binder/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2018 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; + +/** + * Configuration details for a network interface. + * + * {@hide} + */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + /** + * Interface flags, String versions of IFF_* defined in netd/if.h + */ + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/binder/android/net/MarkMaskParcel.aidl b/staticlibs/netd/binder/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..932b7bffbd --- /dev/null +++ b/staticlibs/netd/binder/android/net/MarkMaskParcel.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2019 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; + +/** + * Structure that stores a firewall mark and its mask. + * + * {@hide} + */ +parcelable MarkMaskParcel { + // The fwmark. + int mark; + // Net id mask of fwmark. + int mask; +} diff --git a/staticlibs/netd/binder/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/binder/android/net/NativeNetworkConfig.aidl new file mode 100644 index 0000000000..2c4f83a4cb --- /dev/null +++ b/staticlibs/netd/binder/android/net/NativeNetworkConfig.aidl @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 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 android.net.NativeNetworkType; +import android.net.NativeVpnType; + +/** + * The configuration to create a network. + * + * {@hide} + */ +@JavaDerive(toString=true, equals=true) +@JavaOnlyImmutable +parcelable NativeNetworkConfig { + /** The networkId to create. */ + int netId; + + /** + * The type of network, e.g. physical network or virtual network. + */ + NativeNetworkType networkType = NativeNetworkType.PHYSICAL; + + /** + * For physical networks. The permission necessary to use the network. Must be one of + * PERMISSION_NONE/PERMISSION_NETWORK/PERMISSION_SYSTEM. Ignored for all other network types. + */ + int permission; + + /** + * For virtual networks. Whether unprivileged apps are allowed to bypass the VPN. Ignored for + * all other network types. + */ + boolean secure; + + /** For virtual networks. The type of VPN to create. Ignored for all other network types. */ + NativeVpnType vpnType = NativeVpnType.PLATFORM; +} diff --git a/staticlibs/netd/binder/android/net/NativeNetworkType.aidl b/staticlibs/netd/binder/android/net/NativeNetworkType.aidl new file mode 100644 index 0000000000..d667029470 --- /dev/null +++ b/staticlibs/netd/binder/android/net/NativeNetworkType.aidl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 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; + +@Backing(type="int") +enum NativeNetworkType { + /** + * Physical network type. + */ + PHYSICAL = 0, + + /** + * Virtual private network type. + */ + VIRTUAL = 1, +} \ No newline at end of file diff --git a/staticlibs/netd/binder/android/net/NativeVpnType.aidl b/staticlibs/netd/binder/android/net/NativeVpnType.aidl new file mode 100644 index 0000000000..cd1b4474d6 --- /dev/null +++ b/staticlibs/netd/binder/android/net/NativeVpnType.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 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; + +@Backing(type="int") +enum NativeVpnType { + /** + * A VPN created by an app using the VpnService API. + */ + SERVICE = 1, + + /** + * A VPN created using a VpnManager API such as startProvisionedVpnProfile. + */ + PLATFORM = 2, + + /** + * An IPsec VPN created by the built-in LegacyVpnRunner. + */ + LEGACY = 3, + + /** + * An VPN created by OEM code through other means than VpnService or VpnManager. + */ + OEM = 4, +} \ No newline at end of file diff --git a/staticlibs/netd/binder/android/net/RouteInfoParcel.aidl b/staticlibs/netd/binder/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..fcc86e32ac --- /dev/null +++ b/staticlibs/netd/binder/android/net/RouteInfoParcel.aidl @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2020, 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; + +parcelable RouteInfoParcel { + // The destination of the route. + @utf8InCpp String destination; + // The name of interface of the route. This interface should be assigned to the netID. + @utf8InCpp String ifName; + // The route's next hop address, or one of the NEXTHOP_* constants defined in INetd.aidl. + @utf8InCpp String nextHop; + // The MTU of the route. + int mtu; +} diff --git a/staticlibs/netd/binder/android/net/TetherConfigParcel.aidl b/staticlibs/netd/binder/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..9f371ce106 --- /dev/null +++ b/staticlibs/netd/binder/android/net/TetherConfigParcel.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 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; + +/** + * The configuration to start tethering. + * + * {@hide} + */ +parcelable TetherConfigParcel { + // Whether to enable or disable legacy DNS proxy server. + boolean usingLegacyDnsProxy; + // DHCP ranges to set. + // dhcpRanges might contain many addresss {addr1, addr2, addr3, addr4...} + // Netd splits them into ranges: addr1-addr2, addr3-addr4, etc. + // An odd number of addrs will fail. + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/binder/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/binder/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..c549e610c0 --- /dev/null +++ b/staticlibs/netd/binder/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 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; + +/** + * Represents a forwarding rule for tethering offload. + * + * {@hide} + */ +parcelable TetherOffloadRuleParcel { + /** The interface index of the input interface. */ + int inputInterfaceIndex; + + /** The interface index of the output interface. */ + int outputInterfaceIndex; + + /** The base IP address of the destination prefix as a byte array. */ + byte[] destination; + + /** The destination prefix length. */ + int prefixLength; + + /** The source link-layer address. Currently, must be a 6-byte MAC address.*/ + byte[] srcL2Address; + + /** The destination link-layer address. Currently, must be a 6-byte MAC address. */ + byte[] dstL2Address; + + /** The outbound path mtu. */ + int pmtu = 1500; +} diff --git a/staticlibs/netd/binder/android/net/TetherStatsParcel.aidl b/staticlibs/netd/binder/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..6bf60a86e3 --- /dev/null +++ b/staticlibs/netd/binder/android/net/TetherStatsParcel.aidl @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 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; + +/** + * The statistics of tethering interface + * + * {@hide} + */ +parcelable TetherStatsParcel { + /** + * Parcel representing tethering interface statistics. + * + * This parcel is used by tetherGetStats, tetherOffloadGetStats and + * tetherOffloadGetAndClearStats in INetd.aidl. tetherGetStats uses this parcel to return the + * tethering statistics since netd startup and presents the interface via its interface name. + * Both tetherOffloadGetStats and tetherOffloadGetAndClearStats use this parcel to return + * the tethering statistics since tethering was first started. They present the interface via + * its interface index. Note that the interface must be presented by either interface name + * |iface| or interface index |ifIndex| in this parcel. The unused interface name is set to + * an empty string "" by default and the unused interface index is set to 0 by default. + */ + + /** The interface name. */ + @utf8InCpp String iface; + + /** Total number of received bytes. */ + long rxBytes; + + /** Total number of received packets. */ + long rxPackets; + + /** Total number of transmitted bytes. */ + long txBytes; + + /** Total number of transmitted packets. */ + long txPackets; + + /** The interface index. */ + int ifIndex = 0; +} diff --git a/staticlibs/netd/binder/android/net/UidRangeParcel.aidl b/staticlibs/netd/binder/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..8f1fef6f11 --- /dev/null +++ b/staticlibs/netd/binder/android/net/UidRangeParcel.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 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; + +/** + * An inclusive range of UIDs. + * + * {@hide} + */ +@JavaOnlyImmutable @JavaDerive(toString=true, equals=true) +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/binder/android/net/metrics/INetdEventListener.aidl b/staticlibs/netd/binder/android/net/metrics/INetdEventListener.aidl new file mode 100644 index 0000000000..ef1b2cbcd2 --- /dev/null +++ b/staticlibs/netd/binder/android/net/metrics/INetdEventListener.aidl @@ -0,0 +1,128 @@ +/** + * Copyright (c) 2016, 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.metrics; + +/** + * Logs netd events. + * + * {@hide} + */ +oneway interface INetdEventListener { + const int EVENT_GETADDRINFO = 1; + const int EVENT_GETHOSTBYNAME = 2; + const int EVENT_GETHOSTBYADDR = 3; + const int EVENT_RES_NSEND = 4; + + const int REPORTING_LEVEL_NONE = 0; + const int REPORTING_LEVEL_METRICS = 1; + const int REPORTING_LEVEL_FULL = 2; + + // Maximum number of IP addresses logged for DNS lookups before we truncate the full list. + const int DNS_REPORTED_IP_ADDRESSES_LIMIT = 10; + + /** + * Logs a DNS lookup function call (getaddrinfo and gethostbyname). + * + * @param netId the ID of the network the lookup was performed on. + * @param eventType one of the EVENT_* constants in this interface. + * @param returnCode the return value of the function call. + * @param latencyMs the latency of the function call. + * @param hostname the name that was looked up. + * @param ipAddresses (possibly a subset of) the IP addresses returned. + * At most {@link #DNS_REPORTED_IP_ADDRESSES_LIMIT} addresses are logged. + * @param ipAddressesCount the number of IP addresses returned. May be different from the length + * of ipAddresses if there were too many addresses to log. + * @param uid the UID of the application that performed the query. + */ + void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs, + @utf8InCpp String hostname, in @utf8InCpp String[] ipAddresses, + int ipAddressesCount, int uid); + + /** + * Represents a private DNS validation success or failure. + * + * @param netId the ID of the network the validation was performed on. + * @param ipAddress the IP address for which validation was performed. + * @param hostname the hostname for which validation was performed. + * @param validated whether or not validation was successful. + */ + void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname, + boolean validated); + + /** + * Logs a single connect library call. + * + * @param netId the ID of the network the connect was performed on. + * @param error 0 if the connect call succeeded, otherwise errno if it failed. + * @param latencyMs the latency of the connect call. + * @param ipAddr destination IP address. + * @param port destination port number. + * @param uid the UID of the application that performed the connection. + */ + void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port, int uid); + + /** + * Logs a single RX packet which caused the main CPU to exit sleep state. + * @param prefix arbitrary string provided via wakeupAddInterface() + * @param uid UID of the destination process or -1 if no UID is available. + * @param ethertype of the RX packet encoded in an int in native order, or -1 if not available. + * @param ipNextHeader ip protocol of the RX packet as IPPROTO_* number, + or -1 if the packet was not IPv4 or IPv6. + * @param dstHw destination hardware address, or 0 if not available. + * @param srcIp source IP address, or null if not available. + * @param dstIp destination IP address, or null if not available. + * @param srcPort src port of RX packet in native order, or -1 if the packet was not UDP or TCP. + * @param dstPort dst port of RX packet in native order, or -1 if the packet was not UDP or TCP. + * @param timestampNs receive timestamp for the offending packet. In units of nanoseconds and + * synchronized to CLOCK_MONOTONIC. + */ + void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader, in byte[] dstHw, + String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs); + + /** + * An event sent after every Netlink sock_diag poll performed by Netd. This reported batch + * groups TCP socket stats aggregated by network id. Per-network data are stored in a + * structure-of-arrays style where networkIds, sentPackets, lostPackets, rttUs, and + * sentAckDiffMs have the same length. Stats for the i-th network is spread across all these + * arrays at index i. + * @param networkIds an array of network ids for which there was tcp socket stats to collect in + * the last sock_diag poll. + * @param sentPackets an array of packet sent across all TCP sockets still alive and new + TCP sockets since the last sock_diag poll, summed per network id. + * @param lostPackets, an array of packet lost across all TCP sockets still alive and new + TCP sockets since the last sock_diag poll, summed per network id. + * @param rttUs an array of smoothed round trip times in microseconds, averaged across all TCP + sockets since the last sock_diag poll for a given network id. + * @param sentAckDiffMs an array of milliseconds duration between the last packet sent and the + last ack received for a socket, averaged across all TCP sockets for a network id. + */ + void onTcpSocketStatsEvent(in int[] networkIds, in int[] sentPackets, + in int[] lostPackets, in int[] rttUs, in int[] sentAckDiffMs); + + /** + * Represents adding or removing a NAT64 prefix. + * + * @param netId the ID of the network the prefix was discovered on. + * @param added true if the NAT64 prefix was added, or false if the NAT64 prefix was removed. + * There is only one prefix at a time for each netId. If a prefix is added, it replaces + * the previous-added prefix. + * @param prefixString the detected NAT64 prefix as a string literal. + * @param prefixLength the prefix length associated with this NAT64 prefix. + */ + void onNat64PrefixEvent(int netId, boolean added, @utf8InCpp String prefixString, + int prefixLength); +} diff --git a/staticlibs/netd/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl b/staticlibs/netd/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl new file mode 100644 index 0000000000..99497a863c --- /dev/null +++ b/staticlibs/netd/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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.netd.aidl; + +import android.net.UidRangeParcel; + +/** + * The configuration to add or remove UID ranges. + * + * {@hide} + */ +@JavaDerive(toString=true, equals=true) +@JavaOnlyImmutable +parcelable NativeUidRangeConfig { + /** The network ID of the network to add/remove the ranges to/from. */ + int netId; + + /** A set of non-overlapping ranges of UIDs. */ + UidRangeParcel[] uidRanges; + + /** + * The priority of this UID range config. 0 is the highest priority; 999 is the lowest priority. + * The function of this parameter is to adjust the priority when the same UID is set to + * different networks for different features. + */ + int subPriority; +} \ No newline at end of file From 0705d22e1f884a65fabda13dc656f9447fc8e516 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 1 Oct 2021 03:54:02 +0000 Subject: [PATCH 254/777] Add @NonNull and @Nullable annotations in NetlinkMessage. Add @NonNull and @Nullable annotations on StructNlMsgHdr and parse function to give the caller a clear indication the StructNlMsgHdr should be non-null and safe to call its public method, avoid throwing NPE; the same for parse code, which might return null and caller should check the nullability of return value. Bug: 163492391 Test: atest NetworkStaticLibsTests Change-Id: I0cdf6e611a2b5398b048ffc02ec8fb5f8f8a73db --- .../net/module/util/netlink/ConntrackMessage.java | 4 +++- .../android/net/module/util/netlink/InetDiagMessage.java | 7 +++++-- .../net/module/util/netlink/NduseroptMessage.java | 1 + .../net/module/util/netlink/NetlinkErrorMessage.java | 9 +++++++-- .../android/net/module/util/netlink/NetlinkMessage.java | 8 +++++--- .../module/util/netlink/RtNetlinkNeighborMessage.java | 9 +++++++-- .../android/net/module/util/netlink/StructNlMsgHdr.java | 3 ++- 7 files changed, 30 insertions(+), 11 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/ConntrackMessage.java b/staticlibs/device/com/android/net/module/util/netlink/ConntrackMessage.java index 1763c04ba8..dfed3efb6a 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/ConntrackMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/ConntrackMessage.java @@ -228,7 +228,9 @@ public class ConntrackMessage extends NetlinkMessage { * @return the parsed netfilter conntrack message, or {@code null} if the netfilter conntrack * message could not be parsed successfully (for example, if it was truncated). */ - public static ConntrackMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) { + @Nullable + public static ConntrackMessage parse(@NonNull StructNlMsgHdr header, + @NonNull ByteBuffer byteBuffer) { // Just build the netlink header and netfilter header for now and pretend the whole message // was consumed. // TODO: Parse the conntrack attributes. diff --git a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java index 7b200e7597..a8aef7b434 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java @@ -31,6 +31,7 @@ import android.net.util.SocketUtils; import android.system.ErrnoException; import android.util.Log; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.io.FileDescriptor; @@ -107,7 +108,7 @@ public class InetDiagMessage extends NetlinkMessage { public StructInetDiagMsg mStructInetDiagMsg; - private InetDiagMessage(StructNlMsgHdr header) { + private InetDiagMessage(@NonNull StructNlMsgHdr header) { super(header); mStructInetDiagMsg = new StructInetDiagMsg(); } @@ -115,7 +116,9 @@ public class InetDiagMessage extends NetlinkMessage { /** * Parse an inet_diag_req_v2 message from buffer. */ - public static InetDiagMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) { + @NonNull + public static InetDiagMessage parse(@NonNull StructNlMsgHdr header, + @NonNull ByteBuffer byteBuffer) { final InetDiagMessage msg = new InetDiagMessage(header); msg.mStructInetDiagMsg = StructInetDiagMsg.parse(byteBuffer); return msg; diff --git a/staticlibs/device/com/android/net/module/util/netlink/NduseroptMessage.java b/staticlibs/device/com/android/net/module/util/netlink/NduseroptMessage.java index 9d2402da5d..bdf574db89 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NduseroptMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NduseroptMessage.java @@ -123,6 +123,7 @@ public class NduseroptMessage extends NetlinkMessage { * @return the parsed option, or {@code null} if the option could not be parsed successfully * (for example, if it was truncated, or if the prefix length code was wrong). */ + @Nullable public static NduseroptMessage parse(@NonNull StructNlMsgHdr header, @NonNull ByteBuffer buf) { if (buf == null || buf.remaining() < STRUCT_SIZE) return null; ByteOrder oldOrder = buf.order(); diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkErrorMessage.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkErrorMessage.java index d9fb09e64f..4831432341 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkErrorMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkErrorMessage.java @@ -16,6 +16,9 @@ package com.android.net.module.util.netlink; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.nio.ByteBuffer; /** @@ -32,7 +35,9 @@ public class NetlinkErrorMessage extends NetlinkMessage { * @return the parsed netlink error message, or {@code null} if the netlink error message * could not be parsed successfully (for example, if it was truncated). */ - public static NetlinkErrorMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) { + @Nullable + public static NetlinkErrorMessage parse(@NonNull StructNlMsgHdr header, + @NonNull ByteBuffer byteBuffer) { final NetlinkErrorMessage errorMsg = new NetlinkErrorMessage(header); errorMsg.mNlMsgErr = StructNlMsgErr.parse(byteBuffer); @@ -45,7 +50,7 @@ public class NetlinkErrorMessage extends NetlinkMessage { private StructNlMsgErr mNlMsgErr; - NetlinkErrorMessage(StructNlMsgHdr header) { + NetlinkErrorMessage(@NonNull StructNlMsgHdr header) { super(header); mNlMsgErr = null; } diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java index f425384f34..723d6823a1 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java @@ -79,12 +79,14 @@ public class NetlinkMessage { return null; } - protected StructNlMsgHdr mHeader; + @NonNull + protected final StructNlMsgHdr mHeader; - public NetlinkMessage(StructNlMsgHdr nlmsghdr) { + public NetlinkMessage(@NonNull StructNlMsgHdr nlmsghdr) { mHeader = nlmsghdr; } + @NonNull public StructNlMsgHdr getHeader() { return mHeader; } @@ -96,7 +98,7 @@ public class NetlinkMessage { // a string by StructNlMsgHdr#toString and just keep as an integer. The specific message // which inherits NetlinkMessage could override NetlinkMessage#toString and provide the // specific netlink family to StructNlMsgHdr#toString. - return "NetlinkMessage{" + (mHeader == null ? "" : mHeader.toString()) + "}"; + return "NetlinkMessage{" + mHeader.toString() + "}"; } @NonNull diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkNeighborMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkNeighborMessage.java index a75ef8dd23..4a090151fb 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkNeighborMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkNeighborMessage.java @@ -23,6 +23,9 @@ import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; import android.system.OsConstants; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.net.Inet6Address; import java.net.InetAddress; import java.nio.ByteBuffer; @@ -53,7 +56,9 @@ public class RtNetlinkNeighborMessage extends NetlinkMessage { * @param header netlink message header. * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. */ - public static RtNetlinkNeighborMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) { + @Nullable + public static RtNetlinkNeighborMessage parse(@NonNull StructNlMsgHdr header, + @NonNull ByteBuffer byteBuffer) { final RtNetlinkNeighborMessage neighMsg = new RtNetlinkNeighborMessage(header); neighMsg.mNdmsg = StructNdMsg.parse(byteBuffer); @@ -154,7 +159,7 @@ public class RtNetlinkNeighborMessage extends NetlinkMessage { private int mNumProbes; private StructNdaCacheInfo mCacheInfo; - private RtNetlinkNeighborMessage(StructNlMsgHdr header) { + private RtNetlinkNeighborMessage(@NonNull StructNlMsgHdr header) { super(header); mNdmsg = null; mDestination = null; diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNlMsgHdr.java b/staticlibs/device/com/android/net/module/util/netlink/StructNlMsgHdr.java index ddf1562f17..9567cce22b 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructNlMsgHdr.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNlMsgHdr.java @@ -93,7 +93,8 @@ public class StructNlMsgHdr { /** * Parse netlink message header from buffer. */ - public static StructNlMsgHdr parse(ByteBuffer byteBuffer) { + @Nullable + public static StructNlMsgHdr parse(@NonNull ByteBuffer byteBuffer) { if (!hasAvailableSpace(byteBuffer)) return null; // The ByteOrder must have already been set by the caller. In most From 16b160bfcb020d88c2fbfb50f36486d78150ef5f Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 22 Jun 2021 01:21:24 +0000 Subject: [PATCH 255/777] Add OnSetWarningAndLimit into TestableNetworkStatsProvider This change also address left comments at ag/15010113. Test: m gts && atest \ GtsNetworkStackHostTestCases:NetworkStatsHostTest#testNetworkStatsProvider Bug: 191327585 Merged-In: I100668cc6d4cecbaff29d027d37d313dd48854f3 Change-Id: Ib1f3820fe8502b939d36cef29bdb8dea428604b5 (cherry-picked from ag/15061296) --- .../testutils/TestableNetworkStatsProvider.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt index d034a7d509..8477151b7e 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt @@ -30,7 +30,12 @@ open class TestableNetworkStatsProvider( ) : NetworkStatsProvider() { sealed class CallbackType { data class OnRequestStatsUpdate(val token: Int) : CallbackType() - data class OnSetLimit(val iface: String?, val quotaBytes: Long) : CallbackType() + data class OnSetWarningAndLimit( + val iface: String?, + val warningBytes: Long, + val limitBytes: Long + ) : CallbackType() + data class OnSetLimit(val iface: String?, val limitBytes: Long) : CallbackType() data class OnSetAlert(val quotaBytes: Long) : CallbackType() } @@ -42,6 +47,10 @@ open class TestableNetworkStatsProvider( history.add(CallbackType.OnRequestStatsUpdate(token)) } + override fun onSetWarningAndLimit(iface: String, warningBytes: Long, limitBytes: Long) { + history.add(CallbackType.OnSetWarningAndLimit(iface, warningBytes, limitBytes)) + } + override fun onSetLimit(iface: String, quotaBytes: Long) { history.add(CallbackType.OnSetLimit(iface, quotaBytes)) } @@ -56,7 +65,7 @@ open class TestableNetworkStatsProvider( if (token != TOKEN_ANY) { assertEquals(token, event.token) } - return token + return event.token } fun expectOnSetLimit(iface: String?, quotaBytes: Long, timeout: Long = defaultTimeoutMs) { From 749459c3bd81d2d516067ad44e11295e9b932371 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Fri, 1 Oct 2021 09:52:36 +0000 Subject: [PATCH 256/777] Add getter for quotaBytes Since the counter part test is in internal branch only. Change the member of OnSetLimit makes it fail to build on the rvc+aosp branch. Thus, add a getter for backward compatibility since the rvc test does not recognize limitBytes. This change also addresses some nullability confusions that are not going to happen. Test: m gts && atest \ GtsNetworkStackHostTestCases:NetworkStatsHostTest#testNetworkStatsProvider on R & S codebase. Bug: 191327585 Change-Id: I91dc8cb2297ca503c49b78bf1102cc5572d16530 --- .../android/testutils/TestableNetworkStatsProvider.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt index 8477151b7e..be5c9b2eab 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt @@ -31,11 +31,15 @@ open class TestableNetworkStatsProvider( sealed class CallbackType { data class OnRequestStatsUpdate(val token: Int) : CallbackType() data class OnSetWarningAndLimit( - val iface: String?, + val iface: String, val warningBytes: Long, val limitBytes: Long ) : CallbackType() - data class OnSetLimit(val iface: String?, val limitBytes: Long) : CallbackType() + data class OnSetLimit(val iface: String, val limitBytes: Long) : CallbackType() { + // Add getter for backward compatibility since old tests do not recognize limitBytes. + val quotaBytes: Long + get() = limitBytes + } data class OnSetAlert(val quotaBytes: Long) : CallbackType() } @@ -68,7 +72,7 @@ open class TestableNetworkStatsProvider( return event.token } - fun expectOnSetLimit(iface: String?, quotaBytes: Long, timeout: Long = defaultTimeoutMs) { + fun expectOnSetLimit(iface: String, quotaBytes: Long, timeout: Long = defaultTimeoutMs) { assertEquals(CallbackType.OnSetLimit(iface, quotaBytes), history.poll(timeout)) } From 38c32486230b202e0d7f228b02bacf5450dca765 Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 29 Sep 2021 12:19:44 +0800 Subject: [PATCH 257/777] Move netd AIDL to frameworks/lib/net Clean move system/netd/server/aidl_api/ and system/netd/server/binder/ $ diff -qr frameworks/libs/net/common/binder/netd/aidl_api/ system/netd/server/aidl_api/ $ diff -qr frameworks/libs/net/common/binder/netd/src/ system/netd/server/binder/ Only in system/netd/server/binder/: com Bug: 201488997 Test: atest netd_integration_test atest netd_unit_test Ignore-AOSP-First: the netd change(same topic) would not automerger from aosp. No-Typo-Check: this is a simple code move with no other changes. BYPASS_INCLUSIVE_LANGUAGE_REASON=this is a simple code move with no other changes and these files are frozen anyway Change-Id: Id5bb63794aff4025355c587b372c3ff5b1054da6 Merged-In: Id5bb63794aff4025355c587b372c3ff5b1054da6 --- staticlibs/netd/Android.bp | 155 ++ .../netd/aidl_api/netd_aidl_interface/1/.hash | 1 + .../1/android/net/INetd.aidl | 132 ++ .../net/INetdUnsolicitedEventListener.aidl | 14 + .../net/InterfaceConfigurationParcel.aidl | 8 + .../1/android/net/TetherStatsParcel.aidl | 8 + .../1/android/net/UidRangeParcel.aidl | 5 + .../netd/aidl_api/netd_aidl_interface/2/.hash | 1 + .../2/android/net/INetd.aidl | 153 ++ .../net/INetdUnsolicitedEventListener.aidl | 31 + .../net/InterfaceConfigurationParcel.aidl | 25 + .../2/android/net/TetherStatsParcel.aidl | 25 + .../2/android/net/UidRangeParcel.aidl | 22 + .../netd/aidl_api/netd_aidl_interface/3/.hash | 1 + .../3/android/net/INetd.aidl | 161 ++ .../net/INetdUnsolicitedEventListener.aidl | 32 + .../net/InterfaceConfigurationParcel.aidl | 26 + .../3/android/net/MarkMaskParcel.aidl | 23 + .../3/android/net/RouteInfoParcel.aidl | 24 + .../3/android/net/TetherConfigParcel.aidl | 23 + .../android/net/TetherOffloadRuleParcel.aidl | 27 + .../3/android/net/TetherStatsParcel.aidl | 26 + .../3/android/net/UidRangeParcel.aidl | 23 + .../netd/aidl_api/netd_aidl_interface/4/.hash | 1 + .../4/android/net/INetd.aidl | 164 ++ .../net/INetdUnsolicitedEventListener.aidl | 32 + .../net/InterfaceConfigurationParcel.aidl | 26 + .../4/android/net/MarkMaskParcel.aidl | 23 + .../4/android/net/RouteInfoParcel.aidl | 24 + .../4/android/net/TetherConfigParcel.aidl | 23 + .../android/net/TetherOffloadRuleParcel.aidl | 28 + .../4/android/net/TetherStatsParcel.aidl | 27 + .../4/android/net/UidRangeParcel.aidl | 23 + .../netd/aidl_api/netd_aidl_interface/5/.hash | 1 + .../5/android/net/INetd.aidl | 167 ++ .../net/INetdUnsolicitedEventListener.aidl | 32 + .../net/InterfaceConfigurationParcel.aidl | 26 + .../5/android/net/MarkMaskParcel.aidl | 23 + .../5/android/net/RouteInfoParcel.aidl | 24 + .../5/android/net/TetherConfigParcel.aidl | 23 + .../android/net/TetherOffloadRuleParcel.aidl | 28 + .../5/android/net/TetherStatsParcel.aidl | 27 + .../5/android/net/UidRangeParcel.aidl | 24 + .../netd/aidl_api/netd_aidl_interface/6/.hash | 1 + .../6/android/net/INetd.aidl | 198 +++ .../net/INetdUnsolicitedEventListener.aidl | 48 + .../net/InterfaceConfigurationParcel.aidl | 42 + .../6/android/net/MarkMaskParcel.aidl | 39 + .../6/android/net/NativeNetworkConfig.aidl | 43 + .../6/android/net/NativeNetworkType.aidl | 39 + .../6/android/net/NativeVpnType.aidl | 41 + .../6/android/net/RouteInfoParcel.aidl | 40 + .../6/android/net/TetherConfigParcel.aidl | 39 + .../android/net/TetherOffloadRuleParcel.aidl | 44 + .../6/android/net/TetherStatsParcel.aidl | 43 + .../6/android/net/UidRangeParcel.aidl | 40 + .../netd/aidl_api/netd_aidl_interface/7/.hash | 1 + .../7/android/net/INetd.aidl | 200 +++ .../net/INetdUnsolicitedEventListener.aidl | 48 + .../net/InterfaceConfigurationParcel.aidl | 42 + .../7/android/net/MarkMaskParcel.aidl | 39 + .../7/android/net/NativeNetworkConfig.aidl | 43 + .../7/android/net/NativeNetworkType.aidl | 39 + .../7/android/net/NativeVpnType.aidl | 41 + .../7/android/net/RouteInfoParcel.aidl | 40 + .../7/android/net/TetherConfigParcel.aidl | 39 + .../android/net/TetherOffloadRuleParcel.aidl | 44 + .../7/android/net/TetherStatsParcel.aidl | 43 + .../7/android/net/UidRangeParcel.aidl | 40 + .../net/netd/aidl/NativeUidRangeConfig.aidl | 41 + .../current/android/net/INetd.aidl | 200 +++ .../net/INetdUnsolicitedEventListener.aidl | 48 + .../net/InterfaceConfigurationParcel.aidl | 42 + .../current/android/net/MarkMaskParcel.aidl | 39 + .../android/net/NativeNetworkConfig.aidl | 43 + .../android/net/NativeNetworkType.aidl | 39 + .../current/android/net/NativeVpnType.aidl | 41 + .../current/android/net/RouteInfoParcel.aidl | 40 + .../android/net/TetherConfigParcel.aidl | 39 + .../android/net/TetherOffloadRuleParcel.aidl | 44 + .../android/net/TetherStatsParcel.aidl | 43 + .../current/android/net/UidRangeParcel.aidl | 40 + .../net/netd/aidl/NativeUidRangeConfig.aidl | 41 + .../netd_event_listener_interface/1/.hash | 1 + .../net/metrics/INetdEventListener.aidl | 34 + .../net/metrics/INetdEventListener.aidl | 35 + staticlibs/netd/binder/android/net/INetd.aidl | 1380 +++++++++++++++++ .../net/INetdUnsolicitedEventListener.aidl | 145 ++ .../net/InterfaceConfigurationParcel.aidl | 33 + .../binder/android/net/MarkMaskParcel.aidl | 29 + .../android/net/NativeNetworkConfig.aidl | 52 + .../binder/android/net/NativeNetworkType.aidl | 30 + .../binder/android/net/NativeVpnType.aidl | 40 + .../binder/android/net/RouteInfoParcel.aidl | 28 + .../android/net/TetherConfigParcel.aidl | 32 + .../android/net/TetherOffloadRuleParcel.aidl | 45 + .../binder/android/net/TetherStatsParcel.aidl | 55 + .../binder/android/net/UidRangeParcel.aidl | 28 + .../net/metrics/INetdEventListener.aidl | 128 ++ .../net/netd/aidl/NativeUidRangeConfig.aidl | 41 + 100 files changed, 5884 insertions(+) create mode 100644 staticlibs/netd/Android.bp create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/1/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/2/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeVpnType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeVpnType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/netd/aidl/NativeUidRangeConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeVpnType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_event_listener_interface/1/.hash create mode 100644 staticlibs/netd/aidl_api/netd_event_listener_interface/1/android/net/metrics/INetdEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_event_listener_interface/current/android/net/metrics/INetdEventListener.aidl create mode 100644 staticlibs/netd/binder/android/net/INetd.aidl create mode 100644 staticlibs/netd/binder/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/binder/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/binder/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/binder/android/net/NativeNetworkConfig.aidl create mode 100644 staticlibs/netd/binder/android/net/NativeNetworkType.aidl create mode 100644 staticlibs/netd/binder/android/net/NativeVpnType.aidl create mode 100644 staticlibs/netd/binder/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/binder/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/binder/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/binder/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/binder/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/binder/android/net/metrics/INetdEventListener.aidl create mode 100644 staticlibs/netd/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp new file mode 100644 index 0000000000..c93c2fc485 --- /dev/null +++ b/staticlibs/netd/Android.bp @@ -0,0 +1,155 @@ +// Copyright (C) 2021 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. + +java_library { + name: "netd_aidl_interface-lateststable-java", + sdk_version: "system_current", + min_sdk_version: "29", + static_libs: [ + "netd_aidl_interface-V7-java", + ], + apex_available: [ + "//apex_available:platform", // used from services.net + "com.android.bluetooth.updatable", + "com.android.tethering", + "com.android.wifi", + ], +} + +cc_library_static { + name: "netd_event_listener_interface-lateststable-ndk", + whole_static_libs: [ + "netd_event_listener_interface-V1-ndk", + ], + apex_available: [ + "com.android.resolv", + ], + min_sdk_version: "29", +} + +cc_library_static { + name: "netd_aidl_interface-lateststable-ndk", + whole_static_libs: [ + "netd_aidl_interface-V7-ndk", + ], + apex_available: [ + "com.android.resolv", + ], + min_sdk_version: "29", +} + +cc_library_static { + name: "netd_aidl_interface-lateststable-cpp", + whole_static_libs: [ + "netd_aidl_interface-V7-cpp", + ], +} + +aidl_interface { + name: "netd_aidl_interface", + local_include_dir: "binder", + srcs: [ + "binder/android/net/INetd.aidl", + // AIDL interface that callers can implement to receive networking events from netd. + "binder/android/net/INetdUnsolicitedEventListener.aidl", + "binder/android/net/InterfaceConfigurationParcel.aidl", + "binder/android/net/MarkMaskParcel.aidl", + "binder/android/net/NativeNetworkConfig.aidl", + "binder/android/net/NativeNetworkType.aidl", + "binder/android/net/NativeVpnType.aidl", + "binder/android/net/RouteInfoParcel.aidl", + "binder/android/net/TetherConfigParcel.aidl", + "binder/android/net/TetherOffloadRuleParcel.aidl", + "binder/android/net/TetherStatsParcel.aidl", + "binder/android/net/UidRangeParcel.aidl", + // Add new AIDL classes in android.net.netd.aidl to consist with other network modules. + "binder/android/net/netd/aidl/**/*.aidl", + ], + backend: { + cpp: { + gen_log: true, + }, + java: { + // TODO: Remove apex_available and restrict visibility to only mainline modules that are + // either outside the system server or use jarjar to rename the generated AIDL classes. + apex_available: [ + "//apex_available:platform", // used from services.net + "com.android.bluetooth.updatable", + "com.android.tethering", + "com.android.wifi", + ], + // this is part of updatable modules(NetworkStack) which targets 29(Q) + min_sdk_version: "29", + }, + ndk: { + apex_available: [ + "//apex_available:platform", + ], + // This is necessary for the DnsResovler tests to run in Android Q. + // Soong would recognize this value and produce the Q compatible aidl library. + min_sdk_version: "29", + }, + }, + versions: [ + "1", + "2", + "3", + "4", + "5", + "6", + "7", + ], +} + +java_library { + name: "netd_event_listener_interface-lateststable-java", + sdk_version: "system_current", + min_sdk_version: "29", + static_libs: [ + "netd_event_listener_interface-V1-java", + ], + apex_available: [ + "//apex_available:platform", + "com.android.bluetooth.updatable", + "com.android.wifi", + "com.android.tethering", + ], +} + +aidl_interface { + name: "netd_event_listener_interface", + local_include_dir: "binder", + srcs: [ + "binder/android/net/metrics/INetdEventListener.aidl", + ], + versions: ["1"], + backend: { + ndk: { + apex_available: [ + "//apex_available:platform", + "com.android.resolv", + ], + min_sdk_version: "29", + }, + java: { + apex_available: [ + "//apex_available:platform", + "com.android.bluetooth.updatable", + "com.android.wifi", + "com.android.tethering", + ], + min_sdk_version: "29", + }, + }, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/1/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/1/.hash new file mode 100644 index 0000000000..d33e90387b --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/1/.hash @@ -0,0 +1 @@ +69c2ac134efbb31e9591d7e5c3640fb839e23bdb diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/INetd.aidl new file mode 100644 index 0000000000..664c643fb2 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/INetd.aidl @@ -0,0 +1,132 @@ +package android.net; +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + void networkCreatePhysical(int netId, int permission); + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..18631ffa1a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,14 @@ +package android.net; +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..93407dcb90 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,8 @@ +package android.net; +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..d1782bb0cf --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/TetherStatsParcel.aidl @@ -0,0 +1,8 @@ +package android.net; +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..d3bc7edfd0 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/1/android/net/UidRangeParcel.aidl @@ -0,0 +1,5 @@ +package android.net; +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/2/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/2/.hash new file mode 100644 index 0000000000..5fc5b2d7ed --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/2/.hash @@ -0,0 +1 @@ +e395d63302c47e7d2dac0d503045779029ff598b diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/INetd.aidl new file mode 100644 index 0000000000..0e2d5f4365 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/INetd.aidl @@ -0,0 +1,153 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not +// try to edit this file. It looks like you are doing that because you have +// modified an AIDL interface in a backward-incompatible way, e.g., deleting a +// function from an interface or a field from a parcelable and it broke the +// build. That breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + void networkCreatePhysical(int netId, int permission); + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..621f1cf865 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,31 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not +// try to edit this file. It looks like you are doing that because you have +// modified an AIDL interface in a backward-incompatible way, e.g., deleting a +// function from an interface or a field from a parcelable and it broke the +// build. That breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..18de61f32f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not +// try to edit this file. It looks like you are doing that because you have +// modified an AIDL interface in a backward-incompatible way, e.g., deleting a +// function from an interface or a field from a parcelable and it broke the +// build. That breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..c0ba67666a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/TetherStatsParcel.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not +// try to edit this file. It looks like you are doing that because you have +// modified an AIDL interface in a backward-incompatible way, e.g., deleting a +// function from an interface or a field from a parcelable and it broke the +// build. That breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..c2c35db2d3 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/2/android/net/UidRangeParcel.aidl @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not +// try to edit this file. It looks like you are doing that because you have +// modified an AIDL interface in a backward-incompatible way, e.g., deleting a +// function from an interface or a field from a parcelable and it broke the +// build. That breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/3/.hash new file mode 100644 index 0000000000..59cf70898d --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/.hash @@ -0,0 +1 @@ +e17c1f9b2068b539b22e3a4a447edea3c80aee4b diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/INetd.aidl new file mode 100644 index 0000000000..135b738508 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/INetd.aidl @@ -0,0 +1,161 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + void networkCreatePhysical(int netId, int permission); + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..4459363217 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,32 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..01e0f95541 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..62be838420 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/MarkMaskParcel.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5e0ee62a0f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/RouteInfoParcel.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..b13645450a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherConfigParcel.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..3abf0f89a3 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..71ffb9b964 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/TetherStatsParcel.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..84ff4572dd --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/3/android/net/UidRangeParcel.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/4/.hash new file mode 100644 index 0000000000..0c3f810e67 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/.hash @@ -0,0 +1 @@ +63adaa5098e4d8621e90c5a84f7cb93505c79311 diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/INetd.aidl new file mode 100644 index 0000000000..47e2931d7c --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/INetd.aidl @@ -0,0 +1,164 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + void networkCreatePhysical(int netId, int permission); + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..4459363217 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,32 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..01e0f95541 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..62be838420 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/MarkMaskParcel.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5e0ee62a0f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/RouteInfoParcel.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..b13645450a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherConfigParcel.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..c9d845808e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,28 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..0b0960efc5 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/TetherStatsParcel.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..84ff4572dd --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/4/android/net/UidRangeParcel.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/5/.hash new file mode 100644 index 0000000000..a6ced4538a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/.hash @@ -0,0 +1 @@ +d97c56dd789cee9eeb5cdcec43a99df0a01873a5 diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/INetd.aidl new file mode 100644 index 0000000000..b30748a3c8 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/INetd.aidl @@ -0,0 +1,167 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + void networkCreatePhysical(int netId, int permission); + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + const @JavaPassthrough(annotation="@Deprecated") int FIREWALL_WHITELIST = 0; + const int FIREWALL_ALLOWLIST = 0; + const @JavaPassthrough(annotation="@Deprecated") int FIREWALL_BLACKLIST = 1; + const int FIREWALL_DENYLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const int FIREWALL_CHAIN_RESTRICTED = 4; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..4459363217 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,32 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..01e0f95541 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..62be838420 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/MarkMaskParcel.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5e0ee62a0f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/RouteInfoParcel.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..b13645450a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherConfigParcel.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..c9d845808e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,28 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..0b0960efc5 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/TetherStatsParcel.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..debc6be2d3 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/5/android/net/UidRangeParcel.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/6/.hash new file mode 100644 index 0000000000..f5acf5d1ee --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/.hash @@ -0,0 +1 @@ +b08451d9673b09cba84f1fd8740e1fdac64ff7be diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/INetd.aidl new file mode 100644 index 0000000000..a7952f28df --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/INetd.aidl @@ -0,0 +1,198 @@ +/** + * Copyright (c) 2016, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreatePhysical(int netId, int permission); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + void networkCreate(in android.net.NativeNetworkConfig config); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const int DUMMY_NET_ID = 51; + const int UNREACHABLE_NET_ID = 52; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + /** + * @deprecated use FIREWALL_ALLOWLIST. + */ + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_ALLOWLIST = 0; + /** + * @deprecated use FIREWALL_DENYLIST. + */ + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_DENYLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const int FIREWALL_CHAIN_RESTRICTED = 4; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..31775dfd11 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2018, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..1869d8d49e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..8ea20d118f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/MarkMaskParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkConfig.aidl new file mode 100644 index 0000000000..76562b294a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkConfig.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeNetworkConfig { + int netId; + android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL; + int permission; + boolean secure; + android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkType.aidl new file mode 100644 index 0000000000..06c8979d51 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkType.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeNetworkType { + PHYSICAL = 0, + VIRTUAL = 1, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeVpnType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeVpnType.aidl new file mode 100644 index 0000000000..8a8be83958 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/NativeVpnType.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeVpnType { + SERVICE = 1, + PLATFORM = 2, + LEGACY = 3, + OEM = 4, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5ef95e67ca --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/RouteInfoParcel.aidl @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2020, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..7b39c22e4e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherConfigParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..983e9860ea --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..5f1b722690 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/TetherStatsParcel.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..72e987a2af --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/6/android/net/UidRangeParcel.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/7/.hash new file mode 100644 index 0000000000..cad59dfd74 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/.hash @@ -0,0 +1 @@ +850353de5d19a0dd718f8fd20791f0532e6a34c7 diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/INetd.aidl new file mode 100644 index 0000000000..ec03d86b6c --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/INetd.aidl @@ -0,0 +1,200 @@ +/** + * Copyright (c) 2016, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreatePhysical(int netId, int permission); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + void networkCreate(in android.net.NativeNetworkConfig config); + void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const int DUMMY_NET_ID = 51; + const int UNREACHABLE_NET_ID = 52; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + /** + * @deprecated use FIREWALL_ALLOWLIST. + */ + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_ALLOWLIST = 0; + /** + * @deprecated use FIREWALL_DENYLIST. + */ + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_DENYLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const int FIREWALL_CHAIN_RESTRICTED = 4; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..31775dfd11 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2018, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..1869d8d49e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..8ea20d118f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/MarkMaskParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkConfig.aidl new file mode 100644 index 0000000000..76562b294a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkConfig.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeNetworkConfig { + int netId; + android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL; + int permission; + boolean secure; + android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkType.aidl new file mode 100644 index 0000000000..06c8979d51 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkType.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeNetworkType { + PHYSICAL = 0, + VIRTUAL = 1, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeVpnType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeVpnType.aidl new file mode 100644 index 0000000000..8a8be83958 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/NativeVpnType.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeVpnType { + SERVICE = 1, + PLATFORM = 2, + LEGACY = 3, + OEM = 4, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5ef95e67ca --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/RouteInfoParcel.aidl @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2020, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..7b39c22e4e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherConfigParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..983e9860ea --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..5f1b722690 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/TetherStatsParcel.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..72e987a2af --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/UidRangeParcel.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/netd/aidl/NativeUidRangeConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/netd/aidl/NativeUidRangeConfig.aidl new file mode 100644 index 0000000000..9bb679f1c1 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/7/android/net/netd/aidl/NativeUidRangeConfig.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.netd.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeUidRangeConfig { + int netId; + android.net.UidRangeParcel[] uidRanges; + int subPriority; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl new file mode 100644 index 0000000000..ec03d86b6c --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl @@ -0,0 +1,200 @@ +/** + * Copyright (c) 2016, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreatePhysical(int netId, int permission); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + void networkCreate(in android.net.NativeNetworkConfig config); + void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const int DUMMY_NET_ID = 51; + const int UNREACHABLE_NET_ID = 52; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + /** + * @deprecated use FIREWALL_ALLOWLIST. + */ + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_ALLOWLIST = 0; + /** + * @deprecated use FIREWALL_DENYLIST. + */ + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_DENYLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const int FIREWALL_CHAIN_RESTRICTED = 4; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..31775dfd11 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2018, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..1869d8d49e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..8ea20d118f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl new file mode 100644 index 0000000000..76562b294a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeNetworkConfig { + int netId; + android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL; + int permission; + boolean secure; + android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl new file mode 100644 index 0000000000..06c8979d51 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeNetworkType { + PHYSICAL = 0, + VIRTUAL = 1, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeVpnType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeVpnType.aidl new file mode 100644 index 0000000000..8a8be83958 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeVpnType.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeVpnType { + SERVICE = 1, + PLATFORM = 2, + LEGACY = 3, + OEM = 4, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5ef95e67ca --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2020, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..7b39c22e4e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..983e9860ea --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..5f1b722690 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..72e987a2af --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl new file mode 100644 index 0000000000..9bb679f1c1 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.netd.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeUidRangeConfig { + int netId; + android.net.UidRangeParcel[] uidRanges; + int subPriority; +} diff --git a/staticlibs/netd/aidl_api/netd_event_listener_interface/1/.hash b/staticlibs/netd/aidl_api/netd_event_listener_interface/1/.hash new file mode 100644 index 0000000000..f39f730fe5 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_event_listener_interface/1/.hash @@ -0,0 +1 @@ +8e27594d285ca7c567d87e8cf74766c27647e02b diff --git a/staticlibs/netd/aidl_api/netd_event_listener_interface/1/android/net/metrics/INetdEventListener.aidl b/staticlibs/netd/aidl_api/netd_event_listener_interface/1/android/net/metrics/INetdEventListener.aidl new file mode 100644 index 0000000000..9898a67403 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_event_listener_interface/1/android/net/metrics/INetdEventListener.aidl @@ -0,0 +1,34 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not +// try to edit this file. It looks like you are doing that because you have +// modified an AIDL interface in a backward-incompatible way, e.g., deleting a +// function from an interface or a field from a parcelable and it broke the +// build. That breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.metrics; +interface INetdEventListener { + oneway void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs, @utf8InCpp String hostname, in @utf8InCpp String[] ipAddresses, int ipAddressesCount, int uid); + oneway void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname, boolean validated); + oneway void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port, int uid); + oneway void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader, in byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs); + oneway void onTcpSocketStatsEvent(in int[] networkIds, in int[] sentPackets, in int[] lostPackets, in int[] rttUs, in int[] sentAckDiffMs); + oneway void onNat64PrefixEvent(int netId, boolean added, @utf8InCpp String prefixString, int prefixLength); + const int EVENT_GETADDRINFO = 1; + const int EVENT_GETHOSTBYNAME = 2; + const int EVENT_GETHOSTBYADDR = 3; + const int EVENT_RES_NSEND = 4; + const int REPORTING_LEVEL_NONE = 0; + const int REPORTING_LEVEL_METRICS = 1; + const int REPORTING_LEVEL_FULL = 2; + const int DNS_REPORTED_IP_ADDRESSES_LIMIT = 10; +} diff --git a/staticlibs/netd/aidl_api/netd_event_listener_interface/current/android/net/metrics/INetdEventListener.aidl b/staticlibs/netd/aidl_api/netd_event_listener_interface/current/android/net/metrics/INetdEventListener.aidl new file mode 100644 index 0000000000..d71c3f29b5 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_event_listener_interface/current/android/net/metrics/INetdEventListener.aidl @@ -0,0 +1,35 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.metrics; +/* @hide */ +interface INetdEventListener { + oneway void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs, @utf8InCpp String hostname, in @utf8InCpp String[] ipAddresses, int ipAddressesCount, int uid); + oneway void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname, boolean validated); + oneway void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port, int uid); + oneway void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader, in byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs); + oneway void onTcpSocketStatsEvent(in int[] networkIds, in int[] sentPackets, in int[] lostPackets, in int[] rttUs, in int[] sentAckDiffMs); + oneway void onNat64PrefixEvent(int netId, boolean added, @utf8InCpp String prefixString, int prefixLength); + const int EVENT_GETADDRINFO = 1; + const int EVENT_GETHOSTBYNAME = 2; + const int EVENT_GETHOSTBYADDR = 3; + const int EVENT_RES_NSEND = 4; + const int REPORTING_LEVEL_NONE = 0; + const int REPORTING_LEVEL_METRICS = 1; + const int REPORTING_LEVEL_FULL = 2; + const int DNS_REPORTED_IP_ADDRESSES_LIMIT = 10; +} diff --git a/staticlibs/netd/binder/android/net/INetd.aidl b/staticlibs/netd/binder/android/net/INetd.aidl new file mode 100644 index 0000000000..d6398c1222 --- /dev/null +++ b/staticlibs/netd/binder/android/net/INetd.aidl @@ -0,0 +1,1380 @@ +/** + * Copyright (c) 2016, 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 android.net.INetdUnsolicitedEventListener; +import android.net.InterfaceConfigurationParcel; +import android.net.MarkMaskParcel; +import android.net.NativeNetworkConfig; +import android.net.RouteInfoParcel; +import android.net.TetherConfigParcel; +import android.net.TetherOffloadRuleParcel; +import android.net.TetherStatsParcel; +import android.net.UidRangeParcel; +import android.net.netd.aidl.NativeUidRangeConfig; + +/** {@hide} */ +interface INetd { + /** + * Returns true if the service is responding. + */ + boolean isAlive(); + + /** + * Replaces the contents of the specified UID-based firewall chain. + * + * The chain may be an allowlist chain or a denylist chain. A denylist chain contains DROP + * rules for the specified UIDs and a RETURN rule at the end. An allowlist chain contains RETURN + * rules for the system UID range (0 to {@code UID_APP} - 1), RETURN rules for for the specified + * UIDs, and a DROP rule at the end. The chain will be created if it does not exist. + * + * @param chainName The name of the chain to replace. + * @param isAllowlist Whether this is an allowlist or denylist chain. + * @param uids The list of UIDs to allow/deny. + * @return true if the chain was successfully replaced, false otherwise. + */ + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, + boolean isAllowlist, + in int[] uids); + + /** + * Enables or disables data saver mode on costly network interfaces. + * + * - When disabled, all packets to/from apps in the penalty box chain are rejected on costly + * interfaces. Traffic to/from other apps or on other network interfaces is allowed. + * - When enabled, only apps that are in the happy box chain and not in the penalty box chain + * are allowed network connectivity on costly interfaces. All other packets on these + * interfaces are rejected. The happy box chain always contains all system UIDs; to disallow + * traffic from system UIDs, place them in the penalty box chain. + * + * By default, data saver mode is disabled. This command has no effect but might still return an + * error) if {@code enable} is the same as the current value. + * + * @param enable whether to enable or disable data saver mode. + * @return true if the if the operation was successful, false otherwise. + */ + boolean bandwidthEnableDataSaver(boolean enable); + + /** + * Creates a physical network (i.e., one containing physical interfaces. + * @deprecated use networkCreate() instead. + * + * @param netId the networkId to create. + * @param permission the permission necessary to use the network. Must be one of + * PERMISSION_NONE/PERMISSION_NETWORK/PERMISSION_SYSTEM. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkCreatePhysical(int netId, int permission); + + /** + * Creates a VPN network. + * @deprecated use networkCreate() instead. + * + * @param netId the network to create. + * @param secure whether unprivileged apps are allowed to bypass the VPN. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkCreateVpn(int netId, boolean secure); + + /** + * Destroys a network. Any interfaces added to the network are removed, and the network ceases + * to be the default network. + * + * @param netId the network to destroy. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkDestroy(int netId); + + /** + * Adds an interface to a network. The interface must not be assigned to any network, including + * the specified network. + * + * @param netId the network to add the interface to. + * @param interface the name of the interface to add. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkAddInterface(int netId, in @utf8InCpp String iface); + + /** + * Adds an interface to a network. The interface must be assigned to the specified network. + * + * @param netId the network to remove the interface from. + * @param interface the name of the interface to remove. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + + /** + * Adds the specified UID ranges to the specified network. The network can be physical or + * virtual. Traffic from the UID ranges will be routed to the network by default. + * + * @param netId the network ID of the network to add the ranges to. + * @param uidRanges a set of non-overlapping ranges of UIDs to add. These exact ranges + * must not overlap with existing ranges assigned to this network. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkAddUidRanges(int netId, in UidRangeParcel[] uidRanges); + + /** + * Remove the specified UID ranges from the specified network. The network can be physical or + * virtual. Traffic from the UID ranges will no longer be routed to the network by default. + * + * @param netId the network ID of the network to remove the ranges from. + * @param uidRanges a set of non-overlapping ranges of UIDs to remove. These exact ranges + * must already be assigned to this network. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkRemoveUidRanges(int netId, in UidRangeParcel[] uidRanges); + + /** + * Adds or removes one rule for each supplied UID range to prohibit all network activity outside + * of secure VPN. + * + * When a UID is covered by one of these rules, traffic sent through any socket that is not + * protected or explicitly overriden by the system will be rejected. The kernel will respond + * with an ICMP prohibit message. + * + * Initially, there are no such rules. Any rules that are added will only last until the next + * restart of netd or the device. + * + * @param add {@code true} if the specified UID ranges should be denied access to any network + * which is not secure VPN by adding rules, {@code false} to remove existing rules. + * @param uidRanges a set of non-overlapping, contiguous ranges of UIDs to which to apply or + * remove this restriction. + *

Added rules should not overlap with existing rules. Likewise, removed rules should + * each correspond to an existing rule. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkRejectNonSecureVpn(boolean add, in UidRangeParcel[] uidRanges); + + /** + * Administratively closes sockets belonging to the specified UIDs. + */ + void socketDestroy(in UidRangeParcel[] uidRanges, in int[] exemptUids); + + /** + * Instruct the tethering DNS server to reevaluated serving interfaces. + * This is needed to for the DNS server to observe changes in the set + * of potential listening IP addresses. (Listening on wildcard addresses + * can turn the device into an open resolver; b/7530468) + * + * TODO: Return something richer than just a boolean. + */ + boolean tetherApplyDnsInterfaces(); + + /** + * Return tethering statistics. + * + * @return an array of TetherStatsParcel, where each entry contains the upstream interface + * name and its tethering statistics since netd startup. + * There will only ever be one entry for a given interface. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + TetherStatsParcel[] tetherGetStats(); + + /** + * Add/Remove and IP address from an interface. + * + * @param ifName the interface name + * @param addrString the IP address to add/remove as a string literal + * @param prefixLength the prefix length associated with this IP address + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, + int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, + int prefixLength); + + /** + * Set and get /proc/sys/net interface configuration parameters. + * + * @param ipversion One of IPV4/IPV6 integers, indicating the desired IP version directory. + * @param which One of CONF/NEIGH integers, indicating the desired parameter category directory. + * @param ifname The interface name portion of the path; may also be "all" or "default". + * @param parameter The parameter name portion of the path. + * @param value The value string to be written into the assembled path. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, + in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, + in @utf8InCpp String parameter, in @utf8InCpp String value); + + /** + * Sets owner of socket ParcelFileDescriptor to the new UID, checking to ensure that the caller's + * uid is that of the old owner's, and that this is a UDP-encap socket + * + * @param ParcelFileDescriptor socket Socket file descriptor + * @param int newUid UID of the new socket fd owner + */ + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + + /** + * Reserve an SPI from the kernel + * + * @param transformId a unique identifier for allocated resources + * @param sourceAddress InetAddress as string for the sending endpoint + * @param destinationAddress InetAddress as string for the receiving endpoint + * @param spi a requested 32-bit unique ID or 0 to request random allocation + * @return the SPI that was allocated or 0 if failed + */ + int ipSecAllocateSpi( + int transformId, + in @utf8InCpp String sourceAddress, + in @utf8InCpp String destinationAddress, + int spi); + + /** + * Create an IpSec Security Association describing how ip(v6) traffic will be encrypted + * or decrypted. + * + * @param transformId a unique identifier for allocated resources + * @param mode either Transport or Tunnel mode + * @param sourceAddress InetAddress as string for the sending endpoint + * @param destinationAddress InetAddress as string for the receiving endpoint + * @param underlyingNetId the netId of the network to which the SA is applied. Only accepted for + * tunnel mode SAs. + * @param spi a 32-bit unique ID allocated to the user + * @param markValue a 32-bit unique ID chosen by the user + * @param markMask a 32-bit mask chosen by the user + * @param authAlgo a string identifying the authentication algorithm to be used + * @param authKey a byte array containing the authentication key + * @param authTruncBits the truncation length of the MAC produced by the authentication algorithm + * @param cryptAlgo a string identifying the encryption algorithm to be used + * @param cryptKey a byte arrray containing the encryption key + * @param cryptTruncBits unused parameter + * @param aeadAlgo a string identifying the authenticated encryption algorithm to be used + * @param aeadKey a byte arrray containing the key to be used in authenticated encryption + * @param aeadIcvBits the truncation length of the ICV produced by the authentication algorithm + * (similar to authTruncBits in function) + * @param encapType encapsulation type used (if any) for the udp encap socket + * @param encapLocalPort the port number on the host to be used in encap packets + * @param encapRemotePort the port number of the remote to be used for encap packets + * @param interfaceId the identifier for the IPsec tunnel interface. + * Only accepted for tunnel mode SAs. + */ + void ipSecAddSecurityAssociation( + int transformId, + int mode, + in @utf8InCpp String sourceAddress, + in @utf8InCpp String destinationAddress, + int underlyingNetId, + int spi, + int markValue, + int markMask, + in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, + in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, + in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, + int encapType, + int encapLocalPort, + int encapRemotePort, + int interfaceId); + + /** + * Delete a previously created security association identified by the provided parameters + * + * @param transformId a unique identifier for allocated resources + * @param sourceAddress InetAddress as string for the sending endpoint + * @param destinationAddress InetAddress as string for the receiving endpoint + * @param spi a requested 32-bit unique ID allocated to the user + * @param markValue a 32-bit unique ID chosen by the user + * @param markMask a 32-bit mask chosen by the user + * @param interfaceId the identifier for the IPsec tunnel interface. + */ + void ipSecDeleteSecurityAssociation( + int transformId, + in @utf8InCpp String sourceAddress, + in @utf8InCpp String destinationAddress, + int spi, + int markValue, + int markMask, + int interfaceId); + + /** + * Apply a previously created SA to a specified socket, starting IPsec on that socket + * + * @param socket a user-provided socket that will have IPsec applied + * @param transformId a unique identifier for allocated resources + * @param direction DIRECTION_IN or DIRECTION_OUT + * @param sourceAddress InetAddress as string for the sending endpoint + * @param destinationAddress InetAddress as string for the receiving endpoint + * @param spi a 32-bit unique ID allocated to the user (socket owner) + */ + void ipSecApplyTransportModeTransform( + in ParcelFileDescriptor socket, + int transformId, + int direction, + in @utf8InCpp String sourceAddress, + in @utf8InCpp String destinationAddress, + int spi); + + /** + * Remove an IPsec SA from a given socket. This will allow unencrypted traffic to flow + * on that socket if a transform had been previously applied. + * + * @param socket a user-provided socket from which to remove any IPsec configuration + */ + void ipSecRemoveTransportModeTransform( + in ParcelFileDescriptor socket); + + /** + * Adds an IPsec global policy. + * + * @param transformId a unique identifier for allocated resources + * @param selAddrFamily the address family identifier for the selector + * @param direction DIRECTION_IN or DIRECTION_OUT + * @param tmplSrcAddress InetAddress as string for the sending endpoint + * @param tmplDstAddress InetAddress as string for the receiving endpoint + * @param spi a 32-bit unique ID allocated to the user + * @param markValue a 32-bit unique ID chosen by the user + * @param markMask a 32-bit mask chosen by the user + * @param interfaceId the identifier for the IPsec tunnel interface. + */ + void ipSecAddSecurityPolicy( + int transformId, + int selAddrFamily, + int direction, + in @utf8InCpp String tmplSrcAddress, + in @utf8InCpp String tmplDstAddress, + int spi, + int markValue, + int markMask, + int interfaceId); + + /** + * Updates an IPsec global policy. + * + * @param transformId a unique identifier for allocated resources + * @param selAddrFamily the address family identifier for the selector + * @param direction DIRECTION_IN or DIRECTION_OUT + * @param tmplSrcAddress InetAddress as string for the sending endpoint + * @param tmplDstAddress InetAddress as string for the receiving endpoint + * @param spi a 32-bit unique ID allocated to the user + * @param markValue a 32-bit unique ID chosen by the user + * @param markMask a 32-bit mask chosen by the user + * @param interfaceId the identifier for the IPsec tunnel interface. + */ + void ipSecUpdateSecurityPolicy( + int transformId, + int selAddrFamily, + int direction, + in @utf8InCpp String tmplSrcAddress, + in @utf8InCpp String tmplDstAddress, + int spi, + int markValue, + int markMask, + int interfaceId); + + /** + * Deletes an IPsec global policy. + * + * Deletion of global policies does not do any matching based on the templates, thus + * template source/destination addresses are not needed (as opposed to add/update). + * + * @param transformId a unique identifier for allocated resources + * @param selAddrFamily the address family identifier for the selector + * @param direction DIRECTION_IN or DIRECTION_OUT + * @param markValue a 32-bit unique ID chosen by the user + * @param markMask a 32-bit mask chosen by the user + * @param interfaceId the identifier for the IPsec tunnel interface. + */ + void ipSecDeleteSecurityPolicy( + int transformId, + int selAddrFamily, + int direction, + int markValue, + int markMask, + int interfaceId); + + // This could not be declared as @uft8InCpp; thus, when used in native code it must be + // converted from a UTF-16 string to an ASCII string. + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + + /** + * Add a IPsec Tunnel Interface. + * + * @param devName a unique identifier that represents the name of the device + * @param localAddress InetAddress as string for the local endpoint + * @param remoteAddress InetAddress as string for the remote endpoint + * @param iKey, to match Policies and SAs for input packets. + * @param oKey, to match Policies and SAs for output packets. + * @param interfaceId the identifier for the IPsec tunnel interface. + */ + void ipSecAddTunnelInterface( + in @utf8InCpp String deviceName, + in @utf8InCpp String localAddress, + in @utf8InCpp String remoteAddress, + int iKey, + int oKey, + int interfaceId); + + /** + * Update a IPsec Tunnel Interface. + * + * @param devName a unique identifier that represents the name of the device + * @param localAddress InetAddress as string for the local endpoint + * @param remoteAddress InetAddress as string for the remote endpoint + * @param iKey, to match Policies and SAs for input packets. + * @param oKey, to match Policies and SAs for output packets. + * @param interfaceId the identifier for the IPsec tunnel interface. + */ + void ipSecUpdateTunnelInterface( + in @utf8InCpp String deviceName, + in @utf8InCpp String localAddress, + in @utf8InCpp String remoteAddress, + int iKey, + int oKey, + int interfaceId); + + /** + * Removes a IPsec Tunnel Interface. + * + * @param devName a unique identifier that represents the name of the device + */ + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + + /** + * Request notification of wakeup packets arriving on an interface. Notifications will be + * delivered to INetdEventListener.onWakeupEvent(). + * + * @param ifName the interface + * @param prefix arbitrary string used to identify wakeup sources in onWakeupEvent + */ + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + + /** + * Stop notification of wakeup packets arriving on an interface. + * + * @param ifName the interface + * @param prefix arbitrary string used to identify wakeup sources in onWakeupEvent + */ + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + /** + * Set IPv6 address generation mode. IPv6 should be disabled before changing mode. + * + * @param mode SLAAC address generation mechanism to use + */ + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + + /** + * Add idletimer for specific interface + * + * @param ifName Name of target interface + * @param timeout The time in seconds that will trigger idletimer + * @param classLabel The unique identifier for this idletimer + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void idletimerAddInterface( + in @utf8InCpp String ifName, + int timeout, + in @utf8InCpp String classLabel); + + /** + * Remove idletimer for specific interface + * + * @param ifName Name of target interface + * @param timeout The time in seconds that will trigger idletimer + * @param classLabel The unique identifier for this idletimer + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void idletimerRemoveInterface( + in @utf8InCpp String ifName, + int timeout, + in @utf8InCpp String classLabel); + + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + + /** + * Offers to detect sockets sending data not wrapped inside a layer of SSL/TLS encryption. + * + * @param uid Uid of the app + * @param policyPenalty The penalty policy of the app + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void strictUidCleartextPenalty(int uid, int policyPenalty); + + /** + * Start clatd + * + * @param ifName interface name to start clatd + * @param nat64Prefix the NAT64 prefix, e.g., "2001:db8:64::/96". + * @return a string, the IPv6 address that will be used for 464xlat. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + + /** + * Stop clatd + * + * @param ifName interface name to stop clatd + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void clatdStop(in @utf8InCpp String ifName); + + /** + * Get status of IP forwarding + * + * @return true if IP forwarding is enabled, false otherwise. + */ + boolean ipfwdEnabled(); + + /** + * Get requester list of IP forwarding + * + * @return An array of strings containing requester list of IP forwarding + */ + @utf8InCpp String[] ipfwdGetRequesterList(); + + /** + * Enable IP forwarding for specific requester + * + * @param requester requester name to enable IP forwarding. It is a unique name which will be + * stored in Netd to make sure if any requester needs IP forwarding. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void ipfwdEnableForwarding(in @utf8InCpp String requester); + + /** + * Disable IP forwarding for specific requester + * + * @param requester requester name to disable IP forwarding. This name should match the + * names which are set by ipfwdEnableForwarding. + * IP forwarding would be disabled if it is the last requester. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void ipfwdDisableForwarding(in @utf8InCpp String requester); + + /** + * Add forwarding ip rule + * + * @param fromIface interface name to add forwarding ip rule + * @param toIface interface name to add forwarding ip rule + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + + /** + * Remove forwarding ip rule + * + * @param fromIface interface name to remove forwarding ip rule + * @param toIface interface name to remove forwarding ip rule + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + + /** + * Set quota for interface + * + * @param ifName Name of target interface + * @param bytes Quota value in bytes + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + + /** + * Remove quota for interface + * + * @param ifName Name of target interface + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + + /** + * Set alert for interface + * + * @param ifName Name of target interface + * @param bytes Alert value in bytes + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + + /** + * Remove alert for interface + * + * @param ifName Name of target interface + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + + /** + * Set global alert + * + * @param bytes Alert value in bytes + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthSetGlobalAlert(long bytes); + + /** + * Add naughty app bandwidth rule for specific app + * + * @param uid uid of target app + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthAddNaughtyApp(int uid); + + /** + * Remove naughty app bandwidth rule for specific app + * + * @param uid uid of target app + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthRemoveNaughtyApp(int uid); + + /** + * Add nice app bandwidth rule for specific app + * + * @param uid uid of target app + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthAddNiceApp(int uid); + + /** + * Remove nice app bandwidth rule for specific app + * + * @param uid uid of target app + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void bandwidthRemoveNiceApp(int uid); + + /** + * Start tethering + * + * @param dhcpRanges dhcp ranges to set. + * dhcpRanges might contain many addresss {addr1, addr2, aadr3, addr4...} + * Netd splits them into ranges: addr1-addr2, addr3-addr4, etc. + * An odd number of addrs will fail. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherStart(in @utf8InCpp String[] dhcpRanges); + + /** + * Stop tethering + * + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherStop(); + + /** + * Get status of tethering + * + * @return true if tethering is enabled, false otherwise. + */ + boolean tetherIsEnabled(); + + /** + * Setup interface for tethering + * + * @param ifName interface name to add + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherInterfaceAdd(in @utf8InCpp String ifName); + + /** + * Reset interface for tethering + * + * @param ifName interface name to remove + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherInterfaceRemove(in @utf8InCpp String ifName); + + /** + * Get the interface list which is stored in netd + * The list contains the interfaces managed by tetherInterfaceAdd/tetherInterfaceRemove + * + * @return An array of strings containing interface list result + */ + @utf8InCpp String[] tetherInterfaceList(); + + /** + * Set DNS forwarder server + * + * @param netId the upstream network to forward DNS queries to + * @param dnsAddrs DNS server address to set + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + + /** + * Return the DNS list set by tetherDnsSet + * + * @return An array of strings containing the list of DNS servers + */ + @utf8InCpp String[] tetherDnsList(); + + const int LOCAL_NET_ID = 99; + + /** + * Constant net ID for the "dummy" network. + * + * The dummy network is used to blackhole or reject traffic. Any attempt to use it will + * either drop the packets or fail with ENETUNREACH. + */ + const int DUMMY_NET_ID = 51; + + /** + * Constant net ID for the "unreachable" network. + * + * The unreachable network is used to reject traffic. Any attempt to use it will fail + * with ENETUNREACH. + */ + const int UNREACHABLE_NET_ID = 52; + + // Route does not specify a next hop + const String NEXTHOP_NONE = ""; + // Route next hop is unreachable + const String NEXTHOP_UNREACHABLE = "unreachable"; + // Route next hop is throw + const String NEXTHOP_THROW = "throw"; + + /** + * Add a route for specific network + * + * @param netId the network to add the route to + * @param ifName the name of interface of the route. + * This interface should be assigned to the netID. + * @param destination the destination of the route + * @param nextHop The route's next hop address, + * or it could be either NEXTHOP_NONE, NEXTHOP_UNREACHABLE, NEXTHOP_THROW. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkAddRoute( + int netId, + in @utf8InCpp String ifName, + in @utf8InCpp String destination, + in @utf8InCpp String nextHop); + + /** + * Remove a route for specific network + * + * @param netId the network to remove the route from + * @param ifName the name of interface of the route. + * This interface should be assigned to the netID. + * @param destination the destination of the route + * @param nextHop The route's next hop address, + * or it could be either NEXTHOP_NONE, NEXTHOP_UNREACHABLE, NEXTHOP_THROW. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkRemoveRoute( + int netId, + in @utf8InCpp String ifName, + in @utf8InCpp String destination, + in @utf8InCpp String nextHop); + + /** + * Add a route to legacy routing table for specific network + * + * @param netId the network to add the route to + * @param ifName the name of interface of the route. + * This interface should be assigned to the netID. + * @param destination the destination of the route + * @param nextHop The route's next hop address, + * or it could be either NEXTHOP_NONE, NEXTHOP_UNREACHABLE, NEXTHOP_THROW. + * @param uid uid of the user + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkAddLegacyRoute( + int netId, + in @utf8InCpp String ifName, + in @utf8InCpp String destination, + in @utf8InCpp String nextHop, + int uid); + + /** + * Remove a route from legacy routing table for specific network + * + * @param netId the network to remove the route from + * @param ifName the name of interface of the route. + * This interface should be assigned to the netID. + * @param destination the destination of the route + * @param nextHop The route's next hop address, + * or it could be either NEXTHOP_NONE, NEXTHOP_UNREACHABLE, NEXTHOP_THROW. + * @param uid uid of the user + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkRemoveLegacyRoute( + int netId, + in @utf8InCpp String ifName, + in @utf8InCpp String destination, + in @utf8InCpp String nextHop, + int uid); + + /** + * Get default network + * + * @return netId of default network + */ + int networkGetDefault(); + + /** + * Set network as default network + * + * @param netId the network to set as the default + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkSetDefault(int netId); + + /** + * Clear default network + * + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkClearDefault(); + + /** + * PERMISSION_NONE is used for regular networks and apps. TODO: use PERMISSION_INTERNET + * for this instead, and use PERMISSION_NONE to indicate no network permissions at all. + */ + const int PERMISSION_NONE = 0; + + /** + * PERMISSION_NETWORK represents the CHANGE_NETWORK_STATE permission. + */ + const int PERMISSION_NETWORK = 1; + + /** + * PERMISSION_SYSTEM represents the ability to use restricted networks. This is mostly + * equivalent to the CONNECTIVITY_USE_RESTRICTED_NETWORKS permission. + */ + const int PERMISSION_SYSTEM = 2; + + /** + * NO_PERMISSIONS indicates that this app is installed and doesn't have either + * PERMISSION_INTERNET or PERMISSION_UPDATE_DEVICE_STATS. + * TODO: use PERMISSION_NONE to represent this case + */ + const int NO_PERMISSIONS = 0; + + /** + * PERMISSION_INTERNET indicates that the app can create AF_INET and AF_INET6 sockets + */ + const int PERMISSION_INTERNET = 4; + + /** + * PERMISSION_UPDATE_DEVICE_STATS is used for system UIDs and privileged apps + * that have the UPDATE_DEVICE_STATS permission + */ + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + + /** + * PERMISSION_UNINSTALLED is used when an app is uninstalled from the device. All internet + * related permissions need to be cleaned + */ + const int PERMISSION_UNINSTALLED = -1; + + + /** + * Sets the permission required to access a specific network. + * + * @param netId the network to set + * @param permission network permission to use + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkSetPermissionForNetwork(int netId, int permission); + + /** + * Assigns network access permissions to the specified users. + * + * @param permission network permission to use + * @param uids uid of users to set permission + */ + void networkSetPermissionForUser(int permission, in int[] uids); + + /** + * Clears network access permissions for the specified users. + * + * @param uids uid of users to clear permission + */ + void networkClearPermissionForUser(in int[] uids); + + /** + * Assigns android.permission.INTERNET and/or android.permission.UPDATE_DEVICE_STATS to the uids + * specified. Or remove all permissions from the uids. + * + * @param permission The permission to grant, it could be either PERMISSION_INTERNET and/or + * PERMISSION_UPDATE_DEVICE_STATS. If the permission is NO_PERMISSIONS, then + * revoke all permissions for the uids. + * @param uids uid of users to grant permission + */ + void trafficSetNetPermForUids(int permission, in int[] uids); + + /** + * Gives the specified user permission to protect sockets from VPNs. + * Typically used by VPN apps themselves, to ensure that the sockets + * they use to communicate with the VPN server aren't routed through + * the VPN network. + * + * @param uid uid of user to set + */ + void networkSetProtectAllow(int uid); + + /** + * Removes the permission to protect sockets from VPN. + * + * @param uid uid of user to set + */ + void networkSetProtectDeny(int uid); + + /** + * Get the status of network protect for user + * + * @param uids uid of user + * @return true if the user can protect sockets from VPN, false otherwise. + */ + boolean networkCanProtect(int uid); + + /** Only allows packets from specific UID/Interface. + @deprecated use FIREWALL_ALLOWLIST. */ + const int FIREWALL_WHITELIST = 0; + + /** Only allows packets from specific UID/Interface. */ + const int FIREWALL_ALLOWLIST = 0; + + /** Blocks packets from specific UID/Interface. + @deprecated use FIREWALL_DENYLIST. */ + const int FIREWALL_BLACKLIST = 1; + + /** Blocks packets from specific UID/Interface. */ + const int FIREWALL_DENYLIST = 1; + + /** + * Set type of firewall + * Type allowlist only allows packets from specific UID/Interface + * Type denylist blocks packets from specific UID/Interface + * + * @param firewalltype type of firewall, either FIREWALL_ALLOWLIST or FIREWALL_DENYLIST + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void firewallSetFirewallType(int firewalltype); + + // Specify allow Rule which allows packets + const int FIREWALL_RULE_ALLOW = 1; + // Specify deny Rule which drops packets + const int FIREWALL_RULE_DENY = 2; + + // No specific chain is chosen, use general firewall chain(fw_input, fw_output) + const int FIREWALL_CHAIN_NONE = 0; + // Specify DOZABLE chain(fw_dozable) which is used in dozable mode + const int FIREWALL_CHAIN_DOZABLE = 1; + // Specify STANDBY chain(fw_standby) which is used in standby mode + const int FIREWALL_CHAIN_STANDBY = 2; + // Specify POWERSAVE chain(fw_powersave) which is used in power save mode + const int FIREWALL_CHAIN_POWERSAVE = 3; + // Specify RESTRICTED chain(fw_restricted) which is used in restricted + // networking mode + const int FIREWALL_CHAIN_RESTRICTED = 4; + + /** + * Set firewall rule for interface + * + * @param ifName the interface to allow/deny + * @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + + /** + * Set firewall rule for uid + * + * @param childChain target chain + * @param uid uid to allow/deny + * @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void firewallSetUidRule(int childChain, int uid, int firewallRule); + + /** + * Enable/Disable target firewall child chain + * + * @param childChain target chain to enable + * @param enable whether to enable or disable child chain. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void firewallEnableChildChain(int childChain, boolean enable); + + /** + * Get interface list + * + * @return An array of strings containing all the interfaces on the system. + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + @utf8InCpp String[] interfaceGetList(); + + // Must be kept in sync with constant in InterfaceConfiguration.java + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; + + /** + * Get interface configuration + * + * @param ifName interface name + * @return An InterfaceConfigurationParcel for the specified interface. + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + + /** + * Set interface configuration + * + * @param cfg Interface configuration to set + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void interfaceSetCfg(in InterfaceConfigurationParcel cfg); + + /** + * Set interface IPv6 privacy extensions + * + * @param ifName interface name + * @param enable whether to enable or disable this setting. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + + /** + * Clear all IP addresses on the given interface + * + * @param ifName interface name + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * POSIX errno. + */ + void interfaceClearAddrs(in @utf8InCpp String ifName); + + /** + * Enable or disable IPv6 on the given interface + * + * @param ifName interface name + * @param enable whether to enable or disable this setting. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + + /** + * Set interface MTU + * + * @param ifName interface name + * @param mtu MTU value + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + + /** + * Add forwarding rule/stats on given interface. + * + * @param intIface downstream interface + * @param extIface upstream interface + */ + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + + /** + * Remove forwarding rule/stats on given interface. + * + * @param intIface downstream interface + * @param extIface upstream interface + */ + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + + /** + * Set the values of tcp_{rmem,wmem}. + * + * @param rmemValues the target values of tcp_rmem, each value is separated by spaces + * @param wmemValues the target values of tcp_wmem, each value is separated by spaces + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + + /** + * Register unsolicited event listener + * Netd supports multiple unsolicited event listeners. + * + * @param listener unsolicited event listener to register + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void registerUnsolicitedEventListener(INetdUnsolicitedEventListener listener); + + /** + * 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 + * allowed interface and loopback to be sent to the list of UIDs. + * + * Calling this method on one or more UIDs with an existing filtering rule but a different + * interface name will result in the filtering rule being updated to allow the new interface + * instead. Otherwise calling this method will not affect existing rules set on other UIDs. + * + * @param ifName the name of the interface on which the filtering rules will allow packets to + be received. + * @param uids an array of UIDs which the filtering rules will be set + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + + /** + * Remove ingress interface filtering rules from a list of UIDs + * + * Clear the ingress interface filtering rules from the list of UIDs which were previously set + * by firewallAddUidInterfaceRules(). Ignore any uid which does not have filtering rule. + * + * @param uids an array of UIDs from which the filtering rules will be removed + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void firewallRemoveUidInterfaceRules(in int[] uids); + + /** + * Request netd to change the current active network stats map. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void trafficSwapActiveStatsMap(); + + /** + * Retrieves OEM netd listener interface + * + * @return a IBinder object, it could be casted to oem specific interface. + */ + IBinder getOemNetd(); + + /** + * Start tethering with given configuration + * + * @param config config to start tethering. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherStartWithConfiguration(in TetherConfigParcel config); + + + /** + * Get the fwmark and its net id mask for the given network id. + * + * @param netId the network to get the fwmark and mask for. + * @return A MarkMaskParcel of the given network id. + */ + MarkMaskParcel getFwmarkForNetwork(int netId); + + /** + * Add a route for specific network + * + * @param netId the network to add the route to + * @param routeInfo parcelable with route information + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + + /** + * Update a route for specific network + * + * @param routeInfo parcelable with route information + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + + /** + * Remove a route for specific network + * + * @param routeInfo parcelable with route information + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + + /** + * Adds a tethering offload rule, or updates it if it already exists. + * + * Currently, only downstream /128 IPv6 entries are supported. An existing rule will be updated + * if the input interface and destination prefix match. Otherwise, a new rule will be created. + * + * @param rule The rule to add or update. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherOffloadRuleAdd(in TetherOffloadRuleParcel rule); + + /** + * Deletes a tethering offload rule. + * + * Currently, only downstream /128 IPv6 entries are supported. An existing rule will be deleted + * if the destination IP address and the source interface match. It is not an error if there is + * no matching rule to delete. + * + * @param rule The rule to delete. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherOffloadRuleRemove(in TetherOffloadRuleParcel rule); + + /** + * Return BPF tethering offload statistics. + * + * @return an array of TetherStatsParcel's, where each entry contains the upstream interface + * index and its tethering statistics since tethering was first started. + * There will only ever be one entry for a given interface index. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + TetherStatsParcel[] tetherOffloadGetStats(); + + /** + * Set a per-interface quota for tethering offload. + * + * @param ifIndex Index of upstream interface + * @param quotaBytes The quota defined as the number of bytes, starting from zero and counting + * from *now*. A value of QUOTA_UNLIMITED (-1) indicates there is no limit. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + + /** + * Return BPF tethering offload statistics and clear the stats for a given upstream. + * + * Must only be called once all offload rules have already been deleted for the given upstream + * interface. The existing stats will be fetched and returned. The stats and the limit for the + * given upstream interface will be deleted as well. + * + * The stats and limit for a given upstream interface must be initialized (using + * tetherOffloadSetInterfaceQuota) before any offload will occur on that interface. + * + * @param ifIndex Index of upstream interface. + * @return TetherStatsParcel, which contains the given upstream interface index and its + * tethering statistics since tethering was first started on that upstream interface. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + + /** + * Creates a network. + * + * @param config the configuration of network. + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkCreate(in NativeNetworkConfig config); + + /** + * Adds the specified UID ranges to the specified network. The network can be physical or + * virtual. Traffic from the UID ranges will be routed to the network by default. The possible + * value of subsidiary priority for physical and unreachable networks is 0-999. 0 is the highest + * priority. 0 is also the default value. Virtual network supports only the default value. + * + * @param NativeUidRangeConfig a parcel contains netId, UID ranges, subsidiary priority, etc. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkAddUidRangesParcel(in NativeUidRangeConfig uidRangesConfig); + + /** + * Removes the specified UID ranges from the specified network. The network can be physical or + * virtual. Traffic from the UID ranges will no longer be routed to the network by default. The + * possible value of subsidiary priority for physical and unreachable networks is 0-999. 0 is + * the highest priority. 0 is also the default value. Virtual network supports only the default + * value. + * + * @param NativeUidRangeConfig a parcel contains netId, UID ranges, subsidiary priority, etc. + * + * @throws ServiceSpecificException in case of failure, with an error code corresponding to the + * unix errno. + */ + void networkRemoveUidRangesParcel(in NativeUidRangeConfig uidRangesConfig); +} diff --git a/staticlibs/netd/binder/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/binder/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..652a79cb68 --- /dev/null +++ b/staticlibs/netd/binder/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,145 @@ +/** + * Copyright (c) 2018, 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; + +/** + * Unsolicited netd events which are reported by the kernel via netlink. + * This one-way interface groups asynchronous notifications sent + * by netd to any process that registered itself via INetd.registerUnsolEventListener. + * + * {@hide} + */ +oneway interface INetdUnsolicitedEventListener { + + /** + * Notifies that an interface has been idle/active for a certain period of time. + * It is the event for idletimer. + * + * @param isActive true for active status, false for idle + * @param timerLabel unique identifier of the idletimer. + * Since NMS only set the identifier as int, only report event with int label. + * @param timestampNs kernel timestamp of this event, 0 for no timestamp + * @param uid uid of this event, -1 for no uid. + * It represents the uid that was responsible for waking the radio. + */ + void onInterfaceClassActivityChanged( + boolean isActive, + int timerLabel, + long timestampNs, + int uid); + + /** + * Notifies that a specific interface reached its quota limit. + * + * @param alertName alert name of the quota limit + * @param ifName interface which reached the limit + */ + void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + + /** + * Provides information on IPv6 DNS servers on a specific interface. + * + * @param ifName interface name + * @param lifetimeS lifetime for the DNS servers in seconds + * @param servers the address of servers. + * e.g. IpV6: "2001:4860:4860::6464" + * + */ + void onInterfaceDnsServerInfo( + @utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + + /** + * Notifies that an address has updated on a specific interface. + * + * @param addr address that is being updated + * @param ifName the name of the interface on which the address is configured + * @param flags address flags, see ifa_flags in if_addr.h + * @param scope current scope of the address + */ + void onInterfaceAddressUpdated( + @utf8InCpp String addr, + @utf8InCpp String ifName, + int flags, + int scope); + + /** + * Notifies that an address has been removed on a specific interface. + * + * @param addr address of this change + * @param ifName the name of the interface that changed addresses + * @param flags address flags, see ifa_flags in if_addr.h + * @param scope address address scope + */ + void onInterfaceAddressRemoved( + @utf8InCpp String addr, + @utf8InCpp String ifName, + int flags, + int scope); + + /** + * Notifies that an interface has been added. + * + * @param ifName the name of the added interface + */ + void onInterfaceAdded(@utf8InCpp String ifName); + + /** + * Notifies that an interface has been removed. + * + * @param ifName the name of the removed interface + */ + void onInterfaceRemoved(@utf8InCpp String ifName); + + /** + * Notifies that the status of the specific interface has changed. + * + * @param ifName the name of the interface that changed status + * @param up true for interface up, false for down + */ + void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + + /** + * Notifies that the link state of the specific interface has changed. + * + * @param ifName the name of the interface whose link state has changed + * @param up true for interface link state up, false for link state down + */ + void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + + /** + * Notifies that an IP route has changed. + * + * @param updated true for update, false for remove + * @param route destination prefix of this route, e.g., "2001:db8::/64" + * @param gateway address of gateway, empty string for no gateway + * @param ifName interface name of this route, empty string for no interface + */ + void onRouteChanged( + boolean updated, + @utf8InCpp String route, + @utf8InCpp String gateway, + @utf8InCpp String ifName); + + /** + * Notifies that kernel has detected a socket sending data not wrapped + * inside a layer of SSL/TLS encryption. + * + * @param uid uid of this event + * @param hex packet content in hex format + */ + void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/binder/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/binder/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..c20792c0df --- /dev/null +++ b/staticlibs/netd/binder/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2018 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; + +/** + * Configuration details for a network interface. + * + * {@hide} + */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + /** + * Interface flags, String versions of IFF_* defined in netd/if.h + */ + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/binder/android/net/MarkMaskParcel.aidl b/staticlibs/netd/binder/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..932b7bffbd --- /dev/null +++ b/staticlibs/netd/binder/android/net/MarkMaskParcel.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2019 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; + +/** + * Structure that stores a firewall mark and its mask. + * + * {@hide} + */ +parcelable MarkMaskParcel { + // The fwmark. + int mark; + // Net id mask of fwmark. + int mask; +} diff --git a/staticlibs/netd/binder/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/binder/android/net/NativeNetworkConfig.aidl new file mode 100644 index 0000000000..2c4f83a4cb --- /dev/null +++ b/staticlibs/netd/binder/android/net/NativeNetworkConfig.aidl @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 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 android.net.NativeNetworkType; +import android.net.NativeVpnType; + +/** + * The configuration to create a network. + * + * {@hide} + */ +@JavaDerive(toString=true, equals=true) +@JavaOnlyImmutable +parcelable NativeNetworkConfig { + /** The networkId to create. */ + int netId; + + /** + * The type of network, e.g. physical network or virtual network. + */ + NativeNetworkType networkType = NativeNetworkType.PHYSICAL; + + /** + * For physical networks. The permission necessary to use the network. Must be one of + * PERMISSION_NONE/PERMISSION_NETWORK/PERMISSION_SYSTEM. Ignored for all other network types. + */ + int permission; + + /** + * For virtual networks. Whether unprivileged apps are allowed to bypass the VPN. Ignored for + * all other network types. + */ + boolean secure; + + /** For virtual networks. The type of VPN to create. Ignored for all other network types. */ + NativeVpnType vpnType = NativeVpnType.PLATFORM; +} diff --git a/staticlibs/netd/binder/android/net/NativeNetworkType.aidl b/staticlibs/netd/binder/android/net/NativeNetworkType.aidl new file mode 100644 index 0000000000..d667029470 --- /dev/null +++ b/staticlibs/netd/binder/android/net/NativeNetworkType.aidl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 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; + +@Backing(type="int") +enum NativeNetworkType { + /** + * Physical network type. + */ + PHYSICAL = 0, + + /** + * Virtual private network type. + */ + VIRTUAL = 1, +} \ No newline at end of file diff --git a/staticlibs/netd/binder/android/net/NativeVpnType.aidl b/staticlibs/netd/binder/android/net/NativeVpnType.aidl new file mode 100644 index 0000000000..cd1b4474d6 --- /dev/null +++ b/staticlibs/netd/binder/android/net/NativeVpnType.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 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; + +@Backing(type="int") +enum NativeVpnType { + /** + * A VPN created by an app using the VpnService API. + */ + SERVICE = 1, + + /** + * A VPN created using a VpnManager API such as startProvisionedVpnProfile. + */ + PLATFORM = 2, + + /** + * An IPsec VPN created by the built-in LegacyVpnRunner. + */ + LEGACY = 3, + + /** + * An VPN created by OEM code through other means than VpnService or VpnManager. + */ + OEM = 4, +} \ No newline at end of file diff --git a/staticlibs/netd/binder/android/net/RouteInfoParcel.aidl b/staticlibs/netd/binder/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..fcc86e32ac --- /dev/null +++ b/staticlibs/netd/binder/android/net/RouteInfoParcel.aidl @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2020, 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; + +parcelable RouteInfoParcel { + // The destination of the route. + @utf8InCpp String destination; + // The name of interface of the route. This interface should be assigned to the netID. + @utf8InCpp String ifName; + // The route's next hop address, or one of the NEXTHOP_* constants defined in INetd.aidl. + @utf8InCpp String nextHop; + // The MTU of the route. + int mtu; +} diff --git a/staticlibs/netd/binder/android/net/TetherConfigParcel.aidl b/staticlibs/netd/binder/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..9f371ce106 --- /dev/null +++ b/staticlibs/netd/binder/android/net/TetherConfigParcel.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 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; + +/** + * The configuration to start tethering. + * + * {@hide} + */ +parcelable TetherConfigParcel { + // Whether to enable or disable legacy DNS proxy server. + boolean usingLegacyDnsProxy; + // DHCP ranges to set. + // dhcpRanges might contain many addresss {addr1, addr2, addr3, addr4...} + // Netd splits them into ranges: addr1-addr2, addr3-addr4, etc. + // An odd number of addrs will fail. + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/binder/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/binder/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..c549e610c0 --- /dev/null +++ b/staticlibs/netd/binder/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 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; + +/** + * Represents a forwarding rule for tethering offload. + * + * {@hide} + */ +parcelable TetherOffloadRuleParcel { + /** The interface index of the input interface. */ + int inputInterfaceIndex; + + /** The interface index of the output interface. */ + int outputInterfaceIndex; + + /** The base IP address of the destination prefix as a byte array. */ + byte[] destination; + + /** The destination prefix length. */ + int prefixLength; + + /** The source link-layer address. Currently, must be a 6-byte MAC address.*/ + byte[] srcL2Address; + + /** The destination link-layer address. Currently, must be a 6-byte MAC address. */ + byte[] dstL2Address; + + /** The outbound path mtu. */ + int pmtu = 1500; +} diff --git a/staticlibs/netd/binder/android/net/TetherStatsParcel.aidl b/staticlibs/netd/binder/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..6bf60a86e3 --- /dev/null +++ b/staticlibs/netd/binder/android/net/TetherStatsParcel.aidl @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 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; + +/** + * The statistics of tethering interface + * + * {@hide} + */ +parcelable TetherStatsParcel { + /** + * Parcel representing tethering interface statistics. + * + * This parcel is used by tetherGetStats, tetherOffloadGetStats and + * tetherOffloadGetAndClearStats in INetd.aidl. tetherGetStats uses this parcel to return the + * tethering statistics since netd startup and presents the interface via its interface name. + * Both tetherOffloadGetStats and tetherOffloadGetAndClearStats use this parcel to return + * the tethering statistics since tethering was first started. They present the interface via + * its interface index. Note that the interface must be presented by either interface name + * |iface| or interface index |ifIndex| in this parcel. The unused interface name is set to + * an empty string "" by default and the unused interface index is set to 0 by default. + */ + + /** The interface name. */ + @utf8InCpp String iface; + + /** Total number of received bytes. */ + long rxBytes; + + /** Total number of received packets. */ + long rxPackets; + + /** Total number of transmitted bytes. */ + long txBytes; + + /** Total number of transmitted packets. */ + long txPackets; + + /** The interface index. */ + int ifIndex = 0; +} diff --git a/staticlibs/netd/binder/android/net/UidRangeParcel.aidl b/staticlibs/netd/binder/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..8f1fef6f11 --- /dev/null +++ b/staticlibs/netd/binder/android/net/UidRangeParcel.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 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; + +/** + * An inclusive range of UIDs. + * + * {@hide} + */ +@JavaOnlyImmutable @JavaDerive(toString=true, equals=true) +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/binder/android/net/metrics/INetdEventListener.aidl b/staticlibs/netd/binder/android/net/metrics/INetdEventListener.aidl new file mode 100644 index 0000000000..ef1b2cbcd2 --- /dev/null +++ b/staticlibs/netd/binder/android/net/metrics/INetdEventListener.aidl @@ -0,0 +1,128 @@ +/** + * Copyright (c) 2016, 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.metrics; + +/** + * Logs netd events. + * + * {@hide} + */ +oneway interface INetdEventListener { + const int EVENT_GETADDRINFO = 1; + const int EVENT_GETHOSTBYNAME = 2; + const int EVENT_GETHOSTBYADDR = 3; + const int EVENT_RES_NSEND = 4; + + const int REPORTING_LEVEL_NONE = 0; + const int REPORTING_LEVEL_METRICS = 1; + const int REPORTING_LEVEL_FULL = 2; + + // Maximum number of IP addresses logged for DNS lookups before we truncate the full list. + const int DNS_REPORTED_IP_ADDRESSES_LIMIT = 10; + + /** + * Logs a DNS lookup function call (getaddrinfo and gethostbyname). + * + * @param netId the ID of the network the lookup was performed on. + * @param eventType one of the EVENT_* constants in this interface. + * @param returnCode the return value of the function call. + * @param latencyMs the latency of the function call. + * @param hostname the name that was looked up. + * @param ipAddresses (possibly a subset of) the IP addresses returned. + * At most {@link #DNS_REPORTED_IP_ADDRESSES_LIMIT} addresses are logged. + * @param ipAddressesCount the number of IP addresses returned. May be different from the length + * of ipAddresses if there were too many addresses to log. + * @param uid the UID of the application that performed the query. + */ + void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs, + @utf8InCpp String hostname, in @utf8InCpp String[] ipAddresses, + int ipAddressesCount, int uid); + + /** + * Represents a private DNS validation success or failure. + * + * @param netId the ID of the network the validation was performed on. + * @param ipAddress the IP address for which validation was performed. + * @param hostname the hostname for which validation was performed. + * @param validated whether or not validation was successful. + */ + void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname, + boolean validated); + + /** + * Logs a single connect library call. + * + * @param netId the ID of the network the connect was performed on. + * @param error 0 if the connect call succeeded, otherwise errno if it failed. + * @param latencyMs the latency of the connect call. + * @param ipAddr destination IP address. + * @param port destination port number. + * @param uid the UID of the application that performed the connection. + */ + void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port, int uid); + + /** + * Logs a single RX packet which caused the main CPU to exit sleep state. + * @param prefix arbitrary string provided via wakeupAddInterface() + * @param uid UID of the destination process or -1 if no UID is available. + * @param ethertype of the RX packet encoded in an int in native order, or -1 if not available. + * @param ipNextHeader ip protocol of the RX packet as IPPROTO_* number, + or -1 if the packet was not IPv4 or IPv6. + * @param dstHw destination hardware address, or 0 if not available. + * @param srcIp source IP address, or null if not available. + * @param dstIp destination IP address, or null if not available. + * @param srcPort src port of RX packet in native order, or -1 if the packet was not UDP or TCP. + * @param dstPort dst port of RX packet in native order, or -1 if the packet was not UDP or TCP. + * @param timestampNs receive timestamp for the offending packet. In units of nanoseconds and + * synchronized to CLOCK_MONOTONIC. + */ + void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader, in byte[] dstHw, + String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs); + + /** + * An event sent after every Netlink sock_diag poll performed by Netd. This reported batch + * groups TCP socket stats aggregated by network id. Per-network data are stored in a + * structure-of-arrays style where networkIds, sentPackets, lostPackets, rttUs, and + * sentAckDiffMs have the same length. Stats for the i-th network is spread across all these + * arrays at index i. + * @param networkIds an array of network ids for which there was tcp socket stats to collect in + * the last sock_diag poll. + * @param sentPackets an array of packet sent across all TCP sockets still alive and new + TCP sockets since the last sock_diag poll, summed per network id. + * @param lostPackets, an array of packet lost across all TCP sockets still alive and new + TCP sockets since the last sock_diag poll, summed per network id. + * @param rttUs an array of smoothed round trip times in microseconds, averaged across all TCP + sockets since the last sock_diag poll for a given network id. + * @param sentAckDiffMs an array of milliseconds duration between the last packet sent and the + last ack received for a socket, averaged across all TCP sockets for a network id. + */ + void onTcpSocketStatsEvent(in int[] networkIds, in int[] sentPackets, + in int[] lostPackets, in int[] rttUs, in int[] sentAckDiffMs); + + /** + * Represents adding or removing a NAT64 prefix. + * + * @param netId the ID of the network the prefix was discovered on. + * @param added true if the NAT64 prefix was added, or false if the NAT64 prefix was removed. + * There is only one prefix at a time for each netId. If a prefix is added, it replaces + * the previous-added prefix. + * @param prefixString the detected NAT64 prefix as a string literal. + * @param prefixLength the prefix length associated with this NAT64 prefix. + */ + void onNat64PrefixEvent(int netId, boolean added, @utf8InCpp String prefixString, + int prefixLength); +} diff --git a/staticlibs/netd/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl b/staticlibs/netd/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl new file mode 100644 index 0000000000..99497a863c --- /dev/null +++ b/staticlibs/netd/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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.netd.aidl; + +import android.net.UidRangeParcel; + +/** + * The configuration to add or remove UID ranges. + * + * {@hide} + */ +@JavaDerive(toString=true, equals=true) +@JavaOnlyImmutable +parcelable NativeUidRangeConfig { + /** The network ID of the network to add/remove the ranges to/from. */ + int netId; + + /** A set of non-overlapping ranges of UIDs. */ + UidRangeParcel[] uidRanges; + + /** + * The priority of this UID range config. 0 is the highest priority; 999 is the lowest priority. + * The function of this parameter is to adjust the priority when the same UID is set to + * different networks for different features. + */ + int subPriority; +} \ No newline at end of file From 957b694ed6e156d74d0d4601d9464f480f9d06a6 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Thu, 7 Oct 2021 11:58:21 -0700 Subject: [PATCH 258/777] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/libs/net Added SPDX-license-identifier-Apache-2.0 to: common/netd/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Change-Id: Ic163988eea096e967a8d04624772b2eff350026d --- staticlibs/netd/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index c93c2fc485..530ccd30d7 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + java_library { name: "netd_aidl_interface-lateststable-java", sdk_version: "system_current", From d99cf6fe74b9fb1c3f473193d98ae83cded8b559 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 30 Jul 2021 04:30:40 +0000 Subject: [PATCH 259/777] Add data structures to parse netlink link messages. Bug: 163492391 Test: atest NetworkStaticLibsTests Change-Id: Ida8c22a782eeaca738487d0dc041a459ef6bb936 --- .../module/util/netlink/NetlinkConstants.java | 5 + .../module/util/netlink/NetlinkMessage.java | 3 + .../util/netlink/RtNetlinkLinkMessage.java | 151 +++++++++++++++++ .../module/util/netlink/StructIfinfoMsg.java | 82 +++++++++ .../net/module/util/netlink/StructNlAttr.java | 72 +++++++- .../module/util/netlink/StructNlMsgHdr.java | 2 +- .../util/netlink/ConntrackMessageTest.java | 2 +- .../netlink/RtNetlinkLinkMessageTest.java | 158 ++++++++++++++++++ .../module/util/netlink/StructNlAttrTest.java | 68 ++++++++ 9 files changed, 540 insertions(+), 3 deletions(-) create mode 100644 staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlAttrTest.java diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java index cf9d2c54b2..11aee84a40 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java @@ -70,6 +70,7 @@ public class NetlinkConstants { if (family == OsConstants.AF_INET) return "AF_INET"; if (family == OsConstants.AF_INET6) return "AF_INET6"; if (family == OsConstants.AF_NETLINK) return "AF_NETLINK"; + if (family == OsConstants.AF_UNSPEC) return "AF_UNSPEC"; return String.valueOf(family); } @@ -142,9 +143,13 @@ public class NetlinkConstants { public static final short SOCK_DIAG_BY_FAMILY = 20; // Netlink groups. + public static final int RTMGRP_LINK = 1; public static final int RTNLGRP_ND_USEROPT = 20; public static final int RTMGRP_ND_USEROPT = 1 << (RTNLGRP_ND_USEROPT - 1); + // Device flags. + public static final int IFF_LOWER_UP = 1 << 16; + /** * Convert a netlink message type to a string for control message. */ diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java index 723d6823a1..d83c12f720 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java @@ -120,6 +120,9 @@ public class NetlinkMessage { private static NetlinkMessage parseRtMessage(@NonNull StructNlMsgHdr nlmsghdr, @NonNull ByteBuffer byteBuffer) { switch (nlmsghdr.nlmsg_type) { + case NetlinkConstants.RTM_NEWLINK: + case NetlinkConstants.RTM_DELLINK: + return (NetlinkMessage) RtNetlinkLinkMessage.parse(nlmsghdr, byteBuffer); case NetlinkConstants.RTM_NEWNEIGH: case NetlinkConstants.RTM_DELNEIGH: case NetlinkConstants.RTM_GETNEIGH: diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java new file mode 100644 index 0000000000..92ec0c4e4c --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.netlink; + +import android.net.MacAddress; +import android.system.OsConstants; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +import java.nio.ByteBuffer; + +/** + * A NetlinkMessage subclass for rtnetlink link messages. + * + * RtNetlinkLinkMessage.parse() must be called with a ByteBuffer that contains exactly one netlink + * message. + * + * see also: + * + * include/uapi/linux/rtnetlink.h + * + * @hide + */ +public class RtNetlinkLinkMessage extends NetlinkMessage { + public static final short IFLA_ADDRESS = 1; + public static final short IFLA_IFNAME = 3; + public static final short IFLA_MTU = 4; + + private int mMtu; + @NonNull + private StructIfinfoMsg mIfinfomsg; + @Nullable + private MacAddress mHardwareAddress; + @Nullable + private String mInterfaceName; + + private RtNetlinkLinkMessage(@NonNull StructNlMsgHdr header) { + super(header); + mIfinfomsg = null; + mMtu = 0; + mHardwareAddress = null; + mInterfaceName = null; + } + + public int getMtu() { + return mMtu; + } + + @NonNull + public StructIfinfoMsg getIfinfoHeader() { + return mIfinfomsg; + } + + @Nullable + public MacAddress getHardwareAddress() { + return mHardwareAddress; + } + + @Nullable + public String getInterfaceName() { + return mInterfaceName; + } + + /** + * Parse rtnetlink link message from {@link ByteBuffer}. This method must be called with a + * ByteBuffer that contains exactly one netlink message. + * + * @param header netlink message header. + * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. + */ + @Nullable + public static RtNetlinkLinkMessage parse(@NonNull final StructNlMsgHdr header, + @NonNull final ByteBuffer byteBuffer) { + final RtNetlinkLinkMessage linkMsg = new RtNetlinkLinkMessage(header); + + linkMsg.mIfinfomsg = StructIfinfoMsg.parse(byteBuffer); + if (linkMsg.mIfinfomsg == null) return null; + + // IFLA_MTU + final int baseOffset = byteBuffer.position(); + StructNlAttr nlAttr = StructNlAttr.findNextAttrOfType(IFLA_MTU, byteBuffer); + if (nlAttr != null) { + linkMsg.mMtu = nlAttr.getValueAsInt(0 /* default value */); + } + + // IFLA_ADDRESS + byteBuffer.position(baseOffset); + nlAttr = StructNlAttr.findNextAttrOfType(IFLA_ADDRESS, byteBuffer); + if (nlAttr != null) { + linkMsg.mHardwareAddress = nlAttr.getValueAsMacAddress(); + } + + // IFLA_IFNAME + byteBuffer.position(baseOffset); + nlAttr = StructNlAttr.findNextAttrOfType(IFLA_IFNAME, byteBuffer); + if (nlAttr != null) { + linkMsg.mInterfaceName = nlAttr.getValueAsString(); + } + + return linkMsg; + } + + /** + * Write a rtnetlink link message to {@link ByteBuffer}. + */ + @VisibleForTesting + protected void pack(ByteBuffer byteBuffer) { + getHeader().pack(byteBuffer); + mIfinfomsg.pack(byteBuffer); + + if (mMtu != 0) { + final StructNlAttr mtu = new StructNlAttr(IFLA_MTU, mMtu); + mtu.pack(byteBuffer); + } + if (mHardwareAddress != null) { + final StructNlAttr hardwareAddress = new StructNlAttr(IFLA_ADDRESS, mHardwareAddress); + hardwareAddress.pack(byteBuffer); + } + if (mInterfaceName != null) { + final StructNlAttr ifname = new StructNlAttr(IFLA_IFNAME, mInterfaceName); + ifname.pack(byteBuffer); + } + } + + @Override + public String toString() { + return "RtNetlinkLinkMessage{ " + + "nlmsghdr{" + mHeader.toString(OsConstants.NETLINK_ROUTE) + "}, " + + "Ifinfomsg{" + mIfinfomsg.toString() + "}, " + + "Hardware Address{" + mHardwareAddress + "}, " + + "MTU{" + mMtu + "}, " + + "Ifname{" + mInterfaceName + "} " + + "}"; + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java new file mode 100644 index 0000000000..881dc18cee --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.netlink; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.nio.ByteBuffer; + +/** + * struct ifinfomsg + * + * see also: + * + * include/uapi/linux/rtnetlink.h + * + * @hide + */ +public class StructIfinfoMsg extends Struct { + // Already aligned. + public static final int STRUCT_SIZE = 16; + + @Field(order = 0, type = Type.U8, padding = 1) + public final short family; + @Field(order = 1, type = Type.U16) + public final int type; + @Field(order = 2, type = Type.S32) + public final int index; + @Field(order = 3, type = Type.U32) + public final long flags; + @Field(order = 4, type = Type.U32) + public final long change; + + StructIfinfoMsg(short family, int type, int index, long flags, long change) { + this.family = family; + this.type = type; + this.index = index; + this.flags = flags; + this.change = change; + } + + /** + * Parse a rtnetlink link message header from a {@link ByteBuffer}. + * + * @param byteBuffer The buffer from which to parse the rtnetlink link message header. + * @return the parsed rtnetlink link message header, or {@code null} if the rtnetlink message + * header could not be parsed successfully (for example, if it was truncated). + */ + @Nullable + public static StructIfinfoMsg parse(@NonNull final ByteBuffer byteBuffer) { + if (byteBuffer.remaining() < STRUCT_SIZE) return null; + + // The ByteOrder must already have been set to native order. + return StructIfinfoMsg.parse(StructIfinfoMsg.class, byteBuffer); + } + + /** + * Write ifinfomsg to {@link ByteBuffer}. + */ + public void pack(@NonNull final ByteBuffer byteBuffer) { + // The ByteOrder must already have been set to native order. + this.writeToByteBuffer(byteBuffer); + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNlAttr.java b/staticlibs/device/com/android/net/module/util/netlink/StructNlAttr.java index 80f00579bd..485e67c84d 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructNlAttr.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNlAttr.java @@ -16,12 +16,17 @@ package com.android.net.module.util.netlink; +import android.net.MacAddress; + +import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.Arrays; /** * struct nlattr @@ -173,11 +178,35 @@ public class StructNlAttr { } } - public StructNlAttr(short type, InetAddress ip) { + public StructNlAttr(short type, @NonNull final byte[] value) { + nla_type = type; + setValue(value); + } + + public StructNlAttr(short type, @NonNull final InetAddress ip) { nla_type = type; setValue(ip.getAddress()); } + public StructNlAttr(short type, @NonNull final MacAddress mac) { + nla_type = type; + setValue(mac.toByteArray()); + } + + public StructNlAttr(short type, @NonNull final String string) { + nla_type = type; + byte[] value = null; + try { + final byte[] stringBytes = string.getBytes("UTF-8"); + // Append '\0' at the end of interface name string bytes. + value = Arrays.copyOf(stringBytes, stringBytes.length + 1); + } catch (UnsupportedEncodingException ignored) { + // Do nothing. + } finally { + setValue(value); + } + } + public StructNlAttr(short type, StructNlAttr... nested) { this(); nla_type = makeNestedType(type); @@ -270,7 +299,11 @@ public class StructNlAttr { /** * Get attribute value as InetAddress. + * + * @return the InetAddress instance representation of attribute value or null if IP address + * is of illegal length. */ + @Nullable public InetAddress getValueAsInetAddress() { if (nla_value == null) return null; @@ -281,6 +314,43 @@ public class StructNlAttr { } } + /** + * Get attribute value as MacAddress. + * + * @return the MacAddress instance representation of attribute value or null if the given byte + * array is not a valid representation(e.g, not all link layers have 6-byte link-layer + * addresses) + */ + @Nullable + public MacAddress getValueAsMacAddress() { + if (nla_value == null) return null; + + try { + return MacAddress.fromBytes(nla_value); + } catch (IllegalArgumentException ignored) { + return null; + } + } + + /** + * Get attribute value as a unicode string. + * + * @return a unicode string or null if UTF-8 charset is not supported. + */ + @Nullable + public String getValueAsString() { + if (nla_value == null) return null; + // Check the attribute value length after removing string termination flag '\0'. + if (nla_value.length < (nla_len - NLA_HEADERLEN - 1)) return null; + + try { + final byte[] array = Arrays.copyOf(nla_value, nla_len - NLA_HEADERLEN - 1); + return new String(array, "UTF-8"); + } catch (UnsupportedEncodingException | NegativeArraySizeException ignored) { + return null; + } + } + /** * Write the netlink attribute to {@link ByteBuffer}. */ diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNlMsgHdr.java b/staticlibs/device/com/android/net/module/util/netlink/StructNlMsgHdr.java index 9567cce22b..5052cb8a06 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructNlMsgHdr.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNlMsgHdr.java @@ -166,7 +166,7 @@ public class StructNlMsgHdr { return "StructNlMsgHdr{ " + "nlmsg_len{" + nlmsg_len + "}, " + "nlmsg_type{" + typeStr + "}, " - + "nlmsg_flags{" + flagsStr + ")}, " + + "nlmsg_flags{" + flagsStr + "}, " + "nlmsg_seq{" + nlmsg_seq + "}, " + "nlmsg_pid{" + nlmsg_pid + "} " + "}"; diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/ConntrackMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/ConntrackMessageTest.java index cea763c75c..f02b4cb674 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/ConntrackMessageTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/ConntrackMessageTest.java @@ -422,7 +422,7 @@ public class ConntrackMessageTest { final String expected = "" + "ConntrackMessage{" + "nlmsghdr{StructNlMsgHdr{ nlmsg_len{140}, nlmsg_type{256(IPCTNL_MSG_CT_NEW)}, " - + "nlmsg_flags{1536(NLM_F_MATCH))}, nlmsg_seq{0}, nlmsg_pid{0} }}, " + + "nlmsg_flags{1536(NLM_F_MATCH)}, nlmsg_seq{0}, nlmsg_pid{0} }}, " + "nfgenmsg{NfGenMsg{ nfgen_family{AF_INET}, version{0}, res_id{4660} }}, " + "tuple_orig{Tuple{IPPROTO_TCP: 192.168.80.12:62449 -> 140.112.8.116:443}}, " + "tuple_reply{Tuple{IPPROTO_TCP: 140.112.8.116:443 -> 100.81.179.1:62449}}, " diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java new file mode 100644 index 0000000000..58a7478131 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.netlink; + +import static android.system.OsConstants.NETLINK_ROUTE; + +import static com.android.net.module.util.NetworkStackConstants.ETHER_MTU; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.net.MacAddress; +import android.system.OsConstants; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.net.module.util.HexDump; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class RtNetlinkLinkMessageTest { + private static final String TAG = "RtNetlinkLinkMessageTest"; + + // An example of the full RTM_NEWLINK message. + private static final String RTM_NEWLINK_HEX = + "64000000100000000000000000000000" // struct nlmsghr + + "000001001E0000000210000000000000" // struct ifinfo + + "0A000300776C616E30000000" // IFLA_IFNAME + + "08000D00B80B0000" // IFLA_PROTINFO + + "0500100002000000" // IFLA_OPERSTATE + + "0500110001000000" // IFLA_LINKMODE + + "08000400DC050000" // IFLA_MTU + + "0A00010092C3E3C9374E0000" // IFLA_ADDRESS + + "0A000200FFFFFFFFFFFF0000"; // IFLA_BROADCAST + + private ByteBuffer toByteBuffer(final String hexString) { + return ByteBuffer.wrap(HexDump.hexStringToByteArray(hexString)); + } + + @Test + public void testParseRtmNewLink() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWLINK_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkLinkMessage); + final RtNetlinkLinkMessage linkMsg = (RtNetlinkLinkMessage) msg; + + final StructNlMsgHdr hdr = linkMsg.getHeader(); + assertNotNull(hdr); + assertEquals(100, hdr.nlmsg_len); + assertEquals(NetlinkConstants.RTM_NEWLINK, hdr.nlmsg_type); + assertEquals(0, hdr.nlmsg_flags); + assertEquals(0, hdr.nlmsg_seq); + assertEquals(0, hdr.nlmsg_pid); + + final StructIfinfoMsg ifinfomsgHdr = linkMsg.getIfinfoHeader(); + assertNotNull(ifinfomsgHdr); + assertEquals((byte) OsConstants.AF_UNSPEC, ifinfomsgHdr.family); + assertEquals(OsConstants.ARPHRD_ETHER, ifinfomsgHdr.type); + assertEquals(30, ifinfomsgHdr.index); + assertEquals(0, ifinfomsgHdr.change); + + assertEquals(ETHER_MTU, linkMsg.getMtu()); + assertEquals(MacAddress.fromString("92:C3:E3:C9:37:4E"), linkMsg.getHardwareAddress()); + assertTrue(linkMsg.getInterfaceName().equals("wlan0")); + } + + private static final String RTM_NEWLINK_PACK_HEX = + "34000000100000000000000000000000" // struct nlmsghr + + "000001001E0000000210000000000000" // struct ifinfo + + "08000400DC050000" // IFLA_MTU + + "0A00010092C3E3C9374E0000" // IFLA_ADDRESS + + "0A000300776C616E30000000"; // IFLA_IFNAME + + @Test + public void testPackRtmNewLink() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWLINK_PACK_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkLinkMessage); + final RtNetlinkLinkMessage linkMsg = (RtNetlinkLinkMessage) msg; + + final ByteBuffer packBuffer = ByteBuffer.allocate(64); + packBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + linkMsg.pack(packBuffer); + assertEquals(RTM_NEWLINK_PACK_HEX, HexDump.toHexString(packBuffer.array())); + } + + private static final String RTM_NEWLINK_TRUNCATED_HEX = + "54000000100000000000000000000000" // struct nlmsghr + + "000001001E0000000210000000000000" // struct ifinfo + + "08000D00B80B0000" // IFLA_PROTINFO + + "0500100002000000" // IFLA_OPERSTATE + + "0800010092C3E3C9" // IFLA_ADDRESS(truncated) + + "0500110001000000" // IFLA_LINKMODE + + "0A000300776C616E30000000" // IFLA_IFNAME + + "08000400DC050000"; // IFLA_MTU + + @Test + public void testTruncatedRtmNewLink() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWLINK_TRUNCATED_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkLinkMessage); + final RtNetlinkLinkMessage linkMsg = (RtNetlinkLinkMessage) msg; + + // Truncated IFLA_ADDRESS attribute doesn't affect parsing other attrs. + assertNull(linkMsg.getHardwareAddress()); + assertEquals(ETHER_MTU, linkMsg.getMtu()); + assertTrue(linkMsg.getInterfaceName().equals("wlan0")); + } + + @Test + public void testToString() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWLINK_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkLinkMessage); + final RtNetlinkLinkMessage linkMsg = (RtNetlinkLinkMessage) msg; + final String expected = "RtNetlinkLinkMessage{ " + + "nlmsghdr{" + + "StructNlMsgHdr{ nlmsg_len{100}, nlmsg_type{16(RTM_NEWLINK)}, nlmsg_flags{0()}, " + + "nlmsg_seq{0}, nlmsg_pid{0} }}, " + + "Ifinfomsg{" + + "family: 0, type: 1, index: 30, flags: 4098, change: 0}, " + + "Hardware Address{92:c3:e3:c9:37:4e}, " + "MTU{1500}, " + + "Ifname{wlan0} " + + "}"; + assertEquals(expected, linkMsg.toString()); + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlAttrTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlAttrTest.java new file mode 100644 index 0000000000..72e179bc2e --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlAttrTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.netlink; + +import static com.android.net.module.util.netlink.RtNetlinkLinkMessage.IFLA_ADDRESS; +import static com.android.net.module.util.netlink.RtNetlinkLinkMessage.IFLA_IFNAME; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import android.net.MacAddress; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class StructNlAttrTest { + private static final MacAddress TEST_MAC_ADDRESS = MacAddress.fromString("00:11:22:33:44:55"); + private static final String TEST_INTERFACE_NAME = "wlan0"; + + @Test + public void testGetValueAsMacAddress() { + final StructNlAttr attr1 = new StructNlAttr(IFLA_ADDRESS, TEST_MAC_ADDRESS); + final MacAddress address1 = attr1.getValueAsMacAddress(); + assertEquals(address1, TEST_MAC_ADDRESS); + + // Invalid mac address byte array. + final byte[] array = new byte[] { + (byte) 0x00, (byte) 0x11, (byte) 0x22, (byte) 0x33, + (byte) 0x44, (byte) 0x55, (byte) 0x66, + }; + final StructNlAttr attr2 = new StructNlAttr(IFLA_ADDRESS, array); + final MacAddress address2 = attr2.getValueAsMacAddress(); + assertNull(address2); + } + + @Test + public void testGetValueAsString() { + final StructNlAttr attr1 = new StructNlAttr(IFLA_IFNAME, TEST_INTERFACE_NAME); + final String str1 = attr1.getValueAsString(); + assertEquals(str1, TEST_INTERFACE_NAME); + + final byte[] array = new byte[] { + (byte) 0x77, (byte) 0x6c, (byte) 0x61, (byte) 0x6E, (byte) 0x30, (byte) 0x00, + }; + final StructNlAttr attr2 = new StructNlAttr(IFLA_IFNAME, array); + final String str2 = attr2.getValueAsString(); + assertEquals(str2, TEST_INTERFACE_NAME); + } +} From ec363d1d50e5a02612df0456cd8d081b4925917d Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 18 Oct 2021 14:33:37 +0800 Subject: [PATCH 260/777] Add a withCleanCallingIdentity equivalent to module utils Binder#withCleanCallingIdentity is a very useful utility but it's not public and won't be made public. Thus, make one in the connectivity module utils for later use. Test: TH Fix: 177369996 Change-Id: I3fd0949b7457f9d8bca8613c2bae7ef7a35a5c4c --- .../android/net/module/util/BinderUtils.java | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 staticlibs/framework/com/android/net/module/util/BinderUtils.java diff --git a/staticlibs/framework/com/android/net/module/util/BinderUtils.java b/staticlibs/framework/com/android/net/module/util/BinderUtils.java new file mode 100644 index 0000000000..eb695d1f9d --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/BinderUtils.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util; + +import android.annotation.NonNull; +import android.os.Binder; + +/** + * Collection of utilities for {@link Binder} and related classes. + * @hide + */ +public class BinderUtils { + /** + * Convenience method for running the provided action enclosed in + * {@link Binder#clearCallingIdentity}/{@link Binder#restoreCallingIdentity} + * + * Any exception thrown by the given action will be caught and rethrown after the call to + * {@link Binder#restoreCallingIdentity} + * + * Note that this is copied from Binder#withCleanCallingIdentity with minor changes + * since it is not public. + * + * @hide + */ + public static final void withCleanCallingIdentity( + @NonNull ThrowingRunnable action) throws T { + final long callingIdentity = Binder.clearCallingIdentity(); + try { + action.run(); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + } + + /** + * Like a Runnable, but declared to throw an exception. + * + * @param The exception class which is declared to be thrown. + */ + @FunctionalInterface + public interface ThrowingRunnable { + /** @see java.lang.Runnable */ + void run() throws T; + } +} From ae05481b9a04adcc3145f7c691df23e3722c6525 Mon Sep 17 00:00:00 2001 From: Tyler Wear Date: Tue, 12 Oct 2021 11:01:56 -0700 Subject: [PATCH 261/777] export bpf headers to Connectivity Service Export BPF headers to connectivity service for use with VendorConnectivityService aidl. Bug: 179733303 Change-Id: Ibc098facde54aeb621e53b73ac59eb6416ba9ebb --- staticlibs/native/bpf_syscall_wrappers/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index befb9f8fd1..136342c7a8 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -33,6 +33,7 @@ cc_library_headers { "com.android.tethering", ], visibility: [ + "//packages/modules/Connectivity/service", "//packages/modules/Connectivity/Tethering", "//system/bpf/libbpf_android", "//system/memory/lmkd", From c81f6db429de3ac19382a1fbf8f3cbf85a32c4c1 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 11 Aug 2021 02:26:28 +0000 Subject: [PATCH 262/777] Add data structures to parse netlink IP address messages. Bug: 163492391 Test: atest NetworkStaticLibsTests Change-Id: I85f1b80925fa4a9397df931902d6de189902da72 --- .../module/util/netlink/NetlinkConstants.java | 2 + .../module/util/netlink/NetlinkMessage.java | 3 + .../util/netlink/RtNetlinkAddressMessage.java | 157 ++++++++++++++++++ .../util/netlink/StructIfacacheInfo.java | 79 +++++++++ .../module/util/netlink/StructIfaddrMsg.java | 82 +++++++++ .../module/util/netlink/StructIfinfoMsg.java | 12 +- .../netlink/RtNetlinkAddressMessageTest.java | 151 +++++++++++++++++ .../netlink/RtNetlinkLinkMessageTest.java | 1 - 8 files changed, 480 insertions(+), 7 deletions(-) create mode 100644 staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/StructIfacacheInfo.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/StructIfaddrMsg.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java index 11aee84a40..07b52d8c98 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java @@ -144,6 +144,8 @@ public class NetlinkConstants { // Netlink groups. public static final int RTMGRP_LINK = 1; + public static final int RTMGRP_IPV4_IFADDR = 0x10; + public static final int RTMGRP_IPV6_IFADDR = 0x100; public static final int RTNLGRP_ND_USEROPT = 20; public static final int RTMGRP_ND_USEROPT = 1 << (RTNLGRP_ND_USEROPT - 1); diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java index d83c12f720..708736e54a 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java @@ -123,6 +123,9 @@ public class NetlinkMessage { case NetlinkConstants.RTM_NEWLINK: case NetlinkConstants.RTM_DELLINK: return (NetlinkMessage) RtNetlinkLinkMessage.parse(nlmsghdr, byteBuffer); + case NetlinkConstants.RTM_NEWADDR: + case NetlinkConstants.RTM_DELADDR: + return (NetlinkMessage) RtNetlinkAddressMessage.parse(nlmsghdr, byteBuffer); case NetlinkConstants.RTM_NEWNEIGH: case NetlinkConstants.RTM_DELNEIGH: case NetlinkConstants.RTM_GETNEIGH: diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java new file mode 100644 index 0000000000..a518c76b6b --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.netlink; + +import android.system.OsConstants; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +import com.android.net.module.util.HexDump; + +import java.net.InetAddress; +import java.nio.ByteBuffer; + +/** + * A NetlinkMessage subclass for rtnetlink address messages. + * + * RtNetlinkAddressMessage.parse() must be called with a ByteBuffer that contains exactly one + * netlink message. + * + * see also: + * + * include/uapi/linux/rtnetlink.h + * + * @hide + */ +public class RtNetlinkAddressMessage extends NetlinkMessage { + public static final short IFA_ADDRESS = 1; + public static final short IFA_CACHEINFO = 6; + public static final short IFA_FLAGS = 8; + + private int mFlags; + @NonNull + private StructIfaddrMsg mIfaddrmsg; + @NonNull + private InetAddress mIpAddress; + @Nullable + private StructIfacacheInfo mIfacacheInfo; + + private RtNetlinkAddressMessage(@NonNull StructNlMsgHdr header) { + super(header); + mIfaddrmsg = null; + mIpAddress = null; + mIfacacheInfo = null; + mFlags = 0; + } + + public int getFlags() { + return mFlags; + } + + @NonNull + public StructIfaddrMsg getIfaddrHeader() { + return mIfaddrmsg; + } + + @NonNull + public InetAddress getIpAddress() { + return mIpAddress; + } + + @Nullable + public StructIfacacheInfo getIfacacheInfo() { + return mIfacacheInfo; + } + + /** + * Parse rtnetlink address message from {@link ByteBuffer}. This method must be called with a + * ByteBuffer that contains exactly one netlink message. + * + * @param header netlink message header. + * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. + */ + @Nullable + public static RtNetlinkAddressMessage parse(@NonNull final StructNlMsgHdr header, + @NonNull final ByteBuffer byteBuffer) { + final RtNetlinkAddressMessage addrMsg = new RtNetlinkAddressMessage(header); + + addrMsg.mIfaddrmsg = StructIfaddrMsg.parse(byteBuffer); + if (addrMsg.mIfaddrmsg == null) return null; + + // IFA_ADDRESS + final int baseOffset = byteBuffer.position(); + StructNlAttr nlAttr = StructNlAttr.findNextAttrOfType(IFA_ADDRESS, byteBuffer); + if (nlAttr == null) return null; + addrMsg.mIpAddress = nlAttr.getValueAsInetAddress(); + if (addrMsg.mIpAddress == null) return null; + + // IFA_CACHEINFO + byteBuffer.position(baseOffset); + nlAttr = StructNlAttr.findNextAttrOfType(IFA_CACHEINFO, byteBuffer); + if (nlAttr != null) { + addrMsg.mIfacacheInfo = StructIfacacheInfo.parse(nlAttr.getValueAsByteBuffer()); + } + + // The first 8 bits of flags are in the ifaddrmsg. + addrMsg.mFlags = addrMsg.mIfaddrmsg.flags; + // IFA_FLAGS. All the flags are in the IF_FLAGS attribute. This should always be present, + // and will overwrite the flags set above. + byteBuffer.position(baseOffset); + nlAttr = StructNlAttr.findNextAttrOfType(IFA_FLAGS, byteBuffer); + if (nlAttr != null) { + addrMsg.mFlags = nlAttr.getValueAsInt(0 /* default value */); + } + + return addrMsg; + } + + /** + * Write a rtnetlink address message to {@link ByteBuffer}. + */ + @VisibleForTesting + protected void pack(ByteBuffer byteBuffer) { + getHeader().pack(byteBuffer); + mIfaddrmsg.pack(byteBuffer); + + final StructNlAttr address = new StructNlAttr(IFA_ADDRESS, mIpAddress); + address.pack(byteBuffer); + + if (mIfacacheInfo != null) { + final StructNlAttr cacheInfo = new StructNlAttr(IFA_CACHEINFO, + mIfacacheInfo.writeToBytes()); + cacheInfo.pack(byteBuffer); + } + + // If IFA_FLAGS attribute isn't present on the wire at parsing netlink message, it will + // still be packed to ByteBuffer even if the flag is 0. + final StructNlAttr flags = new StructNlAttr(IFA_FLAGS, mFlags); + flags.pack(byteBuffer); + } + + @Override + public String toString() { + return "RtNetlinkAddressMessage{ " + + "nlmsghdr{" + mHeader.toString(OsConstants.NETLINK_ROUTE) + "}, " + + "Ifaddrmsg{" + mIfaddrmsg.toString() + "}, " + + "IP Address{" + mIpAddress.getHostAddress() + "}, " + + "IfacacheInfo{" + (mIfacacheInfo == null ? "" : mIfacacheInfo.toString()) + "}, " + + "Address Flags{" + HexDump.toHexString(mFlags) + "} " + + "}"; + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructIfacacheInfo.java b/staticlibs/device/com/android/net/module/util/netlink/StructIfacacheInfo.java new file mode 100644 index 0000000000..360f56d268 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/StructIfacacheInfo.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.netlink; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.nio.ByteBuffer; + +/** + * struct ifa_cacheinfo + * + * see also: + * + * include/uapi/linux/if_addr.h + * + * @hide + */ +public class StructIfacacheInfo extends Struct { + // Already aligned. + public static final int STRUCT_SIZE = 16; + + @Field(order = 0, type = Type.U32) + public final long preferred; + @Field(order = 1, type = Type.U32) + public final long valid; + @Field(order = 2, type = Type.U32) + public final long cstamp; // created timestamp, hundredths of seconds. + @Field(order = 3, type = Type.U32) + public final long tstamp; // updated timestamp, hundredths of seconds. + + StructIfacacheInfo(long preferred, long valid, long cstamp, long tstamp) { + this.preferred = preferred; + this.valid = valid; + this.cstamp = cstamp; + this.tstamp = tstamp; + } + + /** + * Parse an ifa_cacheinfo struct from a {@link ByteBuffer}. + * + * @param byteBuffer The buffer from which to parse the ifa_cacheinfo. + * @return the parsed ifa_cacheinfo struct, or {@code null} if the ifa_cacheinfo struct + * could not be parsed successfully (for example, if it was truncated). + */ + @Nullable + public static StructIfacacheInfo parse(@NonNull final ByteBuffer byteBuffer) { + if (byteBuffer.remaining() < STRUCT_SIZE) return null; + + // The ByteOrder must already have been set to native order. + return Struct.parse(StructIfacacheInfo.class, byteBuffer); + } + + /** + * Write an ifa_cacheinfo struct to {@link ByteBuffer}. + */ + public void pack(@NonNull final ByteBuffer byteBuffer) { + // The ByteOrder must already have been set to native order. + this.writeToByteBuffer(byteBuffer); + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructIfaddrMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructIfaddrMsg.java new file mode 100644 index 0000000000..9196feba20 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/StructIfaddrMsg.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.netlink; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.nio.ByteBuffer; + +/** + * struct ifaddrmsg + * + * see also: + * + * include/uapi/linux/if_addr.h + * + * @hide + */ +public class StructIfaddrMsg extends Struct { + // Already aligned. + public static final int STRUCT_SIZE = 8; + + @Field(order = 0, type = Type.U8) + public final short family; + @Field(order = 1, type = Type.U8) + public final short prefixLen; + @Field(order = 2, type = Type.U8) + public final short flags; + @Field(order = 3, type = Type.U8) + public final short scope; + @Field(order = 4, type = Type.S32) + public final int index; + + StructIfaddrMsg(short family, short prefixLen, short flags, short scope, int index) { + this.family = family; + this.prefixLen = prefixLen; + this.flags = flags; + this.scope = scope; + this.index = index; + } + + /** + * Parse an ifaddrmsg struct from a {@link ByteBuffer}. + * + * @param byteBuffer The buffer from which to parse the ifaddrmsg. + * @return the parsed ifaddrmsg struct, or {@code null} if the ifaddrmsg struct + * could not be parsed successfully (for example, if it was truncated). + */ + @Nullable + public static StructIfaddrMsg parse(@NonNull final ByteBuffer byteBuffer) { + if (byteBuffer.remaining() < STRUCT_SIZE) return null; + + // The ByteOrder must already have been set to native order. + return Struct.parse(StructIfaddrMsg.class, byteBuffer); + } + + /** + * Write an ifaddrmsg struct to {@link ByteBuffer}. + */ + public void pack(@NonNull final ByteBuffer byteBuffer) { + // The ByteOrder must already have been set to native order. + this.writeToByteBuffer(byteBuffer); + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java index 881dc18cee..02d1574bff 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java @@ -58,22 +58,22 @@ public class StructIfinfoMsg extends Struct { } /** - * Parse a rtnetlink link message header from a {@link ByteBuffer}. + * Parse an ifinfomsg struct from a {@link ByteBuffer}. * - * @param byteBuffer The buffer from which to parse the rtnetlink link message header. - * @return the parsed rtnetlink link message header, or {@code null} if the rtnetlink message - * header could not be parsed successfully (for example, if it was truncated). + * @param byteBuffer The buffer from which to parse the ifinfomsg. + * @return the parsed ifinfomsg struct, or {@code null} if the ifinfomsg struct + * could not be parsed successfully (for example, if it was truncated). */ @Nullable public static StructIfinfoMsg parse(@NonNull final ByteBuffer byteBuffer) { if (byteBuffer.remaining() < STRUCT_SIZE) return null; // The ByteOrder must already have been set to native order. - return StructIfinfoMsg.parse(StructIfinfoMsg.class, byteBuffer); + return Struct.parse(StructIfinfoMsg.class, byteBuffer); } /** - * Write ifinfomsg to {@link ByteBuffer}. + * Write an ifinfomsg struct to {@link ByteBuffer}. */ public void pack(@NonNull final ByteBuffer byteBuffer) { // The ByteOrder must already have been set to native order. diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java new file mode 100644 index 0000000000..7d8dbd2bbb --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.netlink; + +import static android.system.OsConstants.NETLINK_ROUTE; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.net.InetAddresses; +import android.system.OsConstants; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.net.module.util.HexDump; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet6Address; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class RtNetlinkAddressMessageTest { + private static final Inet6Address TEST_LINK_LOCAL = + (Inet6Address) InetAddresses.parseNumericAddress("fe80::2C41:5CFF:FE09:6665"); + + // An example of the full RTM_NEWADDR message. + private static final String RTM_NEWADDR_HEX = + "48000000140000000000000000000000" // struct nlmsghr + + "0A4080FD1E000000" // struct ifaddrmsg + + "14000100FE800000000000002C415CFFFE096665" // IFA_ADDRESS + + "14000600100E0000201C00002A70000045700000" // IFA_CACHEINFO + + "0800080080000000"; // IFA_FLAGS + + private ByteBuffer toByteBuffer(final String hexString) { + return ByteBuffer.wrap(HexDump.hexStringToByteArray(hexString)); + } + + @Test + public void testParseRtmNewAddress() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWADDR_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkAddressMessage); + final RtNetlinkAddressMessage addrMsg = (RtNetlinkAddressMessage) msg; + + final StructNlMsgHdr hdr = addrMsg.getHeader(); + assertNotNull(hdr); + assertEquals(72, hdr.nlmsg_len); + assertEquals(NetlinkConstants.RTM_NEWADDR, hdr.nlmsg_type); + assertEquals(0, hdr.nlmsg_flags); + assertEquals(0, hdr.nlmsg_seq); + assertEquals(0, hdr.nlmsg_pid); + + final StructIfaddrMsg ifaddrMsgHdr = addrMsg.getIfaddrHeader(); + assertNotNull(ifaddrMsgHdr); + assertEquals((byte) OsConstants.AF_INET6, ifaddrMsgHdr.family); + assertEquals(64, ifaddrMsgHdr.prefixLen); + assertEquals(0x80, ifaddrMsgHdr.flags); + assertEquals(0xFD, ifaddrMsgHdr.scope); + assertEquals(30, ifaddrMsgHdr.index); + + assertEquals((Inet6Address) addrMsg.getIpAddress(), TEST_LINK_LOCAL); + assertEquals(3600L, addrMsg.getIfacacheInfo().preferred); + assertEquals(7200L, addrMsg.getIfacacheInfo().valid); + assertEquals(28714, addrMsg.getIfacacheInfo().cstamp); + assertEquals(28741, addrMsg.getIfacacheInfo().tstamp); + assertEquals(0x80, addrMsg.getFlags()); + } + + private static final String RTM_NEWADDR_PACK_HEX = + "48000000140000000000000000000000" // struct nlmsghr + + "0A4080FD1E000000" // struct ifaddrmsg + + "14000100FE800000000000002C415CFFFE096665" // IFA_ADDRESS + + "14000600FFFFFFFFFFFFFFFF2A7000002A700000" // IFA_CACHEINFO + + "0800080081000000"; // IFA_FLAGS(override ifa_flags) + + @Test + public void testPackRtmNewAddr() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWADDR_PACK_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkAddressMessage); + final RtNetlinkAddressMessage addrMsg = (RtNetlinkAddressMessage) msg; + + final ByteBuffer packBuffer = ByteBuffer.allocate(72); + packBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + addrMsg.pack(packBuffer); + assertEquals(RTM_NEWADDR_PACK_HEX, HexDump.toHexString(packBuffer.array())); + } + + private static final String RTM_NEWADDR_TRUNCATED_HEX = + "44000000140000000000000000000000" // struct nlmsghr + + "0A4080FD1E000000" // struct ifaddrmsg + + "10000100FE800000000000002C415CFF" // IFA_ADDRESS(truncated) + + "14000600FFFFFFFFFFFFFFFF2A7000002A700000" // IFA_CACHEINFO + + "0800080080000000"; // IFA_FLAGS + + @Test + public void testTruncatedRtmNewAddr() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWADDR_TRUNCATED_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + // Parsing RTM_NEWADDR with truncated IFA_ADDRESS attribute returns null. + assertNull(msg); + } + + @Test + public void testToString() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWADDR_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkAddressMessage); + final RtNetlinkAddressMessage addrMsg = (RtNetlinkAddressMessage) msg; + final String expected = "RtNetlinkAddressMessage{ " + + "nlmsghdr{" + + "StructNlMsgHdr{ nlmsg_len{72}, nlmsg_type{20(RTM_NEWADDR)}, nlmsg_flags{0()}, " + + "nlmsg_seq{0}, nlmsg_pid{0} }}, " + + "Ifaddrmsg{" + + "family: 10, prefixLen: 64, flags: 128, scope: 253, index: 30}, " + + "IP Address{fe80::2c41:5cff:fe09:6665}, " + + "IfacacheInfo{" + + "preferred: 3600, valid: 7200, cstamp: 28714, tstamp: 28741}, " + + "Address Flags{00000080} " + + "}"; + assertEquals(expected, addrMsg.toString()); + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java index 58a7478131..5d446b878d 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java @@ -42,7 +42,6 @@ import java.nio.ByteOrder; @RunWith(AndroidJUnit4.class) @SmallTest public class RtNetlinkLinkMessageTest { - private static final String TAG = "RtNetlinkLinkMessageTest"; // An example of the full RTM_NEWLINK message. private static final String RTM_NEWLINK_HEX = From b61091b30be395aa4e9893ba042c3338935c77ac Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 7 Oct 2021 15:29:13 +0900 Subject: [PATCH 263/777] Move static utils to the static library MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These classes used to live as a static utility in the NetworkStack module, but that's not the right place for them. The point of this patch is to *not* require topics, as any change in this space will very quickly spin out of control and become unmanageable. As such, this starts with creating equivalent classes in a single, easier to manage change. Followup changes will migrate users of the old classes to use these ones instead. Finally, the old classes can be removed. This way, work can be broken down into separate changes and be checked in little by little, rather than one huge topic with many changes doing everything in one go, which is unlikely to be manageable. There are no code changes from the originals, but a number of reorganizations, most of them unavoidable. • Vertical spacing (these classes fix it) • Package names/imports are adjusted • Added @hide on NetlinkMonitor • Move all contents of RouteUtils to NetdUtils, because all methods depend on INetd, and some of the targets do not/cannot depend on netd-client • Restrict the files used by the filegroup net-utils-framework-wifi-common-srcs, since that target does not necessarily provide all dependencies to all its users. • Don't move NetworkMonitorUtils, since it depends on SdkLevel, and net-utils-framework-common-srcs is using **/*.java. It would have been possible to list explicitly all files actually necessary in this filegroup, but NetworkMonitorUtils is actually only used by the networking modules and not the framework. Eventually it should move but it doesn't have to be in this patch, which is complicated enough as it is. • RouteUtils is now empty, because some new methods will be added to it soon and it is less expensive to keep it empty than to remove it now and add it again later. • Merge NetdUtils, and unify the constants. Some changes to satisfy checkstyle : • Remove unused imports • Reorder modifiers in InterfaceController • Remove {} in IpNetworkMonitor • Remove redundant public modifier in IpNetworkMonitor • Add javadoc to a few methods • Add whitespace around | in InterfaceParams However, don't rename members in IpNeighborMonitor like checkstyle would prefer because this would make migration to this more involved. Test: NetworkStaticLibsTests NetdStaticLibTests Change-Id: I439121cba5d7ea95aa4d6c80ea25207c316880a0 --- staticlibs/Android.bp | 39 +- .../android/net/module/util/SharedLog.java | 232 ++++++++++++ .../net/module/util/ip/ConntrackMonitor.java | 203 +++++++++++ .../module/util/ip/InterfaceController.java | 211 +++++++++++ .../net/module/util/ip/IpNeighborMonitor.java | 189 ++++++++++ .../net/module/util/ip/NetlinkMonitor.java | 166 +++++++++ .../net/module/util/InterfaceParams.java | 105 ++++++ .../android/net/module/util/RouteUtils.java | 23 ++ staticlibs/tests/unit/Android.bp | 2 + .../net/module/util/SharedLogTest.java | 95 +++++ .../module/util/ip/ConntrackMonitorTest.java | 336 ++++++++++++++++++ .../util/ip/InterfaceControllerTest.java | 90 +++++ 12 files changed, 1689 insertions(+), 2 deletions(-) create mode 100644 staticlibs/device/com/android/net/module/util/SharedLog.java create mode 100644 staticlibs/device/com/android/net/module/util/ip/ConntrackMonitor.java create mode 100644 staticlibs/device/com/android/net/module/util/ip/InterfaceController.java create mode 100644 staticlibs/device/com/android/net/module/util/ip/IpNeighborMonitor.java create mode 100644 staticlibs/device/com/android/net/module/util/ip/NetlinkMonitor.java create mode 100644 staticlibs/framework/com/android/net/module/util/InterfaceParams.java create mode 100644 staticlibs/framework/com/android/net/module/util/RouteUtils.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/SharedLogTest.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/ip/ConntrackMonitorTest.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/ip/InterfaceControllerTest.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index a7a027cb38..4fc93ce7a2 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -38,6 +38,7 @@ java_library { "device/com/android/net/module/util/FdEventsReader.java", "device/com/android/net/module/util/HexDump.java", "device/com/android/net/module/util/PacketReader.java", + "device/com/android/net/module/util/SharedLog.java", // This library is used by system modules, for which the system health impact of Kotlin // has not yet been evaluated. Annotations may need jarjar'ing. // "src_devicecommon/**/*.kt", @@ -95,7 +96,7 @@ filegroup { java_library { name: "net-utils-device-common-netlink", - // TODO: Ipv6Utils and Struct stuff could be separated out of th netlink library into + // TODO: Ipv6Utils and Struct stuff could be separated out of the netlink library into // an individual Struct library, and remove the net-utils-framework-common lib dependency. // But there is no need doing this at the moment. srcs: [ @@ -124,6 +125,36 @@ java_library { ], } +java_library { + // TODO : this target should probably be folded into net-utils-device-common + name: "net-utils-device-common-ip", + srcs: [ + "device/com/android/net/module/util/ip/*.java", + ], + sdk_version: "module_current", + min_sdk_version: "29", + visibility: [ + "//frameworks/libs/net/common/tests:__subpackages__", + "//frameworks/libs/net/common/testutils:__subpackages__", + "//packages/modules/Connectivity:__subpackages__", + "//packages/modules/NetworkStack:__subpackages__", + ], + libs: [ + "framework-annotations-lib", + "framework-connectivity", + ], + static_libs: [ + "net-utils-device-common", + "net-utils-device-common-netlink", + "net-utils-framework-common", + "netd-client", + ], + apex_available: [ + "com.android.tethering", + "//apex_available:platform", + ], +} + java_library { name: "net-utils-framework-common", srcs: [ @@ -205,7 +236,11 @@ filegroup { filegroup { name: "net-utils-framework-wifi-common-srcs", srcs: [ - "framework/com/android/net/module/util/**/*.java", + "framework/com/android/net/module/util/DnsSdTxtRecord.java", + "framework/com/android/net/module/util/Inet4AddressUtils.java", + "framework/com/android/net/module/util/InetAddressUtils.java", + "framework/com/android/net/module/util/MacAddressUtils.java", + "framework/com/android/net/module/util/NetUtils.java", ], path: "framework", visibility: [ diff --git a/staticlibs/device/com/android/net/module/util/SharedLog.java b/staticlibs/device/com/android/net/module/util/SharedLog.java new file mode 100644 index 0000000000..37c6f6dc23 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/SharedLog.java @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2017 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 com.android.net.module.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.text.TextUtils; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.time.LocalDateTime; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.StringJoiner; + + +/** + * Class to centralize logging functionality for tethering. + * + * All access to class methods other than dump() must be on the same thread. + * + * @hide + */ +public class SharedLog { + private static final int DEFAULT_MAX_RECORDS = 500; + private static final String COMPONENT_DELIMITER = "."; + + private enum Category { + NONE, + ERROR, + MARK, + WARN, + } + + private final LocalLog mLocalLog; + // The tag to use for output to the system log. This is not output to the + // LocalLog because that would be redundant. + private final String mTag; + // The component (or subcomponent) of a system that is sharing this log. + // This can grow in depth if components call forSubComponent() to obtain + // their SharedLog instance. The tag is not included in the component for + // brevity. + private final String mComponent; + + public SharedLog(String tag) { + this(DEFAULT_MAX_RECORDS, tag); + } + + public SharedLog(int maxRecords, String tag) { + this(new LocalLog(maxRecords), tag, tag); + } + + private SharedLog(LocalLog localLog, String tag, String component) { + mLocalLog = localLog; + mTag = tag; + mComponent = component; + } + + public String getTag() { + return mTag; + } + + /** + * Create a SharedLog based on this log with an additional component prefix on each logged line. + */ + public SharedLog forSubComponent(String component) { + if (!isRootLogInstance()) { + component = mComponent + COMPONENT_DELIMITER + component; + } + return new SharedLog(mLocalLog, mTag, component); + } + + /** + * Dump the contents of this log. + * + *

This method may be called on any thread. + */ + public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + mLocalLog.dump(writer); + } + + ////// + // Methods that both log an entry and emit it to the system log. + ////// + + /** + * Log an error due to an exception. This does not include the exception stacktrace. + * + *

The log entry will be also added to the system log. + * @see #e(String, Throwable) + */ + public void e(Exception e) { + Log.e(mTag, record(Category.ERROR, e.toString())); + } + + /** + * Log an error message. + * + *

The log entry will be also added to the system log. + */ + public void e(String msg) { + Log.e(mTag, record(Category.ERROR, msg)); + } + + /** + * Log an error due to an exception, with the exception stacktrace if provided. + * + *

The error and exception message appear in the shared log, but the stacktrace is only + * logged in general log output (logcat). The log entry will be also added to the system log. + */ + public void e(@NonNull String msg, @Nullable Throwable exception) { + if (exception == null) { + e(msg); + return; + } + Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception); + } + + /** + * Log an informational message. + * + *

The log entry will be also added to the system log. + */ + public void i(String msg) { + Log.i(mTag, record(Category.NONE, msg)); + } + + /** + * Log a warning message. + * + *

The log entry will be also added to the system log. + */ + public void w(String msg) { + Log.w(mTag, record(Category.WARN, msg)); + } + + ////// + // Methods that only log an entry (and do NOT emit to the system log). + ////// + + /** + * Log a general message to be only included in the in-memory log. + * + *

The log entry will *not* be added to the system log. + */ + public void log(String msg) { + record(Category.NONE, msg); + } + + /** + * Log a general, formatted message to be only included in the in-memory log. + * + *

The log entry will *not* be added to the system log. + * @see String#format(String, Object...) + */ + public void logf(String fmt, Object... args) { + log(String.format(fmt, args)); + } + + /** + * Log a message with MARK level. + * + *

The log entry will *not* be added to the system log. + */ + public void mark(String msg) { + record(Category.MARK, msg); + } + + private String record(Category category, String msg) { + final String entry = logLine(category, msg); + mLocalLog.append(entry); + return entry; + } + + private String logLine(Category category, String msg) { + final StringJoiner sj = new StringJoiner(" "); + if (!isRootLogInstance()) sj.add("[" + mComponent + "]"); + if (category != Category.NONE) sj.add(category.toString()); + return sj.add(msg).toString(); + } + + // Check whether this SharedLog instance is nominally the top level in + // a potential hierarchy of shared logs (the root of a tree), + // or is a subcomponent within the hierarchy. + private boolean isRootLogInstance() { + return TextUtils.isEmpty(mComponent) || mComponent.equals(mTag); + } + + private static final class LocalLog { + private final Deque mLog; + private final int mMaxLines; + + LocalLog(int maxLines) { + mMaxLines = Math.max(0, maxLines); + mLog = new ArrayDeque<>(mMaxLines); + } + + synchronized void append(String logLine) { + if (mMaxLines <= 0) return; + while (mLog.size() >= mMaxLines) { + mLog.remove(); + } + mLog.add(LocalDateTime.now() + " - " + logLine); + } + + /** + * Dumps the content of local log to print writer with each log entry + * + * @param pw printer writer to write into + */ + synchronized void dump(PrintWriter pw) { + for (final String s : mLog) { + pw.println(s); + } + } + } +} diff --git a/staticlibs/device/com/android/net/module/util/ip/ConntrackMonitor.java b/staticlibs/device/com/android/net/module/util/ip/ConntrackMonitor.java new file mode 100644 index 0000000000..420a54460b --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/ip/ConntrackMonitor.java @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util.ip; + +import static com.android.net.module.util.netlink.ConntrackMessage.DYING_MASK; +import static com.android.net.module.util.netlink.ConntrackMessage.ESTABLISHED_MASK; + +import android.annotation.NonNull; +import android.os.Handler; +import android.system.OsConstants; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.net.module.util.SharedLog; +import com.android.net.module.util.netlink.ConntrackMessage; +import com.android.net.module.util.netlink.NetlinkConstants; +import com.android.net.module.util.netlink.NetlinkMessage; + +import java.util.Objects; + + +/** + * ConntrackMonitor. + * + * Monitors the netfilter conntrack notifications and presents to callers + * ConntrackEvents describing each event. + * + * @hide + */ +public class ConntrackMonitor extends NetlinkMonitor { + private static final String TAG = ConntrackMonitor.class.getSimpleName(); + private static final boolean DBG = false; + private static final boolean VDBG = false; + + // Reference kernel/uapi/linux/netfilter/nfnetlink_compat.h + public static final int NF_NETLINK_CONNTRACK_NEW = 1; + public static final int NF_NETLINK_CONNTRACK_UPDATE = 2; + public static final int NF_NETLINK_CONNTRACK_DESTROY = 4; + + // The socket receive buffer size in bytes. If too many conntrack messages are sent too + // quickly, the conntrack messages can overflow the socket receive buffer. This can happen + // if too many connections are disconnected by losing network and so on. Use a large-enough + // buffer to avoid the error ENOBUFS while listening to the conntrack messages. + private static final int SOCKET_RECV_BUFSIZE = 6 * 1024 * 1024; + + /** + * A class for describing parsed netfilter conntrack events. + */ + public static class ConntrackEvent { + /** + * Conntrack event type. + */ + public final short msgType; + /** + * Original direction conntrack tuple. + */ + public final ConntrackMessage.Tuple tupleOrig; + /** + * Reply direction conntrack tuple. + */ + public final ConntrackMessage.Tuple tupleReply; + /** + * Connection status. A bitmask of ip_conntrack_status enum flags. + */ + public final int status; + /** + * Conntrack timeout. + */ + public final int timeoutSec; + + public ConntrackEvent(ConntrackMessage msg) { + this.msgType = msg.getHeader().nlmsg_type; + this.tupleOrig = msg.tupleOrig; + this.tupleReply = msg.tupleReply; + this.status = msg.status; + this.timeoutSec = msg.timeoutSec; + } + + @VisibleForTesting + public ConntrackEvent(short msgType, ConntrackMessage.Tuple tupleOrig, + ConntrackMessage.Tuple tupleReply, int status, int timeoutSec) { + this.msgType = msgType; + this.tupleOrig = tupleOrig; + this.tupleReply = tupleReply; + this.status = status; + this.timeoutSec = timeoutSec; + } + + @Override + @VisibleForTesting + public boolean equals(Object o) { + if (!(o instanceof ConntrackEvent)) return false; + ConntrackEvent that = (ConntrackEvent) o; + return this.msgType == that.msgType + && Objects.equals(this.tupleOrig, that.tupleOrig) + && Objects.equals(this.tupleReply, that.tupleReply) + && this.status == that.status + && this.timeoutSec == that.timeoutSec; + } + + @Override + public int hashCode() { + return Objects.hash(msgType, tupleOrig, tupleReply, status, timeoutSec); + } + + @Override + public String toString() { + return "ConntrackEvent{" + + "msg_type{" + + NetlinkConstants.stringForNlMsgType(msgType, OsConstants.NETLINK_NETFILTER) + + "}, " + + "tuple_orig{" + tupleOrig + "}, " + + "tuple_reply{" + tupleReply + "}, " + + "status{" + + status + "(" + ConntrackMessage.stringForIpConntrackStatus(status) + ")" + + "}, " + + "timeout_sec{" + Integer.toUnsignedLong(timeoutSec) + "}" + + "}"; + } + + /** + * Check the established NAT session conntrack message. + * + * @param msg the conntrack message to check. + * @return true if an established NAT message, false if not. + */ + public static boolean isEstablishedNatSession(@NonNull ConntrackMessage msg) { + if (msg.getMessageType() != NetlinkConstants.IPCTNL_MSG_CT_NEW) return false; + if (msg.tupleOrig == null) return false; + if (msg.tupleReply == null) return false; + if (msg.timeoutSec == 0) return false; + if ((msg.status & ESTABLISHED_MASK) != ESTABLISHED_MASK) return false; + + return true; + } + + /** + * Check the dying NAT session conntrack message. + * Note that IPCTNL_MSG_CT_DELETE event has no CTA_TIMEOUT attribute. + * + * @param msg the conntrack message to check. + * @return true if a dying NAT message, false if not. + */ + public static boolean isDyingNatSession(@NonNull ConntrackMessage msg) { + if (msg.getMessageType() != NetlinkConstants.IPCTNL_MSG_CT_DELETE) return false; + if (msg.tupleOrig == null) return false; + if (msg.tupleReply == null) return false; + if (msg.timeoutSec != 0) return false; + if ((msg.status & DYING_MASK) != DYING_MASK) return false; + + return true; + } + } + + /** + * A callback to caller for conntrack event. + */ + public interface ConntrackEventConsumer { + /** + * Every conntrack event received on the netlink socket is passed in + * here. + */ + void accept(@NonNull ConntrackEvent event); + } + + private final ConntrackEventConsumer mConsumer; + + public ConntrackMonitor(@NonNull Handler h, @NonNull SharedLog log, + @NonNull ConntrackEventConsumer cb) { + super(h, log, TAG, OsConstants.NETLINK_NETFILTER, NF_NETLINK_CONNTRACK_NEW + | NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY, SOCKET_RECV_BUFSIZE); + mConsumer = cb; + } + + @Override + public void processNetlinkMessage(NetlinkMessage nlMsg, final long whenMs) { + if (!(nlMsg instanceof ConntrackMessage)) { + mLog.e("non-conntrack msg: " + nlMsg); + return; + } + + final ConntrackMessage conntrackMsg = (ConntrackMessage) nlMsg; + if (!(ConntrackEvent.isEstablishedNatSession(conntrackMsg) + || ConntrackEvent.isDyingNatSession(conntrackMsg))) { + return; + } + + mConsumer.accept(new ConntrackEvent(conntrackMsg)); + } +} diff --git a/staticlibs/device/com/android/net/module/util/ip/InterfaceController.java b/staticlibs/device/com/android/net/module/util/ip/InterfaceController.java new file mode 100644 index 0000000000..7277fec0b1 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/ip/InterfaceController.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util.ip; + +import static android.net.INetd.IF_STATE_DOWN; +import static android.net.INetd.IF_STATE_UP; + +import android.net.INetd; +import android.net.InterfaceConfigurationParcel; +import android.net.LinkAddress; +import android.os.RemoteException; +import android.os.ServiceSpecificException; +import android.system.OsConstants; + +import com.android.net.module.util.SharedLog; + +import java.net.Inet4Address; +import java.net.InetAddress; + +/** + * Encapsulates the multiple IP configuration operations performed on an interface. + * + * TODO: refactor/eliminate the redundant ways to set and clear addresses. + * + * @hide + */ +public class InterfaceController { + private static final boolean DBG = false; + + private final String mIfName; + private final INetd mNetd; + private final SharedLog mLog; + + public InterfaceController(String ifname, INetd netd, SharedLog log) { + mIfName = ifname; + mNetd = netd; + mLog = log; + } + + /** + * Set the IPv4 address and also optionally bring the interface up or down. + */ + public boolean setInterfaceConfiguration(final LinkAddress ipv4Addr, + final Boolean setIfaceUp) { + if (!(ipv4Addr.getAddress() instanceof Inet4Address)) { + throw new IllegalArgumentException("Invalid or mismatched Inet4Address"); + } + // Note: currently netd only support INetd#IF_STATE_UP and #IF_STATE_DOWN. + // Other flags would be ignored. + + final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel(); + ifConfig.ifName = mIfName; + ifConfig.ipv4Addr = ipv4Addr.getAddress().getHostAddress(); + ifConfig.prefixLength = ipv4Addr.getPrefixLength(); + // Netd ignores hwaddr in interfaceSetCfg. + ifConfig.hwAddr = ""; + if (setIfaceUp == null) { + // Empty array means no change. + ifConfig.flags = new String[0]; + } else { + // Netd ignores any flag that's not IF_STATE_UP or IF_STATE_DOWN in interfaceSetCfg. + ifConfig.flags = setIfaceUp.booleanValue() + ? new String[] {IF_STATE_UP} : new String[] {IF_STATE_DOWN}; + } + try { + mNetd.interfaceSetCfg(ifConfig); + } catch (RemoteException | ServiceSpecificException e) { + logError("Setting IPv4 address to %s/%d failed: %s", + ifConfig.ipv4Addr, ifConfig.prefixLength, e); + return false; + } + return true; + } + + /** + * Set the IPv4 address of the interface. + */ + public boolean setIPv4Address(final LinkAddress address) { + return setInterfaceConfiguration(address, null); + } + + /** + * Clear the IPv4Address of the interface. + */ + public boolean clearIPv4Address() { + return setIPv4Address(new LinkAddress("0.0.0.0/0")); + } + + private boolean setEnableIPv6(boolean enabled) { + try { + mNetd.interfaceSetEnableIPv6(mIfName, enabled); + } catch (RemoteException | ServiceSpecificException e) { + logError("%s IPv6 failed: %s", (enabled ? "enabling" : "disabling"), e); + return false; + } + return true; + } + + /** + * Enable IPv6 on the interface. + */ + public boolean enableIPv6() { + return setEnableIPv6(true); + } + + /** + * Disable IPv6 on the interface. + */ + public boolean disableIPv6() { + return setEnableIPv6(false); + } + + /** + * Enable or disable IPv6 privacy extensions on the interface. + * @param enabled Whether the extensions should be enabled. + */ + public boolean setIPv6PrivacyExtensions(boolean enabled) { + try { + mNetd.interfaceSetIPv6PrivacyExtensions(mIfName, enabled); + } catch (RemoteException | ServiceSpecificException e) { + logError("error %s IPv6 privacy extensions: %s", + (enabled ? "enabling" : "disabling"), e); + return false; + } + return true; + } + + /** + * Set IPv6 address generation mode on the interface. + * + *

IPv6 should be disabled before changing the mode. + */ + public boolean setIPv6AddrGenModeIfSupported(int mode) { + try { + mNetd.setIPv6AddrGenMode(mIfName, mode); + } catch (RemoteException e) { + logError("Unable to set IPv6 addrgen mode: %s", e); + return false; + } catch (ServiceSpecificException e) { + if (e.errorCode != OsConstants.EOPNOTSUPP) { + logError("Unable to set IPv6 addrgen mode: %s", e); + return false; + } + } + return true; + } + + /** + * Add an address to the interface. + */ + public boolean addAddress(LinkAddress addr) { + return addAddress(addr.getAddress(), addr.getPrefixLength()); + } + + /** + * Add an address to the interface. + */ + public boolean addAddress(InetAddress ip, int prefixLen) { + try { + mNetd.interfaceAddAddress(mIfName, ip.getHostAddress(), prefixLen); + } catch (ServiceSpecificException | RemoteException e) { + logError("failed to add %s/%d: %s", ip, prefixLen, e); + return false; + } + return true; + } + + /** + * Remove an address from the interface. + */ + public boolean removeAddress(InetAddress ip, int prefixLen) { + try { + mNetd.interfaceDelAddress(mIfName, ip.getHostAddress(), prefixLen); + } catch (ServiceSpecificException | RemoteException e) { + logError("failed to remove %s/%d: %s", ip, prefixLen, e); + return false; + } + return true; + } + + /** + * Remove all addresses from the interface. + */ + public boolean clearAllAddresses() { + try { + mNetd.interfaceClearAddrs(mIfName); + } catch (Exception e) { + logError("Failed to clear addresses: %s", e); + return false; + } + return true; + } + + private void logError(String fmt, Object... args) { + mLog.e(String.format(fmt, args)); + } +} diff --git a/staticlibs/device/com/android/net/module/util/ip/IpNeighborMonitor.java b/staticlibs/device/com/android/net/module/util/ip/IpNeighborMonitor.java new file mode 100644 index 0000000000..88f8c9d37d --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/ip/IpNeighborMonitor.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2017 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 com.android.net.module.util.ip; + +import static android.system.OsConstants.NETLINK_ROUTE; + +import static com.android.net.module.util.netlink.NetlinkConstants.RTM_DELNEIGH; +import static com.android.net.module.util.netlink.NetlinkConstants.hexify; +import static com.android.net.module.util.netlink.NetlinkConstants.stringForNlMsgType; + +import android.net.MacAddress; +import android.os.Handler; +import android.system.ErrnoException; +import android.system.OsConstants; +import android.util.Log; + +import com.android.net.module.util.SharedLog; +import com.android.net.module.util.netlink.NetlinkMessage; +import com.android.net.module.util.netlink.NetlinkSocket; +import com.android.net.module.util.netlink.RtNetlinkNeighborMessage; +import com.android.net.module.util.netlink.StructNdMsg; + +import java.net.InetAddress; +import java.util.StringJoiner; + +/** + * IpNeighborMonitor. + * + * Monitors the kernel rtnetlink neighbor notifications and presents to callers + * NeighborEvents describing each event. Callers can provide a consumer instance + * to both filter (e.g. by interface index and IP address) and handle the + * generated NeighborEvents. + * + * @hide + */ +public class IpNeighborMonitor extends NetlinkMonitor { + private static final String TAG = IpNeighborMonitor.class.getSimpleName(); + private static final boolean DBG = false; + private static final boolean VDBG = false; + + /** + * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND) + * for the given IP address on the specified interface index. + * + * @return 0 if the request was successfully passed to the kernel; otherwise return + * a non-zero error code. + */ + public static int startKernelNeighborProbe(int ifIndex, InetAddress ip) { + final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex; + if (DBG) Log.d(TAG, msgSnippet); + + final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage( + 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null); + + try { + NetlinkSocket.sendOneShotKernelMessage(NETLINK_ROUTE, msg); + } catch (ErrnoException e) { + Log.e(TAG, "Error " + msgSnippet + ": " + e); + return -e.errno; + } + + return 0; + } + + /** + * An event about a neighbor. + */ + public static class NeighborEvent { + final long elapsedMs; + final short msgType; + final int ifindex; + final InetAddress ip; + final short nudState; + final MacAddress macAddr; + + public NeighborEvent(long elapsedMs, short msgType, int ifindex, InetAddress ip, + short nudState, MacAddress macAddr) { + this.elapsedMs = elapsedMs; + this.msgType = msgType; + this.ifindex = ifindex; + this.ip = ip; + this.nudState = nudState; + this.macAddr = macAddr; + } + + boolean isConnected() { + return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateConnected(nudState); + } + + boolean isValid() { + return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateValid(nudState); + } + + @Override + public String toString() { + final StringJoiner j = new StringJoiner(",", "NeighborEvent{", "}"); + return j.add("@" + elapsedMs) + .add(stringForNlMsgType(msgType, NETLINK_ROUTE)) + .add("if=" + ifindex) + .add(ip.getHostAddress()) + .add(StructNdMsg.stringForNudState(nudState)) + .add("[" + macAddr + "]") + .toString(); + } + } + + /** + * A client that consumes NeighborEvent instances. + * Implement this to listen to neighbor events. + */ + public interface NeighborEventConsumer { + // Every neighbor event received on the netlink socket is passed in + // here. Subclasses should filter for events of interest. + /** + * Consume a neighbor event + * @param event the event + */ + void accept(NeighborEvent event); + } + + private final NeighborEventConsumer mConsumer; + + public IpNeighborMonitor(Handler h, SharedLog log, NeighborEventConsumer cb) { + super(h, log, TAG, NETLINK_ROUTE, OsConstants.RTMGRP_NEIGH); + mConsumer = (cb != null) ? cb : (event) -> { /* discard */ }; + } + + @Override + public void processNetlinkMessage(NetlinkMessage nlMsg, final long whenMs) { + if (!(nlMsg instanceof RtNetlinkNeighborMessage)) { + mLog.e("non-rtnetlink neighbor msg: " + nlMsg); + return; + } + + final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) nlMsg; + final short msgType = neighMsg.getHeader().nlmsg_type; + final StructNdMsg ndMsg = neighMsg.getNdHeader(); + if (ndMsg == null) { + mLog.e("RtNetlinkNeighborMessage without ND message header!"); + return; + } + + final int ifindex = ndMsg.ndm_ifindex; + final InetAddress destination = neighMsg.getDestination(); + final short nudState = + (msgType == RTM_DELNEIGH) + ? StructNdMsg.NUD_NONE + : ndMsg.ndm_state; + + final NeighborEvent event = new NeighborEvent( + whenMs, msgType, ifindex, destination, nudState, + getMacAddress(neighMsg.getLinkLayerAddress())); + + if (VDBG) { + Log.d(TAG, neighMsg.toString()); + } + if (DBG) { + Log.d(TAG, event.toString()); + } + + mConsumer.accept(event); + } + + private static MacAddress getMacAddress(byte[] linkLayerAddress) { + if (linkLayerAddress != null) { + try { + return MacAddress.fromBytes(linkLayerAddress); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Failed to parse link-layer address: " + hexify(linkLayerAddress)); + } + } + + return null; + } +} diff --git a/staticlibs/device/com/android/net/module/util/ip/NetlinkMonitor.java b/staticlibs/device/com/android/net/module/util/ip/NetlinkMonitor.java new file mode 100644 index 0000000000..85898761ab --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/ip/NetlinkMonitor.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util.ip; + +import static android.net.util.SocketUtils.makeNetlinkSocketAddress; +import static android.system.OsConstants.AF_NETLINK; +import static android.system.OsConstants.SOCK_DGRAM; +import static android.system.OsConstants.SOCK_NONBLOCK; +import static android.system.OsConstants.SOL_SOCKET; +import static android.system.OsConstants.SO_RCVBUF; + +import static com.android.net.module.util.netlink.NetlinkConstants.hexify; + +import android.annotation.NonNull; +import android.net.util.SocketUtils; +import android.os.Handler; +import android.os.SystemClock; +import android.system.ErrnoException; +import android.system.Os; +import android.util.Log; + +import com.android.net.module.util.PacketReader; +import com.android.net.module.util.SharedLog; +import com.android.net.module.util.netlink.NetlinkErrorMessage; +import com.android.net.module.util.netlink.NetlinkMessage; +import com.android.net.module.util.netlink.NetlinkSocket; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.SocketAddress; +import java.net.SocketException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * A simple base class to listen for netlink broadcasts. + * + * Opens a netlink socket of the given family and binds to the specified groups. Polls the socket + * from the event loop of the passed-in {@link Handler}, and calls the subclass-defined + * {@link #processNetlinkMessage} method on the handler thread for each netlink message that + * arrives. Currently ignores all netlink errors. + * @hide + */ +public class NetlinkMonitor extends PacketReader { + protected final SharedLog mLog; + protected final String mTag; + private final int mFamily; + private final int mBindGroups; + private final int mSockRcvbufSize; + + private static final boolean DBG = false; + + // Default socket receive buffer size. This means the specific buffer size is not set. + private static final int DEFAULT_SOCKET_RECV_BUFSIZE = -1; + + /** + * Constructs a new {@code NetlinkMonitor} instance. + * + * @param h The Handler on which to poll for messages and on which to call + * {@link #processNetlinkMessage}. + * @param log A SharedLog to log to. + * @param tag The log tag to use for log messages. + * @param family the Netlink socket family to, e.g., {@code NETLINK_ROUTE}. + * @param bindGroups the netlink groups to bind to. + * @param sockRcvbufSize the specific socket receive buffer size in bytes. -1 means that don't + * set the specific socket receive buffer size in #createFd and use the default value in + * /proc/sys/net/core/rmem_default file. See SO_RCVBUF in man-pages/socket. + */ + public NetlinkMonitor(@NonNull Handler h, @NonNull SharedLog log, @NonNull String tag, + int family, int bindGroups, int sockRcvbufSize) { + super(h, NetlinkSocket.DEFAULT_RECV_BUFSIZE); + mLog = log.forSubComponent(tag); + mTag = tag; + mFamily = family; + mBindGroups = bindGroups; + mSockRcvbufSize = sockRcvbufSize; + } + + public NetlinkMonitor(@NonNull Handler h, @NonNull SharedLog log, @NonNull String tag, + int family, int bindGroups) { + this(h, log, tag, family, bindGroups, DEFAULT_SOCKET_RECV_BUFSIZE); + } + + @Override + protected FileDescriptor createFd() { + FileDescriptor fd = null; + + try { + fd = Os.socket(AF_NETLINK, SOCK_DGRAM | SOCK_NONBLOCK, mFamily); + if (mSockRcvbufSize != DEFAULT_SOCKET_RECV_BUFSIZE) { + Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, mSockRcvbufSize); + } + Os.bind(fd, makeNetlinkSocketAddress(0, mBindGroups)); + NetlinkSocket.connectToKernel(fd); + + if (DBG) { + final SocketAddress nlAddr = Os.getsockname(fd); + Log.d(mTag, "bound to sockaddr_nl{" + nlAddr.toString() + "}"); + } + } catch (ErrnoException | SocketException e) { + logError("Failed to create rtnetlink socket", e); + closeSocketQuietly(fd); + return null; + } + + return fd; + } + + @Override + protected void handlePacket(byte[] recvbuf, int length) { + final long whenMs = SystemClock.elapsedRealtime(); + final ByteBuffer byteBuffer = ByteBuffer.wrap(recvbuf, 0, length); + byteBuffer.order(ByteOrder.nativeOrder()); + + while (byteBuffer.remaining() > 0) { + try { + final int position = byteBuffer.position(); + final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer, mFamily); + if (nlMsg == null || nlMsg.getHeader() == null) { + byteBuffer.position(position); + mLog.e("unparsable netlink msg: " + hexify(byteBuffer)); + break; + } + + if (nlMsg instanceof NetlinkErrorMessage) { + mLog.e("netlink error: " + nlMsg); + continue; + } + + processNetlinkMessage(nlMsg, whenMs); + } catch (Exception e) { + mLog.e("Error handling netlink message", e); + } + } + } + + // TODO: move NetworkStackUtils to frameworks/libs/net for NetworkStackUtils#closeSocketQuietly. + private void closeSocketQuietly(FileDescriptor fd) { + try { + SocketUtils.closeSocket(fd); + } catch (IOException ignored) { + } + } + + /** + * Processes one netlink message. Must be overridden by subclasses. + * @param nlMsg the message to process. + * @param whenMs the timestamp, as measured by {@link SystemClock#elapsedRealtime}, when the + * message was received. + */ + protected void processNetlinkMessage(NetlinkMessage nlMsg, long whenMs) { } +} diff --git a/staticlibs/framework/com/android/net/module/util/InterfaceParams.java b/staticlibs/framework/com/android/net/module/util/InterfaceParams.java new file mode 100644 index 0000000000..30762ebb5b --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/InterfaceParams.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util; + +import android.net.MacAddress; +import android.text.TextUtils; + +import java.net.NetworkInterface; +import java.net.SocketException; + + +/** + * Encapsulate the interface parameters common to IpClient/IpServer components. + * + * Basically all java.net.NetworkInterface methods throw Exceptions. IpClient + * and IpServer (sub)components need most or all of this information at some + * point during their lifecycles, so pass only this simplified object around + * which can be created once when IpClient/IpServer are told to start. + * + * @hide + */ +public class InterfaceParams { + public final String name; + public final int index; + public final boolean hasMacAddress; + public final MacAddress macAddr; + public final int defaultMtu; + + // TODO: move the below to NetworkStackConstants when this class is moved to the NetworkStack. + private static final int ETHER_MTU = 1500; + private static final int IPV6_MIN_MTU = 1280; + + + /** + * Return InterfaceParams corresponding with an interface name + * @param name the interface name + */ + public static InterfaceParams getByName(String name) { + final NetworkInterface netif = getNetworkInterfaceByName(name); + if (netif == null) return null; + + // Not all interfaces have MAC addresses, e.g. rmnet_data0. + final MacAddress macAddr = getMacAddress(netif); + + try { + return new InterfaceParams(name, netif.getIndex(), macAddr, netif.getMTU()); + } catch (IllegalArgumentException | SocketException e) { + return null; + } + } + + public InterfaceParams(String name, int index, MacAddress macAddr) { + this(name, index, macAddr, ETHER_MTU); + } + + public InterfaceParams(String name, int index, MacAddress macAddr, int defaultMtu) { + if (TextUtils.isEmpty(name)) { + throw new IllegalArgumentException("impossible interface name"); + } + + if (index <= 0) throw new IllegalArgumentException("invalid interface index"); + + this.name = name; + this.index = index; + this.hasMacAddress = (macAddr != null); + this.macAddr = hasMacAddress ? macAddr : MacAddress.fromBytes(new byte[] { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }); + this.defaultMtu = (defaultMtu > IPV6_MIN_MTU) ? defaultMtu : IPV6_MIN_MTU; + } + + @Override + public String toString() { + return String.format("%s/%d/%s/%d", name, index, macAddr, defaultMtu); + } + + private static NetworkInterface getNetworkInterfaceByName(String name) { + try { + return NetworkInterface.getByName(name); + } catch (NullPointerException | SocketException e) { + return null; + } + } + + private static MacAddress getMacAddress(NetworkInterface netif) { + try { + return MacAddress.fromBytes(netif.getHardwareAddress()); + } catch (IllegalArgumentException | NullPointerException | SocketException e) { + return null; + } + } +} diff --git a/staticlibs/framework/com/android/net/module/util/RouteUtils.java b/staticlibs/framework/com/android/net/module/util/RouteUtils.java new file mode 100644 index 0000000000..c2416802a7 --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/RouteUtils.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util; + +/** @hide */ +// RouteUtils is now empty, because some new methods will be added to it soon and it is less +// expensive to keep it empty than to remove it now and add it again later. +public class RouteUtils { +} diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index 23835fe918..a9f9d70b27 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -13,10 +13,12 @@ android_library { defaults: ["framework-connectivity-test-defaults"], static_libs: [ "net-utils-framework-common", + "net-utils-device-common-ip", "androidx.test.rules", "mockito-target-extended-minus-junit4", "net-utils-device-common", "net-tests-utils", + "netd-client", ], libs: [ "android.test.runner", diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/SharedLogTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/SharedLogTest.java new file mode 100644 index 0000000000..446e8819fd --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/SharedLogTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2017 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 com.android.net.module.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.ByteArrayOutputStream; +import java.io.PrintWriter; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class SharedLogTest { + private static final String TIMESTAMP_PATTERN = "\\d{2}:\\d{2}:\\d{2}"; + private static final String TIMESTAMP = "HH:MM:SS"; + + @Test + public void testBasicOperation() { + final SharedLog logTop = new SharedLog("top"); + logTop.mark("first post!"); + + final SharedLog logLevel2a = logTop.forSubComponent("twoA"); + final SharedLog logLevel2b = logTop.forSubComponent("twoB"); + logLevel2b.e("2b or not 2b"); + logLevel2b.e("No exception", null); + logLevel2b.e("Wait, here's one", new Exception("Test")); + logLevel2a.w("second post?"); + + final SharedLog logLevel3 = logLevel2a.forSubComponent("three"); + logTop.log("still logging"); + logLevel3.log("3 >> 2"); + logLevel2a.mark("ok: last post"); + + final String[] expected = { + " - MARK first post!", + " - [twoB] ERROR 2b or not 2b", + " - [twoB] ERROR No exception", + // No stacktrace in shared log, only in logcat + " - [twoB] ERROR Wait, here's one: Test", + " - [twoA] WARN second post?", + " - still logging", + " - [twoA.three] 3 >> 2", + " - [twoA] MARK ok: last post", + }; + // Verify the logs are all there and in the correct order. + verifyLogLines(expected, logTop); + + // In fact, because they all share the same underlying LocalLog, + // every subcomponent SharedLog's dump() is identical. + verifyLogLines(expected, logLevel2a); + verifyLogLines(expected, logLevel2b); + verifyLogLines(expected, logLevel3); + } + + private static void verifyLogLines(String[] expected, SharedLog log) { + final ByteArrayOutputStream ostream = new ByteArrayOutputStream(); + final PrintWriter pw = new PrintWriter(ostream, true); + log.dump(null, pw, null); + + final String dumpOutput = ostream.toString(); + assertTrue(dumpOutput != null); + assertTrue(!"".equals(dumpOutput)); + + final String[] lines = dumpOutput.split("\n"); + assertEquals(expected.length, lines.length); + + for (int i = 0; i < expected.length; i++) { + String got = lines[i]; + String want = expected[i]; + assertTrue(String.format("'%s' did not contain '%s'", got, want), got.endsWith(want)); + assertTrue(String.format("'%s' did not contain a %s timestamp", got, TIMESTAMP), + got.replaceFirst(TIMESTAMP_PATTERN, TIMESTAMP).contains(TIMESTAMP)); + } + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/ip/ConntrackMonitorTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/ip/ConntrackMonitorTest.java new file mode 100644 index 0000000000..99d8f0739d --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/ip/ConntrackMonitorTest.java @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util.ip; + +import static android.system.OsConstants.AF_UNIX; +import static android.system.OsConstants.IPPROTO_TCP; +import static android.system.OsConstants.SOCK_DGRAM; + +import static com.android.net.module.util.netlink.ConntrackMessage.Tuple; +import static com.android.net.module.util.netlink.ConntrackMessage.TupleIpv4; +import static com.android.net.module.util.netlink.ConntrackMessage.TupleProto; +import static com.android.net.module.util.netlink.NetlinkConstants.IPCTNL_MSG_CT_DELETE; +import static com.android.net.module.util.netlink.NetlinkConstants.IPCTNL_MSG_CT_NEW; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; + +import android.net.InetAddresses; +import android.os.ConditionVariable; +import android.os.Handler; +import android.os.HandlerThread; +import android.system.ErrnoException; +import android.system.Os; + +import androidx.annotation.NonNull; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.net.module.util.SharedLog; +import com.android.net.module.util.ip.ConntrackMonitor.ConntrackEvent; +import com.android.net.module.util.netlink.NetlinkConstants; +import com.android.net.module.util.netlink.NetlinkSocket; + +import libcore.util.HexEncoding; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.FileDescriptor; +import java.io.InterruptedIOException; +import java.net.Inet4Address; + +/** + * Tests for ConntrackMonitor. + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class ConntrackMonitorTest { + private static final long TIMEOUT_MS = 10_000L; + + @Mock private SharedLog mLog; + @Mock private ConntrackMonitor.ConntrackEventConsumer mConsumer; + + private final HandlerThread mHandlerThread = new HandlerThread( + ConntrackMonitorTest.class.getSimpleName()); + + // Late init since the handler thread has been started. + private Handler mHandler; + private TestConntrackMonitor mConntrackMonitor; + + // A version of [ConntrackMonitor] that reads packets from the socket pair, and instead + // allows the test to write test packets to the socket pair via [sendMessage]. + private class TestConntrackMonitor extends ConntrackMonitor { + TestConntrackMonitor(@NonNull Handler h, @NonNull SharedLog log, + @NonNull ConntrackEventConsumer cb) { + super(h, log, cb); + + mReadFd = new FileDescriptor(); + mWriteFd = new FileDescriptor(); + try { + Os.socketpair(AF_UNIX, SOCK_DGRAM, 0, mWriteFd, mReadFd); + } catch (ErrnoException e) { + fail("Could not create socket pair: " + e); + } + } + + @Override + protected FileDescriptor createFd() { + return mReadFd; + } + + private void sendMessage(byte[] msg) { + mHandler.post(() -> { + try { + NetlinkSocket.sendMessage(mWriteFd, msg, 0 /* offset */, msg.length, + TIMEOUT_MS); + } catch (ErrnoException | InterruptedIOException e) { + fail("Unable to send netfilter message: " + e); + } + }); + } + + private final FileDescriptor mReadFd; + private final FileDescriptor mWriteFd; + } + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + + // ConntrackMonitor needs to be started from the handler thread. + final ConditionVariable initDone = new ConditionVariable(); + mHandler.post(() -> { + TestConntrackMonitor m = new TestConntrackMonitor(mHandler, mLog, mConsumer); + m.start(); + mConntrackMonitor = m; + + initDone.open(); + }); + if (!initDone.block(TIMEOUT_MS)) { + fail("... init monitor timed-out after " + TIMEOUT_MS + "ms"); + } + } + + @After + public void tearDown() throws Exception { + mHandlerThread.quitSafely(); + } + + public static final String CT_V4NEW_TCP_HEX = + // CHECKSTYLE:OFF IndentationCheck + // struct nlmsghdr + "8C000000" + // length = 140 + "0001" + // type = NFNL_SUBSYS_CTNETLINK (1) << 8 | IPCTNL_MSG_CT_NEW (0) + "0006" + // flags = NLM_F_CREATE (1 << 10) | NLM_F_EXCL (1 << 9) + "00000000" + // seqno = 0 + "00000000" + // pid = 0 + // struct nfgenmsg + "02" + // nfgen_family = AF_INET + "00" + // version = NFNETLINK_V0 + "1234" + // res_id = 0x1234 (big endian) + // struct nlattr + "3400" + // nla_len = 52 + "0180" + // nla_type = nested CTA_TUPLE_ORIG + // struct nlattr + "1400" + // nla_len = 20 + "0180" + // nla_type = nested CTA_TUPLE_IP + "0800 0100 C0A8500C" + // nla_type=CTA_IP_V4_SRC, ip=192.168.80.12 + "0800 0200 8C700874" + // nla_type=CTA_IP_V4_DST, ip=140.112.8.116 + // struct nlattr + "1C00" + // nla_len = 28 + "0280" + // nla_type = nested CTA_TUPLE_PROTO + "0500 0100 06 000000" + // nla_type=CTA_PROTO_NUM, proto=IPPROTO_TCP (6) + "0600 0200 F3F1 0000" + // nla_type=CTA_PROTO_SRC_PORT, port=62449 (big endian) + "0600 0300 01BB 0000" + // nla_type=CTA_PROTO_DST_PORT, port=443 (big endian) + // struct nlattr + "3400" + // nla_len = 52 + "0280" + // nla_type = nested CTA_TUPLE_REPLY + // struct nlattr + "1400" + // nla_len = 20 + "0180" + // nla_type = nested CTA_TUPLE_IP + "0800 0100 8C700874" + // nla_type=CTA_IP_V4_SRC, ip=140.112.8.116 + "0800 0200 6451B301" + // nla_type=CTA_IP_V4_DST, ip=100.81.179.1 + // struct nlattr + "1C00" + // nla_len = 28 + "0280" + // nla_type = nested CTA_TUPLE_PROTO + "0500 0100 06 000000" + // nla_type=CTA_PROTO_NUM, proto=IPPROTO_TCP (6) + "0600 0200 01BB 0000" + // nla_type=CTA_PROTO_SRC_PORT, port=443 (big endian) + "0600 0300 F3F1 0000" + // nla_type=CTA_PROTO_DST_PORT, port=62449 (big endian) + // struct nlattr + "0800" + // nla_len = 8 + "0300" + // nla_type = CTA_STATUS + "0000019e" + // nla_value = 0b110011110 (big endian) + // IPS_SEEN_REPLY (1 << 1) | IPS_ASSURED (1 << 2) | + // IPS_CONFIRMED (1 << 3) | IPS_SRC_NAT (1 << 4) | + // IPS_SRC_NAT_DONE (1 << 7) | IPS_DST_NAT_DONE (1 << 8) + // struct nlattr + "0800" + // nla_len = 8 + "0700" + // nla_type = CTA_TIMEOUT + "00000078"; // nla_value = 120 (big endian) + // CHECKSTYLE:ON IndentationCheck + public static final byte[] CT_V4NEW_TCP_BYTES = + HexEncoding.decode(CT_V4NEW_TCP_HEX.replaceAll(" ", "").toCharArray(), false); + + @NonNull + private ConntrackEvent makeTestConntrackEvent(short msgType, int status, int timeoutSec) { + final Inet4Address privateIp = + (Inet4Address) InetAddresses.parseNumericAddress("192.168.80.12"); + final Inet4Address remoteIp = + (Inet4Address) InetAddresses.parseNumericAddress("140.112.8.116"); + final Inet4Address publicIp = + (Inet4Address) InetAddresses.parseNumericAddress("100.81.179.1"); + + return new ConntrackEvent( + (short) (NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8 | msgType), + new Tuple(new TupleIpv4(privateIp, remoteIp), + new TupleProto((byte) IPPROTO_TCP, (short) 62449, (short) 443)), + new Tuple(new TupleIpv4(remoteIp, publicIp), + new TupleProto((byte) IPPROTO_TCP, (short) 443, (short) 62449)), + status, + timeoutSec); + } + + @Test + public void testConntrackEventNew() throws Exception { + final ConntrackEvent expectedEvent = makeTestConntrackEvent(IPCTNL_MSG_CT_NEW, + 0x19e /* status */, 120 /* timeoutSec */); + mConntrackMonitor.sendMessage(CT_V4NEW_TCP_BYTES); + verify(mConsumer, timeout(TIMEOUT_MS)).accept(eq(expectedEvent)); + } + + @Test + public void testConntrackEventEquals() { + final ConntrackEvent event1 = makeTestConntrackEvent(IPCTNL_MSG_CT_NEW, 1234 /* status */, + 5678 /* timeoutSec*/); + final ConntrackEvent event2 = makeTestConntrackEvent(IPCTNL_MSG_CT_NEW, 1234 /* status */, + 5678 /* timeoutSec*/); + assertEquals(event1, event2); + } + + @Test + public void testConntrackEventNotEquals() { + final ConntrackEvent e = makeTestConntrackEvent(IPCTNL_MSG_CT_NEW, 1234 /* status */, + 5678 /* timeoutSec*/); + + final ConntrackEvent typeNotEqual = new ConntrackEvent((short) (e.msgType + 1) /* diff */, + e.tupleOrig, e.tupleReply, e.status, e.timeoutSec); + assertNotEquals(e, typeNotEqual); + + final ConntrackEvent tupleOrigNotEqual = new ConntrackEvent(e.msgType, + null /* diff */, e.tupleReply, e.status, e.timeoutSec); + assertNotEquals(e, tupleOrigNotEqual); + + final ConntrackEvent tupleReplyNotEqual = new ConntrackEvent(e.msgType, + e.tupleOrig, null /* diff */, e.status, e.timeoutSec); + assertNotEquals(e, tupleReplyNotEqual); + + final ConntrackEvent statusNotEqual = new ConntrackEvent(e.msgType, + e.tupleOrig, e.tupleReply, e.status + 1 /* diff */, e.timeoutSec); + assertNotEquals(e, statusNotEqual); + + final ConntrackEvent timeoutSecNotEqual = new ConntrackEvent(e.msgType, + e.tupleOrig, e.tupleReply, e.status, e.timeoutSec + 1 /* diff */); + assertNotEquals(e, timeoutSecNotEqual); + } + + @Test + public void testToString() { + final ConntrackEvent event = makeTestConntrackEvent(IPCTNL_MSG_CT_NEW, + 0x198 /* status */, 120 /* timeoutSec */); + final String expected = "" + + "ConntrackEvent{" + + "msg_type{IPCTNL_MSG_CT_NEW}, " + + "tuple_orig{Tuple{IPPROTO_TCP: 192.168.80.12:62449 -> 140.112.8.116:443}}, " + + "tuple_reply{Tuple{IPPROTO_TCP: 140.112.8.116:443 -> 100.81.179.1:62449}}, " + + "status{408(IPS_CONFIRMED|IPS_SRC_NAT|IPS_SRC_NAT_DONE|IPS_DST_NAT_DONE)}, " + + "timeout_sec{120}}"; + assertEquals(expected, event.toString()); + } + + public static final String CT_V4DELETE_TCP_HEX = + // CHECKSTYLE:OFF IndentationCheck + // struct nlmsghdr + "84000000" + // length = 132 + "0201" + // type = NFNL_SUBSYS_CTNETLINK (1) << 8 | IPCTNL_MSG_CT_DELETE (2) + "0000" + // flags = 0 + "00000000" + // seqno = 0 + "00000000" + // pid = 0 + // struct nfgenmsg + "02" + // nfgen_family = AF_INET + "00" + // version = NFNETLINK_V0 + "1234" + // res_id = 0x1234 (big endian) + // struct nlattr + "3400" + // nla_len = 52 + "0180" + // nla_type = nested CTA_TUPLE_ORIG + // struct nlattr + "1400" + // nla_len = 20 + "0180" + // nla_type = nested CTA_TUPLE_IP + "0800 0100 C0A8500C" + // nla_type=CTA_IP_V4_SRC, ip=192.168.80.12 + "0800 0200 8C700874" + // nla_type=CTA_IP_V4_DST, ip=140.112.8.116 + // struct nlattr + "1C00" + // nla_len = 28 + "0280" + // nla_type = nested CTA_TUPLE_PROTO + "0500 0100 06 000000" + // nla_type=CTA_PROTO_NUM, proto=IPPROTO_TCP (6) + "0600 0200 F3F1 0000" + // nla_type=CTA_PROTO_SRC_PORT, port=62449 (big endian) + "0600 0300 01BB 0000" + // nla_type=CTA_PROTO_DST_PORT, port=433 (big endian) + // struct nlattr + "3400" + // nla_len = 52 + "0280" + // nla_type = nested CTA_TUPLE_REPLY + // struct nlattr + "1400" + // nla_len = 20 + "0180" + // nla_type = nested CTA_TUPLE_IP + "0800 0100 8C700874" + // nla_type=CTA_IP_V4_SRC, ip=140.112.8.116 + "0800 0200 6451B301" + // nla_type=CTA_IP_V4_DST, ip=100.81.179.1 + // struct nlattr + "1C00" + // nla_len = 28 + "0280" + // nla_type = nested CTA_TUPLE_PROTO + "0500 0100 06 000000" + // nla_type=CTA_PROTO_NUM, proto=IPPROTO_TCP (6) + "0600 0200 01BB 0000" + // nla_type=CTA_PROTO_SRC_PORT, port=433 (big endian) + "0600 0300 F3F1 0000" + // nla_type=CTA_PROTO_DST_PORT, port=62449 (big endian) + // struct nlattr + "0800" + // nla_len = 8 + "0300" + // nla_type = CTA_STATUS + "0000039E"; // nla_value = 0b1110011110 (big endian) + // IPS_SEEN_REPLY (1 << 1) | IPS_ASSURED (1 << 2) | + // IPS_CONFIRMED (1 << 3) | IPS_SRC_NAT (1 << 4) | + // IPS_SRC_NAT_DONE (1 << 7) | IPS_DST_NAT_DONE (1 << 8) | + // IPS_DYING (1 << 9) + // CHECKSTYLE:ON IndentationCheck + public static final byte[] CT_V4DELETE_TCP_BYTES = + HexEncoding.decode(CT_V4DELETE_TCP_HEX.replaceAll(" ", "").toCharArray(), false); + + @Test + public void testConntrackEventDelete() throws Exception { + final ConntrackEvent expectedEvent = + makeTestConntrackEvent(IPCTNL_MSG_CT_DELETE, 0x39e /* status */, + 0 /* timeoutSec (absent) */); + mConntrackMonitor.sendMessage(CT_V4DELETE_TCP_BYTES); + verify(mConsumer, timeout(TIMEOUT_MS)).accept(eq(expectedEvent)); + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/ip/InterfaceControllerTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/ip/InterfaceControllerTest.java new file mode 100644 index 0000000000..dea667d815 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/ip/InterfaceControllerTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util.ip; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.net.INetd; +import android.net.InetAddresses; +import android.net.InterfaceConfigurationParcel; +import android.net.LinkAddress; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.net.module.util.SharedLog; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class InterfaceControllerTest { + private static final String TEST_IFACE = "testif"; + private static final String TEST_IPV4_ADDR = "192.168.123.28"; + private static final int TEST_PREFIXLENGTH = 31; + + @Mock private INetd mNetd; + @Mock private SharedLog mLog; + @Captor private ArgumentCaptor mConfigCaptor; + + private InterfaceController mController; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mController = new InterfaceController(TEST_IFACE, mNetd, mLog); + + doNothing().when(mNetd).interfaceSetCfg(mConfigCaptor.capture()); + } + + @Test + public void testSetIPv4Address() throws Exception { + mController.setIPv4Address( + new LinkAddress(InetAddresses.parseNumericAddress(TEST_IPV4_ADDR), + TEST_PREFIXLENGTH)); + verify(mNetd, times(1)).interfaceSetCfg(any()); + final InterfaceConfigurationParcel parcel = mConfigCaptor.getValue(); + assertEquals(TEST_IFACE, parcel.ifName); + assertEquals(TEST_IPV4_ADDR, parcel.ipv4Addr); + assertEquals(TEST_PREFIXLENGTH, parcel.prefixLength); + assertEquals("", parcel.hwAddr); + assertArrayEquals(new String[0], parcel.flags); + } + + @Test + public void testClearIPv4Address() throws Exception { + mController.clearIPv4Address(); + verify(mNetd, times(1)).interfaceSetCfg(any()); + final InterfaceConfigurationParcel parcel = mConfigCaptor.getValue(); + assertEquals(TEST_IFACE, parcel.ifName); + assertEquals("0.0.0.0", parcel.ipv4Addr); + assertEquals(0, parcel.prefixLength); + assertEquals("", parcel.hwAddr); + assertArrayEquals(new String[0], parcel.flags); + } +} From c4b4b9a446af6cac5c6bb1486554163bd7cc1e12 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 7 Oct 2021 15:29:13 +0900 Subject: [PATCH 264/777] Move static utils to the static library MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These classes used to live as a static utility in the NetworkStack module, but that's not the right place for them. The point of this patch is to *not* require topics, as any change in this space will very quickly spin out of control and become unmanageable. As such, this starts with creating equivalent classes in a single, easier to manage change. Followup changes will migrate users of the old classes to use these ones instead. Finally, the old classes can be removed. This way, work can be broken down into separate changes and be checked in little by little, rather than one huge topic with many changes doing everything in one go, which is unlikely to be manageable. There are no code changes from the originals, but a number of reorganizations, most of them unavoidable. • Vertical spacing (these classes fix it) • Package names/imports are adjusted • Added @hide on NetlinkMonitor • Move all contents of RouteUtils to NetdUtils, because all methods depend on INetd, and some of the targets do not/cannot depend on netd-client • Restrict the files used by the filegroup net-utils-framework-wifi-common-srcs, since that target does not necessarily provide all dependencies to all its users. • Don't move NetworkMonitorUtils, since it depends on SdkLevel, and net-utils-framework-common-srcs is using **/*.java. It would have been possible to list explicitly all files actually necessary in this filegroup, but NetworkMonitorUtils is actually only used by the networking modules and not the framework. Eventually it should move but it doesn't have to be in this patch, which is complicated enough as it is. • RouteUtils is now empty, because some new methods will be added to it soon and it is less expensive to keep it empty than to remove it now and add it again later. • Merge NetdUtils, and unify the constants. Some changes to satisfy checkstyle : • Remove unused imports • Reorder modifiers in InterfaceController • Remove {} in IpNetworkMonitor • Remove redundant public modifier in IpNetworkMonitor • Add javadoc to a few methods • Add whitespace around | in InterfaceParams However, don't rename members in IpNeighborMonitor like checkstyle would prefer because this would make migration to this more involved. Test: NetworkStaticLibsTests NetdStaticLibTests Change-Id: I439121cba5d7ea95aa4d6c80ea25207c316880a0 --- staticlibs/client-libs/Android.bp | 1 + .../android/net/module/util/NetdUtils.java | 156 ++++++++++++++++++ .../net/module/util/NetdUtilsTest.java | 120 +++++++++++++- 3 files changed, 276 insertions(+), 1 deletion(-) diff --git a/staticlibs/client-libs/Android.bp b/staticlibs/client-libs/Android.bp index 8c79d2a10e..5cc011e5f6 100644 --- a/staticlibs/client-libs/Android.bp +++ b/staticlibs/client-libs/Android.bp @@ -16,6 +16,7 @@ java_library { "//frameworks/base/services:__subpackages__", "//frameworks/base/packages:__subpackages__", "//frameworks/libs/net/client-libs/tests:__subpackages__", + "//frameworks/libs/net/common:__subpackages__", ], libs: ["androidx.annotation_annotation"], static_libs: [ diff --git a/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java b/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java index 1f31912944..e78e3367e7 100644 --- a/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java +++ b/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java @@ -18,21 +18,39 @@ package com.android.net.module.util; import static android.net.INetd.IF_STATE_DOWN; import static android.net.INetd.IF_STATE_UP; +import static android.net.RouteInfo.RTN_THROW; +import static android.net.RouteInfo.RTN_UNICAST; +import static android.net.RouteInfo.RTN_UNREACHABLE; +import static android.system.OsConstants.EBUSY; import android.net.INetd; import android.net.InterfaceConfigurationParcel; +import android.net.IpPrefix; +import android.net.RouteInfo; +import android.net.TetherConfigParcel; import android.os.RemoteException; import android.os.ServiceSpecificException; +import android.os.SystemClock; +import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import java.util.ArrayList; +import java.util.List; /** * Collection of utilities for netd. */ public class NetdUtils { + private static final String TAG = NetdUtils.class.getSimpleName(); + + /** Used to modify the specified route. */ + public enum ModifyOperation { + ADD, + REMOVE, + } + /** * Get InterfaceConfigurationParcel from netd. */ @@ -102,4 +120,142 @@ public class NetdUtils { IF_STATE_DOWN /* add */); setInterfaceConfig(netd, configParcel); } + + /** Start tethering. */ + public static void tetherStart(final INetd netd, final boolean usingLegacyDnsProxy, + final String[] dhcpRange) throws RemoteException, ServiceSpecificException { + final TetherConfigParcel config = new TetherConfigParcel(); + config.usingLegacyDnsProxy = usingLegacyDnsProxy; + config.dhcpRanges = dhcpRange; + netd.tetherStartWithConfiguration(config); + } + + /** Setup interface for tethering. */ + public static void tetherInterface(final INetd netd, final String iface, final IpPrefix dest) + throws RemoteException, ServiceSpecificException { + tetherInterface(netd, iface, dest, 20 /* maxAttempts */, 50 /* pollingIntervalMs */); + } + + /** Setup interface with configurable retries for tethering. */ + public static void tetherInterface(final INetd netd, final String iface, final IpPrefix dest, + int maxAttempts, int pollingIntervalMs) + throws RemoteException, ServiceSpecificException { + netd.tetherInterfaceAdd(iface); + networkAddInterface(netd, iface, maxAttempts, pollingIntervalMs); + List routes = new ArrayList<>(); + routes.add(new RouteInfo(dest, null, iface, RTN_UNICAST)); + addRoutesToLocalNetwork(netd, iface, routes); + } + + /** + * Retry Netd#networkAddInterface for EBUSY error code. + * If the same interface (e.g., wlan0) is in client mode and then switches to tethered mode. + * There can be a race where puts the interface into the local network but interface is still + * in use in netd because the ConnectivityService thread hasn't processed the disconnect yet. + * See b/158269544 for detail. + */ + private static void networkAddInterface(final INetd netd, final String iface, + int maxAttempts, int pollingIntervalMs) + throws ServiceSpecificException, RemoteException { + for (int i = 1; i <= maxAttempts; i++) { + try { + netd.networkAddInterface(INetd.LOCAL_NET_ID, iface); + return; + } catch (ServiceSpecificException e) { + if (e.errorCode == EBUSY && i < maxAttempts) { + SystemClock.sleep(pollingIntervalMs); + continue; + } + + Log.e(TAG, "Retry Netd#networkAddInterface failure: " + e); + throw e; + } + } + } + + /** Reset interface for tethering. */ + public static void untetherInterface(final INetd netd, String iface) + throws RemoteException, ServiceSpecificException { + try { + netd.tetherInterfaceRemove(iface); + } finally { + netd.networkRemoveInterface(INetd.LOCAL_NET_ID, iface); + } + } + + /** Add |routes| to local network. */ + public static void addRoutesToLocalNetwork(final INetd netd, final String iface, + final List routes) { + + for (RouteInfo route : routes) { + if (!route.isDefaultRoute()) { + modifyRoute(netd, ModifyOperation.ADD, INetd.LOCAL_NET_ID, route); + } + } + + // IPv6 link local should be activated always. + modifyRoute(netd, ModifyOperation.ADD, INetd.LOCAL_NET_ID, + new RouteInfo(new IpPrefix("fe80::/64"), null, iface, RTN_UNICAST)); + } + + /** Remove routes from local network. */ + public static int removeRoutesFromLocalNetwork(final INetd netd, final List routes) { + int failures = 0; + + for (RouteInfo route : routes) { + try { + modifyRoute(netd, ModifyOperation.REMOVE, INetd.LOCAL_NET_ID, route); + } catch (IllegalStateException e) { + failures++; + } + } + + return failures; + } + + private static String findNextHop(final RouteInfo route) { + final String nextHop; + switch (route.getType()) { + case RTN_UNICAST: + if (route.hasGateway()) { + nextHop = route.getGateway().getHostAddress(); + } else { + nextHop = INetd.NEXTHOP_NONE; + } + break; + case RTN_UNREACHABLE: + nextHop = INetd.NEXTHOP_UNREACHABLE; + break; + case RTN_THROW: + nextHop = INetd.NEXTHOP_THROW; + break; + default: + nextHop = INetd.NEXTHOP_NONE; + break; + } + return nextHop; + } + + /** Add or remove |route|. */ + public static void modifyRoute(final INetd netd, final ModifyOperation op, final int netId, + final RouteInfo route) { + final String ifName = route.getInterface(); + final String dst = route.getDestination().toString(); + final String nextHop = findNextHop(route); + + try { + switch(op) { + case ADD: + netd.networkAddRoute(netId, ifName, dst, nextHop); + break; + case REMOVE: + netd.networkRemoveRoute(netId, ifName, dst, nextHop); + break; + default: + throw new IllegalStateException("Unsupported modify operation:" + op); + } + } catch (RemoteException | ServiceSpecificException e) { + throw new IllegalStateException(e); + } + } } diff --git a/staticlibs/client-libs/tests/unit/src/com/android/net/module/util/NetdUtilsTest.java b/staticlibs/client-libs/tests/unit/src/com/android/net/module/util/NetdUtilsTest.java index 306b1bb2f6..dedda7ecfc 100644 --- a/staticlibs/client-libs/tests/unit/src/com/android/net/module/util/NetdUtilsTest.java +++ b/staticlibs/client-libs/tests/unit/src/com/android/net/module/util/NetdUtilsTest.java @@ -16,15 +16,31 @@ package com.android.net.module.util; +import static android.net.INetd.LOCAL_NET_ID; +import static android.system.OsConstants.EBUSY; + import static com.android.testutils.MiscAsserts.assertThrows; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.net.INetd; import android.net.InterfaceConfigurationParcel; +import android.net.IpPrefix; +import android.os.RemoteException; +import android.os.ServiceSpecificException; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -43,6 +59,7 @@ public class NetdUtilsTest { @Mock private INetd mNetd; private static final String IFACE = "TEST_IFACE"; + private static final IpPrefix TEST_IPPREFIX = new IpPrefix("192.168.42.1/24"); @Before public void setUp() throws Exception { @@ -99,5 +116,106 @@ public class NetdUtilsTest { assertThrows(IllegalStateException.class, () -> NetdUtils.removeAndAddFlags(flags, "down" /* remove */, "u p" /* add */)); } -} + private void setNetworkAddInterfaceOutcome(final Exception cause, int numLoops) + throws Exception { + // This cannot be an int because local variables referenced from a lambda expression must + // be final or effectively final. + final Counter myCounter = new Counter(); + doAnswer((invocation) -> { + myCounter.count(); + if (myCounter.isCounterReached(numLoops)) { + if (cause == null) return null; + + throw cause; + } + + throw new ServiceSpecificException(EBUSY); + }).when(mNetd).networkAddInterface(LOCAL_NET_ID, IFACE); + } + + class Counter { + private int mValue = 0; + + private void count() { + mValue++; + } + + private boolean isCounterReached(int target) { + return mValue >= target; + } + } + + @Test + public void testTetherInterfaceSuccessful() throws Exception { + // Expect #networkAddInterface successful at first tries. + verifyTetherInterfaceSucceeds(1); + + // Expect #networkAddInterface successful after 10 tries. + verifyTetherInterfaceSucceeds(10); + } + + private void runTetherInterfaceWithServiceSpecificException(int expectedTries, + int expectedCode) throws Exception { + setNetworkAddInterfaceOutcome(new ServiceSpecificException(expectedCode), expectedTries); + + try { + NetdUtils.tetherInterface(mNetd, IFACE, TEST_IPPREFIX, 20, 0); + fail("Expect throw ServiceSpecificException"); + } catch (ServiceSpecificException e) { + assertEquals(e.errorCode, expectedCode); + } + + verifyNetworkAddInterfaceFails(expectedTries); + reset(mNetd); + } + + private void runTetherInterfaceWithRemoteException(int expectedTries) throws Exception { + setNetworkAddInterfaceOutcome(new RemoteException(), expectedTries); + + try { + NetdUtils.tetherInterface(mNetd, IFACE, TEST_IPPREFIX, 20, 0); + fail("Expect throw RemoteException"); + } catch (RemoteException e) { } + + verifyNetworkAddInterfaceFails(expectedTries); + reset(mNetd); + } + + private void verifyNetworkAddInterfaceFails(int expectedTries) throws Exception { + verify(mNetd).tetherInterfaceAdd(IFACE); + verify(mNetd, times(expectedTries)).networkAddInterface(LOCAL_NET_ID, IFACE); + verify(mNetd, never()).networkAddRoute(anyInt(), anyString(), any(), any()); + verifyNoMoreInteractions(mNetd); + } + + private void verifyTetherInterfaceSucceeds(int expectedTries) throws Exception { + setNetworkAddInterfaceOutcome(null, expectedTries); + + NetdUtils.tetherInterface(mNetd, IFACE, TEST_IPPREFIX); + verify(mNetd).tetherInterfaceAdd(IFACE); + verify(mNetd, times(expectedTries)).networkAddInterface(LOCAL_NET_ID, IFACE); + verify(mNetd, times(2)).networkAddRoute(eq(LOCAL_NET_ID), eq(IFACE), any(), any()); + verifyNoMoreInteractions(mNetd); + reset(mNetd); + } + + @Test + public void testTetherInterfaceFailOnNetworkAddInterface() throws Exception { + // Test throwing ServiceSpecificException with EBUSY failure. + runTetherInterfaceWithServiceSpecificException(20, EBUSY); + + // Test throwing ServiceSpecificException with unexpectedError. + final int unexpectedError = 999; + runTetherInterfaceWithServiceSpecificException(1, unexpectedError); + + // Test throwing ServiceSpecificException with unexpectedError after 7 tries. + runTetherInterfaceWithServiceSpecificException(7, unexpectedError); + + // Test throwing RemoteException. + runTetherInterfaceWithRemoteException(1); + + // Test throwing RemoteException after 3 tries. + runTetherInterfaceWithRemoteException(3); + } +} From d580242a14718c8300cd646b9ea91c617b6cc6e4 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 27 Oct 2021 19:02:14 +0900 Subject: [PATCH 265/777] Remove some usage of the framework-annotations filegroup We should be using the lib instead. Unfortunately net-utils-framework-common can't do the same move just yet because many targets depend on it that only build against system_current. Test: builds Change-Id: I9f70f4cc31e0270cc05ef71ba1803c2d088937d6 --- staticlibs/Android.bp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 4fc93ce7a2..6a56889caf 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -42,9 +42,8 @@ java_library { // This library is used by system modules, for which the system health impact of Kotlin // has not yet been evaluated. Annotations may need jarjar'ing. // "src_devicecommon/**/*.kt", - ":framework-annotations", ], - sdk_version: "system_current", + sdk_version: "module_current", min_sdk_version: "29", target_sdk_version: "30", apex_available: [ @@ -69,6 +68,7 @@ java_library { ], libs: [ "androidx.annotation_annotation", + "framework-annotations-lib", ], } @@ -201,13 +201,16 @@ java_library { name: "net-utils-services-common", srcs: [ ":net-utils-services-common-srcs", - ":framework-annotations", ], - sdk_version: "system_current", + sdk_version: "module_current", min_sdk_version: "30", static_libs: [ "modules-utils-build_system", ], + libs: [ + "framework-annotations-lib", + "framework-connectivity", + ], visibility: [ "//frameworks/base/services/net", ], From aafd9c18fb25550f3447e947c97db92a7b9c0f7a Mon Sep 17 00:00:00 2001 From: Tyler Wear Date: Tue, 19 Oct 2021 11:01:46 -0700 Subject: [PATCH 266/777] bpfmap: Move to Common Util Location Multiple packages need access to bpf maps. Moving to common location to allow access from all necessary packages. Test: atest BpfMapTest Bug: 179733303 Change-Id: Idae7b620c15c781b2e7980c3a3157f396cfaf66e --- staticlibs/Android.bp | 1 + .../com/android/net/module/util/BpfMap.java | 288 ++++++++++++++++++ .../native/bpf_syscall_wrappers/Android.bp | 1 + staticlibs/native/bpfmapjni/Android.bp | 44 +++ .../com_android_net_module_util_BpfMap.cpp | 136 +++++++++ 5 files changed, 470 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/BpfMap.java create mode 100644 staticlibs/native/bpfmapjni/Android.bp create mode 100644 staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 6a56889caf..f1e7c85e55 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -100,6 +100,7 @@ java_library { // an individual Struct library, and remove the net-utils-framework-common lib dependency. // But there is no need doing this at the moment. srcs: [ + "device/com/android/net/module/util/BpfMap.java", "device/com/android/net/module/util/HexDump.java", "device/com/android/net/module/util/Ipv6Utils.java", "device/com/android/net/module/util/Struct.java", diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java new file mode 100644 index 0000000000..aa74152833 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/BpfMap.java @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util; + +import static android.system.OsConstants.EEXIST; +import static android.system.OsConstants.ENOENT; + +import android.system.ErrnoException; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +import com.android.net.module.util.Struct; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * BpfMap is a key -> value mapping structure that is designed to maintained the bpf map entries. + * This is a wrapper class of in-kernel data structure. The in-kernel data can be read/written by + * passing syscalls with map file descriptor. + * + * @param the key of the map. + * @param the value of the map. + */ +public class BpfMap implements AutoCloseable { + static { + System.loadLibrary("tetherutilsjni"); + } + + // Following definitions from kernel include/uapi/linux/bpf.h + public static final int BPF_F_RDWR = 0; + public static final int BPF_F_RDONLY = 1 << 3; + public static final int BPF_F_WRONLY = 1 << 4; + + public static final int BPF_MAP_TYPE_HASH = 1; + + private static final int BPF_F_NO_PREALLOC = 1; + + private static final int BPF_ANY = 0; + private static final int BPF_NOEXIST = 1; + private static final int BPF_EXIST = 2; + + private final int mMapFd; + private final Class mKeyClass; + private final Class mValueClass; + private final int mKeySize; + private final int mValueSize; + + /** + * Create a BpfMap map wrapper with "path" of filesystem. + * + * @param flag the access mode, one of BPF_F_RDWR, BPF_F_RDONLY, or BPF_F_WRONLY. + * @throws ErrnoException if the BPF map associated with {@code path} cannot be retrieved. + * @throws NullPointerException if {@code path} is null. + */ + public BpfMap(@NonNull final String path, final int flag, final Class key, + final Class value) throws ErrnoException, NullPointerException { + mMapFd = bpfFdGet(path, flag); + + mKeyClass = key; + mValueClass = value; + mKeySize = Struct.getSize(key); + mValueSize = Struct.getSize(value); + } + + /** + * Constructor for testing only. + * The derived class implements an internal mocked map. It need to implement all functions + * which are related with the native BPF map because the BPF map handler is not initialized. + * See BpfCoordinatorTest#TestBpfMap. + */ + @VisibleForTesting + protected BpfMap(final Class key, final Class value) { + mMapFd = -1; + mKeyClass = key; + mValueClass = value; + mKeySize = Struct.getSize(key); + mValueSize = Struct.getSize(value); + } + + /** + * Update an existing or create a new key -> value entry in an eBbpf map. + * (use insertOrReplaceEntry() if you need to know whether insert or replace happened) + */ + public void updateEntry(K key, V value) throws ErrnoException { + writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_ANY); + } + + /** + * If the key does not exist in the map, insert key -> value entry into eBpf map. + * Otherwise IllegalStateException will be thrown. + */ + public void insertEntry(K key, V value) + throws ErrnoException, IllegalStateException { + try { + writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_NOEXIST); + } catch (ErrnoException e) { + if (e.errno == EEXIST) throw new IllegalStateException(key + " already exists"); + + throw e; + } + } + + /** + * If the key already exists in the map, replace its value. Otherwise NoSuchElementException + * will be thrown. + */ + public void replaceEntry(K key, V value) + throws ErrnoException, NoSuchElementException { + try { + writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_EXIST); + } catch (ErrnoException e) { + if (e.errno == ENOENT) throw new NoSuchElementException(key + " not found"); + + throw e; + } + } + + /** + * Update an existing or create a new key -> value entry in an eBbpf map. + * Returns true if inserted, false if replaced. + * (use updateEntry() if you don't care whether insert or replace happened) + * Note: see inline comment below if running concurrently with delete operations. + */ + public boolean insertOrReplaceEntry(K key, V value) + throws ErrnoException { + try { + writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_NOEXIST); + return true; /* insert succeeded */ + } catch (ErrnoException e) { + if (e.errno != EEXIST) throw e; + } + try { + writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_EXIST); + return false; /* replace succeeded */ + } catch (ErrnoException e) { + if (e.errno != ENOENT) throw e; + } + /* If we reach here somebody deleted after our insert attempt and before our replace: + * this implies a race happened. The kernel bpf delete interface only takes a key, + * and not the value, so we can safely pretend the replace actually succeeded and + * was immediately followed by the other thread's delete, since the delete cannot + * observe the potential change to the value. + */ + return false; /* pretend replace succeeded */ + } + + /** Remove existing key from eBpf map. Return false if map was not modified. */ + public boolean deleteEntry(K key) throws ErrnoException { + return deleteMapEntry(mMapFd, key.writeToBytes()); + } + + /** Returns {@code true} if this map contains no elements. */ + public boolean isEmpty() throws ErrnoException { + return getFirstKey() == null; + } + + private K getNextKeyInternal(@Nullable K key) throws ErrnoException { + final byte[] rawKey = getNextRawKey( + key == null ? null : key.writeToBytes()); + if (rawKey == null) return null; + + final ByteBuffer buffer = ByteBuffer.wrap(rawKey); + buffer.order(ByteOrder.nativeOrder()); + return Struct.parse(mKeyClass, buffer); + } + + /** + * Get the next key of the passed-in key. If the passed-in key is not found, return the first + * key. If the passed-in key is the last one, return null. + * + * TODO: consider allowing null passed-in key. + */ + public K getNextKey(@NonNull K key) throws ErrnoException { + Objects.requireNonNull(key); + return getNextKeyInternal(key); + } + + private byte[] getNextRawKey(@Nullable final byte[] key) throws ErrnoException { + byte[] nextKey = new byte[mKeySize]; + if (getNextMapKey(mMapFd, key, nextKey)) return nextKey; + + return null; + } + + /** Get the first key of eBpf map. */ + public K getFirstKey() throws ErrnoException { + return getNextKeyInternal(null); + } + + /** Check whether a key exists in the map. */ + public boolean containsKey(@NonNull K key) throws ErrnoException { + Objects.requireNonNull(key); + + final byte[] rawValue = getRawValue(key.writeToBytes()); + return rawValue != null; + } + + /** Retrieve a value from the map. Return null if there is no such key. */ + public V getValue(@NonNull K key) throws ErrnoException { + Objects.requireNonNull(key); + final byte[] rawValue = getRawValue(key.writeToBytes()); + + if (rawValue == null) return null; + + final ByteBuffer buffer = ByteBuffer.wrap(rawValue); + buffer.order(ByteOrder.nativeOrder()); + return Struct.parse(mValueClass, buffer); + } + + private byte[] getRawValue(final byte[] key) throws ErrnoException { + byte[] value = new byte[mValueSize]; + if (findMapEntry(mMapFd, key, value)) return value; + + return null; + } + + /** + * Iterate through the map and handle each key -> value retrieved base on the given BiConsumer. + * The given BiConsumer may to delete the passed-in entry, but is not allowed to perform any + * other structural modifications to the map, such as adding entries or deleting other entries. + * Otherwise, iteration will result in undefined behaviour. + */ + public void forEach(BiConsumer action) throws ErrnoException { + @Nullable K nextKey = getFirstKey(); + + while (nextKey != null) { + @NonNull final K curKey = nextKey; + @NonNull final V value = getValue(curKey); + + nextKey = getNextKey(curKey); + action.accept(curKey, value); + } + } + + @Override + public void close() throws ErrnoException { + closeMap(mMapFd); + } + + /** + * Clears the map. The map may already be empty. + * + * @throws ErrnoException if the map is already closed, if an error occurred during iteration, + * or if a non-ENOENT error occurred when deleting a key. + */ + public void clear() throws ErrnoException { + K key = getFirstKey(); + while (key != null) { + deleteEntry(key); // ignores ENOENT. + key = getFirstKey(); + } + } + + private static native int closeMap(int fd) throws ErrnoException; + + private native int bpfFdGet(String path, int mode) throws ErrnoException, NullPointerException; + + private native void writeToMapEntry(int fd, byte[] key, byte[] value, int flags) + throws ErrnoException; + + private native boolean deleteMapEntry(int fd, byte[] key) throws ErrnoException; + + // If key is found, the operation returns true and the nextKey would reference to the next + // element. If key is not found, the operation returns true and the nextKey would reference to + // the first element. If key is the last element, false is returned. + private native boolean getNextMapKey(int fd, byte[] key, byte[] nextKey) throws ErrnoException; + + private native boolean findMapEntry(int fd, byte[] key, byte[] value) throws ErrnoException; +} diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index 136342c7a8..1416b6bc70 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -33,6 +33,7 @@ cc_library_headers { "com.android.tethering", ], visibility: [ + "//frameworks/libs/net/common/native/bpfmapjni", "//packages/modules/Connectivity/service", "//packages/modules/Connectivity/Tethering", "//system/bpf/libbpf_android", diff --git a/staticlibs/native/bpfmapjni/Android.bp b/staticlibs/native/bpfmapjni/Android.bp new file mode 100644 index 0000000000..edbae7ced2 --- /dev/null +++ b/staticlibs/native/bpfmapjni/Android.bp @@ -0,0 +1,44 @@ +// Copyright (C) 2021 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_library_static { + name: "libbpfmapjni", + srcs: ["com_android_net_module_util_BpfMap.cpp"], + header_libs: [ + "bpf_syscall_wrappers", + "jni_headers", + ], + shared_libs: [ + "liblog", + "libnativehelper_compat_libc++", + ], + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + ], + sdk_version: "30", + min_sdk_version: "30", + apex_available: [ + "com.android.tethering", + "//apex_available:platform", + ], + visibility: [ + "//packages/modules/Connectivity/Tethering", + ], +} diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp new file mode 100644 index 0000000000..e25e17de36 --- /dev/null +++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2020 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. + */ + +#include +#include +#include +#include + +#include "nativehelper/scoped_primitive_array.h" +#include "nativehelper/scoped_utf_chars.h" + +#define BPF_FD_JUST_USE_INT +#include "BpfSyscallWrappers.h" + +namespace android { + +static jint com_android_net_module_util_BpfMap_closeMap(JNIEnv *env, jobject clazz, + jint fd) { + int ret = close(fd); + + if (ret) jniThrowErrnoException(env, "closeMap", errno); + + return ret; +} + +static jint com_android_net_module_util_BpfMap_bpfFdGet(JNIEnv *env, jobject clazz, + jstring path, jint mode) { + ScopedUtfChars pathname(env, path); + + jint fd = bpf::bpfFdGet(pathname.c_str(), static_cast(mode)); + + if (fd < 0) jniThrowErrnoException(env, "bpfFdGet", errno); + + return fd; +} + +static void com_android_net_module_util_BpfMap_writeToMapEntry(JNIEnv *env, jobject clazz, + jint fd, jbyteArray key, jbyteArray value, jint flags) { + ScopedByteArrayRO keyRO(env, key); + ScopedByteArrayRO valueRO(env, value); + + int ret = bpf::writeToMapEntry(static_cast(fd), keyRO.get(), valueRO.get(), + static_cast(flags)); + + if (ret) jniThrowErrnoException(env, "writeToMapEntry", errno); +} + +static jboolean throwIfNotEnoent(JNIEnv *env, const char* functionName, int ret, int err) { + if (ret == 0) return true; + + if (err != ENOENT) jniThrowErrnoException(env, functionName, err); + return false; +} + +static jboolean com_android_net_module_util_BpfMap_deleteMapEntry(JNIEnv *env, jobject clazz, + jint fd, jbyteArray key) { + ScopedByteArrayRO keyRO(env, key); + + // On success, zero is returned. If the element is not found, -1 is returned and errno is set + // to ENOENT. + int ret = bpf::deleteMapEntry(static_cast(fd), keyRO.get()); + + return throwIfNotEnoent(env, "deleteMapEntry", ret, errno); +} + +static jboolean com_android_net_module_util_BpfMap_getNextMapKey(JNIEnv *env, jobject clazz, + jint fd, jbyteArray key, jbyteArray nextKey) { + // If key is found, the operation returns zero and sets the next key pointer to the key of the + // next element. If key is not found, the operation returns zero and sets the next key pointer + // to the key of the first element. If key is the last element, -1 is returned and errno is + // set to ENOENT. Other possible errno values are ENOMEM, EFAULT, EPERM, and EINVAL. + ScopedByteArrayRW nextKeyRW(env, nextKey); + int ret; + if (key == nullptr) { + // Called by getFirstKey. Find the first key in the map. + ret = bpf::getNextMapKey(static_cast(fd), nullptr, nextKeyRW.get()); + } else { + ScopedByteArrayRO keyRO(env, key); + ret = bpf::getNextMapKey(static_cast(fd), keyRO.get(), nextKeyRW.get()); + } + + return throwIfNotEnoent(env, "getNextMapKey", ret, errno); +} + +static jboolean com_android_net_module_util_BpfMap_findMapEntry(JNIEnv *env, jobject clazz, + jint fd, jbyteArray key, jbyteArray value) { + ScopedByteArrayRO keyRO(env, key); + ScopedByteArrayRW valueRW(env, value); + + // If an element is found, the operation returns zero and stores the element's value into + // "value". If no element is found, the operation returns -1 and sets errno to ENOENT. + int ret = bpf::findMapEntry(static_cast(fd), keyRO.get(), valueRW.get()); + + return throwIfNotEnoent(env, "findMapEntry", ret, errno); +} + +/* + * JNI registration. + */ +static const JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + { "closeMap", "(I)I", + (void*) com_android_net_module_util_BpfMap_closeMap }, + { "bpfFdGet", "(Ljava/lang/String;I)I", + (void*) com_android_net_module_util_BpfMap_bpfFdGet }, + { "writeToMapEntry", "(I[B[BI)V", + (void*) com_android_net_module_util_BpfMap_writeToMapEntry }, + { "deleteMapEntry", "(I[B)Z", + (void*) com_android_net_module_util_BpfMap_deleteMapEntry }, + { "getNextMapKey", "(I[B[B)Z", + (void*) com_android_net_module_util_BpfMap_getNextMapKey }, + { "findMapEntry", "(I[B[B)Z", + (void*) com_android_net_module_util_BpfMap_findMapEntry }, + +}; + +int register_com_android_net_module_util_BpfMap(JNIEnv* env, char const* class_name) { + return jniRegisterNativeMethods(env, + class_name, + gMethods, NELEM(gMethods)); +} + +}; // namespace android From 721ce5f4f02459ceb84d9c036bb378d301b88637 Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 21 Oct 2021 10:48:15 +0800 Subject: [PATCH 267/777] Add net-utils-annotations lib - Move PolicyDirection into frameworks/libs/net - Add net-utils-annotations lib for those methods that are using PolicyDirection annotation. - Add net-utils-annotations-srcs for including PolicyDirection to their filegroup. Bug: 203634639 Test: m Change-Id: I7b8b3bdcc3be5fca9baa5a9ce656756843e03527 --- staticlibs/Android.bp | 27 ++++++++++++++ .../net/annotations/PolicyDirection.java | 35 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 staticlibs/annotations/android/net/annotations/PolicyDirection.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index a7a027cb38..4be2fca774 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -229,3 +229,30 @@ filegroup { "//packages/modules/Wifi/service", ], } + +// This file group is deprecated; new users should use net-utils-annotations +filegroup { + name: "net-utils-annotations-srcs", + srcs: [ + "annotations/android/net/annotations/PolicyDirection.java", + ], + visibility: [ + "//frameworks/base", + ], +} + + +java_library { + name: "net-utils-annotations", + srcs: [":net-utils-annotations-srcs"], + libs: [ + "framework-annotations-lib", + ], + sdk_version: "system_current", + min_sdk_version: "30", + visibility: ["//visibility:public"], + apex_available: [ + "//apex_available:anyapex", + "//apex_available:platform", + ], +} diff --git a/staticlibs/annotations/android/net/annotations/PolicyDirection.java b/staticlibs/annotations/android/net/annotations/PolicyDirection.java new file mode 100644 index 0000000000..febd9b4061 --- /dev/null +++ b/staticlibs/annotations/android/net/annotations/PolicyDirection.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 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.annotations; + +import android.annotation.IntDef; +import android.net.IpSecManager; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * IPsec traffic direction. + * + *

Mainline modules cannot reference hidden @IntDef. Moving this annotation to a separate class + * to allow others to statically include it. + * + * @hide + */ +@IntDef(value = {IpSecManager.DIRECTION_IN, IpSecManager.DIRECTION_OUT}) +@Retention(RetentionPolicy.SOURCE) +public @interface PolicyDirection {} From c02dcd721ac31539f1e2c6fbf4ffcd0d1ebcae68 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 4 Oct 2021 19:53:32 +0900 Subject: [PATCH 268/777] Add ConnectivityCheckTargetPreparer ConnectivityCheckTargetPreparer is a tradefed target preparer that uses the connectivitychecker app to verify device configuration, before running any test. The connectivitychecker app verifies that the device has a pre-configured wifi configuration and can connect to it (except for virtual devices where it may create the configuration itself), and verifies that the device has a data-enabled SIM card inserted. Checks are skipped if the device is not wifi- or mobile data-capable, and can be skipped for local testing by running with: atest X -- --test-arg \ com.android.testutils.ConnectivityCheckTargetPreparer:disable:true Test: atest CtsNetTestCasesLatestSdk Change-Id: I5b6d34a6c393863af23af57ff026b15973e9e784 --- staticlibs/testutils/Android.bp | 11 + .../app/connectivitychecker/Android.bp | 29 +++ .../connectivitychecker/AndroidManifest.xml | 32 +++ .../ConnectivityCheckTest.kt | 65 ++++++ .../com/android/testutils/ConnectUtil.kt | 203 ++++++++++++++++++ .../ConnectivityCheckTargetPreparer.kt | 77 +++++++ 6 files changed, 417 insertions(+) create mode 100644 staticlibs/testutils/app/connectivitychecker/Android.bp create mode 100644 staticlibs/testutils/app/connectivitychecker/AndroidManifest.xml create mode 100644 staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitychecker/ConnectivityCheckTest.kt create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt create mode 100644 staticlibs/testutils/host/com/android/testutils/ConnectivityCheckTargetPreparer.kt diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index b7297bb8b5..9fd30f7001 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -61,3 +61,14 @@ java_library { "kotlin-test" ] } + +java_test_host { + name: "net-tests-utils-host-common", + srcs: [ + "host/**/*.java", + "host/**/*.kt", + ], + libs: ["tradefed"], + test_suites: ["device-tests", "general-tests", "cts", "mts"], + data: [":ConnectivityChecker"], +} diff --git a/staticlibs/testutils/app/connectivitychecker/Android.bp b/staticlibs/testutils/app/connectivitychecker/Android.bp new file mode 100644 index 0000000000..55b585aec5 --- /dev/null +++ b/staticlibs/testutils/app/connectivitychecker/Android.bp @@ -0,0 +1,29 @@ +// Copyright (C) 2021 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. + +android_test_helper_app { + name: "ConnectivityChecker", + srcs: ["src/**/*.kt"], + sdk_version: "system_current", + // Allow running the test on any device with SDK Q+, even when built from a branch that uses + // an unstable SDK, by targeting a stable SDK regardless of the build SDK. + min_sdk_version: "29", + target_sdk_version: "30", + static_libs: [ + "androidx.test.rules", + "modules-utils-build_system", + "net-tests-utils", + ], + host_required: ["net-tests-utils-host-common"], +} \ No newline at end of file diff --git a/staticlibs/testutils/app/connectivitychecker/AndroidManifest.xml b/staticlibs/testutils/app/connectivitychecker/AndroidManifest.xml new file mode 100644 index 0000000000..8e5958c316 --- /dev/null +++ b/staticlibs/testutils/app/connectivitychecker/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + diff --git a/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitychecker/ConnectivityCheckTest.kt b/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitychecker/ConnectivityCheckTest.kt new file mode 100644 index 0000000000..43b130b27b --- /dev/null +++ b/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitychecker/ConnectivityCheckTest.kt @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2021 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 com.android.testutils.connectivitychecker + +import android.content.pm.PackageManager.FEATURE_TELEPHONY +import android.content.pm.PackageManager.FEATURE_WIFI +import android.telephony.TelephonyManager +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import com.android.testutils.ConnectUtil +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.test.assertTrue +import kotlin.test.fail + +@RunWith(AndroidJUnit4::class) +class ConnectivityCheckTest { + val context by lazy { InstrumentationRegistry.getInstrumentation().context } + val pm by lazy { context.packageManager } + + @Test + fun testCheckDeviceSetup() { + checkWifiSetup() + checkTelephonySetup() + } + + private fun checkWifiSetup() { + if (!pm.hasSystemFeature(FEATURE_WIFI)) return + ConnectUtil(context).ensureWifiConnected() + } + + private fun checkTelephonySetup() { + if (!pm.hasSystemFeature(FEATURE_TELEPHONY)) return + val tm = context.getSystemService(TelephonyManager::class.java) + ?: fail("Could not get telephony service") + + val commonError = "Check the test bench. To run the tests anyway for quick & dirty local " + + "testing, you can use atest X -- " + + "--test-arg com.android.testutils.ConnectivityCheckTargetPreparer:disable:true" + // Do not use assertEquals: it outputs "expected X, was Y", which looks like a test failure + if (tm.simState == TelephonyManager.SIM_STATE_ABSENT) { + fail("The device has no SIM card inserted. " + commonError) + } else if (tm.simState != TelephonyManager.SIM_STATE_READY) { + fail("The device is not setup with a usable SIM card. Sim state was ${tm.simState}. " + + commonError) + } + assertTrue(tm.isDataConnectivityPossible, + "The device is not setup with a SIM card that supports data connectivity. " + + commonError) + } +} \ No newline at end of file diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt new file mode 100644 index 0000000000..fc951d862e --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2021 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 com.android.testutils + +import android.Manifest.permission +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.net.ConnectivityManager +import android.net.Network +import android.net.NetworkCapabilities.TRANSPORT_WIFI +import android.net.NetworkRequest +import android.net.wifi.ScanResult +import android.net.wifi.WifiConfiguration +import android.net.wifi.WifiManager +import android.os.ParcelFileDescriptor +import android.os.SystemClock +import android.util.Log +import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation +import java.util.concurrent.CompletableFuture +import java.util.concurrent.TimeUnit +import kotlin.test.assertNotNull +import kotlin.test.assertTrue +import kotlin.test.fail + +private const val MAX_WIFI_CONNECT_RETRIES = 10 +private const val WIFI_CONNECT_INTERVAL_MS = 500L +private const val WIFI_CONNECT_TIMEOUT_MS = 30_000L + +// Constants used by WifiManager.ActionListener#onFailure. Although onFailure is SystemApi, +// the error code constants are not (b/204277752) +private const val WIFI_ERROR_IN_PROGRESS = 1 +private const val WIFI_ERROR_BUSY = 2 + +class ConnectUtil(private val context: Context) { + private val TAG = ConnectUtil::class.java.simpleName + + private val cm = context.getSystemService(ConnectivityManager::class.java) + ?: fail("Could not find ConnectivityManager") + private val wifiManager = context.getSystemService(WifiManager::class.java) + ?: fail("Could not find WifiManager") + + fun ensureWifiConnected(): Network { + val callback = TestableNetworkCallback() + cm.registerNetworkCallback(NetworkRequest.Builder() + .addTransportType(TRANSPORT_WIFI) + .build(), callback) + + try { + val connInfo = wifiManager.connectionInfo + if (connInfo == null || connInfo.networkId == -1) { + clearWifiBlocklist() + val pfd = getInstrumentation().uiAutomation.executeShellCommand("svc wifi enable") + // Read the output stream to ensure the command has completed + ParcelFileDescriptor.AutoCloseInputStream(pfd).use { it.readBytes() } + val config = getOrCreateWifiConfiguration() + connectToWifiConfig(config) + } + val cb = callback.eventuallyExpectOrNull( + timeoutMs = WIFI_CONNECT_TIMEOUT_MS) + + assertNotNull(cb, "Could not connect to a wifi access point within " + + "$WIFI_CONNECT_INTERVAL_MS ms. Check that the test device has a wifi network " + + "configured, and that the test access point is functioning properly.") + return cb.network + } finally { + cm.unregisterNetworkCallback(callback) + } + } + + private fun connectToWifiConfig(config: WifiConfiguration) { + repeat(MAX_WIFI_CONNECT_RETRIES) { + val error = runAsShell(permission.NETWORK_SETTINGS) { + val listener = ConnectWifiListener() + wifiManager.connect(config, listener) + listener.connectFuture.get(WIFI_CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS) + } ?: return // Connect succeeded + + // Only retry for IN_PROGRESS and BUSY + if (error != WIFI_ERROR_IN_PROGRESS && error != WIFI_ERROR_BUSY) { + fail("Failed to connect to " + config.SSID + ": " + error) + } + Log.w(TAG, "connect failed with $error; waiting before retry") + SystemClock.sleep(WIFI_CONNECT_INTERVAL_MS) + } + fail("Failed to connect to ${config.SSID} after $MAX_WIFI_CONNECT_RETRIES retries") + } + + private class ConnectWifiListener : WifiManager.ActionListener { + /** + * Future completed when the connect process ends. Provides the error code or null if none. + */ + val connectFuture = CompletableFuture() + override fun onSuccess() { + connectFuture.complete(null) + } + + override fun onFailure(reason: Int) { + connectFuture.complete(reason) + } + } + + private fun getOrCreateWifiConfiguration(): WifiConfiguration { + val configs = runAsShell(permission.NETWORK_SETTINGS) { + wifiManager.getConfiguredNetworks() + } + // If no network is configured, add a config for virtual access points if applicable + if (configs.size == 0) { + val scanResults = getWifiScanResults() + val virtualConfig = maybeConfigureVirtualNetwork(scanResults) + assertNotNull(virtualConfig, "The device has no configured wifi network") + return virtualConfig + } + // No need to add a configuration: there is already one. + if (configs.size > 1) { + // For convenience in case of local testing on devices with multiple saved configs, + // prefer the first configuration that is in range. + // In actual tests, there should only be one configuration, and it should be usable as + // assumed by WifiManagerTest.testConnect. + Log.w(TAG, "Multiple wifi configurations found: " + + configs.joinToString(", ") { it.SSID }) + val scanResultsList = getWifiScanResults() + Log.i(TAG, "Scan results: " + scanResultsList.joinToString(", ") { + "${it.SSID} (${it.level})" + }) + + val scanResults = scanResultsList.map { "\"${it.SSID}\"" }.toSet() + return configs.firstOrNull { scanResults.contains(it.SSID) } ?: configs[0] + } + return configs[0] + } + + private fun getWifiScanResults(): List { + val scanResultsFuture = CompletableFuture>() + runAsShell(permission.NETWORK_SETTINGS) { + val receiver: BroadcastReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + scanResultsFuture.complete(wifiManager.scanResults) + } + } + context.registerReceiver(receiver, + IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) + wifiManager.startScan() + } + return try { + scanResultsFuture.get(WIFI_CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS) + } catch (e: Exception) { + throw AssertionError("Wifi scan results not received within timeout", e) + } + } + + /** + * If a virtual wifi network is detected, add a configuration for that network. + * TODO(b/158150376): have the test infrastructure add virtual wifi networks when appropriate. + */ + private fun maybeConfigureVirtualNetwork(scanResults: List): WifiConfiguration? { + // Virtual wifi networks used on the emulator and cloud testing infrastructure + val virtualSsids = listOf("VirtWifi", "AndroidWifi") + Log.d(TAG, "Wifi scan results: $scanResults") + val virtualScanResult = scanResults.firstOrNull { virtualSsids.contains(it.SSID) } + ?: return null + + // Only add the virtual configuration if the virtual AP is detected in scans + val virtualConfig = WifiConfiguration() + // ASCII SSIDs need to be surrounded by double quotes + virtualConfig.SSID = "\"${virtualScanResult.SSID}\"" + virtualConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE) + runAsShell(permission.NETWORK_SETTINGS) { + val networkId = wifiManager.addNetwork(virtualConfig) + assertTrue(networkId >= 0) + assertTrue(wifiManager.enableNetwork(networkId, false /* attemptConnect */)) + } + return virtualConfig + } + + /** + * Re-enable wifi networks that were blocked, typically because no internet connection was + * detected the last time they were connected. This is necessary to make sure wifi can reconnect + * to them. + */ + private fun clearWifiBlocklist() { + runAsShell(permission.NETWORK_SETTINGS, permission.ACCESS_WIFI_STATE) { + for (cfg in wifiManager.configuredNetworks) { + assertTrue(wifiManager.enableNetwork(cfg.networkId, false /* attemptConnect */)) + } + } + } +} \ No newline at end of file diff --git a/staticlibs/testutils/host/com/android/testutils/ConnectivityCheckTargetPreparer.kt b/staticlibs/testutils/host/com/android/testutils/ConnectivityCheckTargetPreparer.kt new file mode 100644 index 0000000000..85589ad9e6 --- /dev/null +++ b/staticlibs/testutils/host/com/android/testutils/ConnectivityCheckTargetPreparer.kt @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2021 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 com.android.testutils + +import com.android.ddmlib.testrunner.TestResult +import com.android.tradefed.invoker.TestInformation +import com.android.tradefed.result.CollectingTestListener +import com.android.tradefed.result.ddmlib.DefaultRemoteAndroidTestRunner +import com.android.tradefed.targetprep.BaseTargetPreparer +import com.android.tradefed.targetprep.suite.SuiteApkInstaller + +private const val CONNECTIVITY_CHECKER_APK = "ConnectivityChecker.apk" +private const val CONNECTIVITY_PKG_NAME = "com.android.testutils.connectivitychecker" +// As per the defined in the checker manifest +private const val CONNECTIVITY_CHECK_RUNNER_NAME = "androidx.test.runner.AndroidJUnitRunner" + +/** + * A target preparer that verifies that the device was setup correctly for connectivity tests. + * + * For quick and dirty local testing, can be disabled by running tests with + * "atest -- --test-arg com.android.testutils.ConnectivityCheckTargetPreparer:disable:true". + */ +class ConnectivityCheckTargetPreparer : BaseTargetPreparer() { + val installer = SuiteApkInstaller() + + override fun setUp(testInformation: TestInformation) { + if (isDisabled) return + installer.setCleanApk(true) + installer.addTestFileName(CONNECTIVITY_CHECKER_APK) + installer.setShouldGrantPermission(true) + installer.setUp(testInformation) + + val runner = DefaultRemoteAndroidTestRunner( + CONNECTIVITY_PKG_NAME, + CONNECTIVITY_CHECK_RUNNER_NAME, + testInformation.device.iDevice) + runner.runOptions = "--no-hidden-api-checks" + + val receiver = CollectingTestListener() + if (!testInformation.device.runInstrumentationTests(runner, receiver)) { + throw AssertionError("Device state check failed to complete") + } + + val runResult = receiver.currentRunResults + if (runResult.isRunFailure) { + throw AssertionError("Failed to check device state before the test: " + + runResult.runFailureMessage) + } + + if (!runResult.hasFailedTests()) return + val errorMsg = runResult.testResults.mapNotNull { (testDescription, testResult) -> + if (TestResult.TestStatus.FAILURE != testResult.status) null + else "$testDescription: ${testResult.stackTrace}" + }.joinToString("\n") + + throw AssertionError("Device setup checks failed. Check the test bench: \n$errorMsg") + } + + override fun tearDown(testInformation: TestInformation?, e: Throwable?) { + if (isTearDownDisabled) return + installer.tearDown(testInformation, e) + } +} \ No newline at end of file From 2c0b10cb0aba96548ee6f25ce7abcc82dccf4ca8 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Tue, 17 Aug 2021 14:26:27 +0000 Subject: [PATCH 269/777] Add data structures to parse netlink route messages. Bug: 163492391 Test: atest NetworkStaticLibsTests Change-Id: If8c960849f4840b7c516c0d2579da8a805978e13 --- .../module/util/netlink/NetlinkConstants.java | 14 ++ .../module/util/netlink/NetlinkMessage.java | 3 + .../util/netlink/RtNetlinkRouteMessage.java | 193 ++++++++++++++++++ .../net/module/util/netlink/StructRtMsg.java | 95 +++++++++ .../netlink/RtNetlinkRouteMessageTest.java | 193 ++++++++++++++++++ 5 files changed, 498 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java create mode 100644 staticlibs/device/com/android/net/module/util/netlink/StructRtMsg.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java index 07b52d8c98..83a82b74bd 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java @@ -146,12 +146,26 @@ public class NetlinkConstants { public static final int RTMGRP_LINK = 1; public static final int RTMGRP_IPV4_IFADDR = 0x10; public static final int RTMGRP_IPV6_IFADDR = 0x100; + public static final int RTMGRP_IPV6_ROUTE = 0x400; public static final int RTNLGRP_ND_USEROPT = 20; public static final int RTMGRP_ND_USEROPT = 1 << (RTNLGRP_ND_USEROPT - 1); // Device flags. public static final int IFF_LOWER_UP = 1 << 16; + // Known values for struct rtmsg rtm_protocol. + public static final short RTPROT_KERNEL = 2; + public static final short RTPROT_RA = 9; + + // Known values for struct rtmsg rtm_scope. + public static final short RT_SCOPE_UNIVERSE = 0; + + // Known values for struct rtmsg rtm_type. + public static final short RTN_UNICAST = 1; + + // Known values for struct rtmsg rtm_flags. + public static final int RTM_F_CLONED = 0x200; + /** * Convert a netlink message type to a string for control message. */ diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java index 708736e54a..a216752b42 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java @@ -126,6 +126,9 @@ public class NetlinkMessage { case NetlinkConstants.RTM_NEWADDR: case NetlinkConstants.RTM_DELADDR: return (NetlinkMessage) RtNetlinkAddressMessage.parse(nlmsghdr, byteBuffer); + case NetlinkConstants.RTM_NEWROUTE: + case NetlinkConstants.RTM_DELROUTE: + return (NetlinkMessage) RtNetlinkRouteMessage.parse(nlmsghdr, byteBuffer); case NetlinkConstants.RTM_NEWNEIGH: case NetlinkConstants.RTM_DELNEIGH: case NetlinkConstants.RTM_GETNEIGH: diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java new file mode 100644 index 0000000000..c5efcb2651 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.netlink; + +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + +import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY; +import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ANY; + +import android.net.IpPrefix; +import android.system.OsConstants; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; + +/** + * A NetlinkMessage subclass for rtnetlink route messages. + * + * RtNetlinkRouteMessage.parse() must be called with a ByteBuffer that contains exactly one + * netlink message. + * + * see also: + * + * include/uapi/linux/rtnetlink.h + * + * @hide + */ +public class RtNetlinkRouteMessage extends NetlinkMessage { + public static final short RTA_DST = 1; + public static final short RTA_OIF = 4; + public static final short RTA_GATEWAY = 5; + + private int mIfindex; + @NonNull + private StructRtMsg mRtmsg; + @NonNull + private IpPrefix mDestination; + @Nullable + private InetAddress mGateway; + + private RtNetlinkRouteMessage(StructNlMsgHdr header) { + super(header); + mRtmsg = null; + mDestination = null; + mGateway = null; + mIfindex = 0; + } + + public int getInterfaceIndex() { + return mIfindex; + } + + @NonNull + public StructRtMsg getRtMsgHeader() { + return mRtmsg; + } + + @NonNull + public IpPrefix getDestination() { + return mDestination; + } + + @Nullable + public InetAddress getGateway() { + return mGateway; + } + + /** + * Check whether the address families of destination and gateway match rtm_family in + * StructRtmsg. + * + * For example, IPv4-mapped IPv6 addresses as an IPv6 address will be always converted to IPv4 + * address, that's incorrect when upper layer creates a new {@link RouteInfo} class instance + * for IPv6 route with the converted IPv4 gateway. + */ + private static boolean matchRouteAddressFamily(@NonNull final InetAddress address, + int family) { + return ((address instanceof Inet4Address) && (family == AF_INET)) + || ((address instanceof Inet6Address) && (family == AF_INET6)); + } + + /** + * Parse rtnetlink route message from {@link ByteBuffer}. This method must be called with a + * ByteBuffer that contains exactly one netlink message. + * + * @param header netlink message header. + * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. + */ + @Nullable + public static RtNetlinkRouteMessage parse(@NonNull final StructNlMsgHdr header, + @NonNull final ByteBuffer byteBuffer) { + final RtNetlinkRouteMessage routeMsg = new RtNetlinkRouteMessage(header); + + routeMsg.mRtmsg = StructRtMsg.parse(byteBuffer); + if (routeMsg.mRtmsg == null) return null; + int rtmFamily = routeMsg.mRtmsg.family; + + // RTA_DST + final int baseOffset = byteBuffer.position(); + StructNlAttr nlAttr = StructNlAttr.findNextAttrOfType(RTA_DST, byteBuffer); + if (nlAttr != null) { + final InetAddress destination = nlAttr.getValueAsInetAddress(); + // If the RTA_DST attribute is malformed, return null. + if (destination == null) return null; + // If the address family of destination doesn't match rtm_family, return null. + if (!matchRouteAddressFamily(destination, rtmFamily)) return null; + routeMsg.mDestination = new IpPrefix(destination, routeMsg.mRtmsg.dstLen); + } else if (rtmFamily == AF_INET) { + routeMsg.mDestination = new IpPrefix(IPV4_ADDR_ANY, 0); + } else if (rtmFamily == AF_INET6) { + routeMsg.mDestination = new IpPrefix(IPV6_ADDR_ANY, 0); + } else { + return null; + } + + // RTA_GATEWAY + byteBuffer.position(baseOffset); + nlAttr = StructNlAttr.findNextAttrOfType(RTA_GATEWAY, byteBuffer); + if (nlAttr != null) { + routeMsg.mGateway = nlAttr.getValueAsInetAddress(); + // If the RTA_GATEWAY attribute is malformed, return null. + if (routeMsg.mGateway == null) return null; + // If the address family of gateway doesn't match rtm_family, return null. + if (!matchRouteAddressFamily(routeMsg.mGateway, rtmFamily)) return null; + } + + // RTA_OIF + byteBuffer.position(baseOffset); + nlAttr = StructNlAttr.findNextAttrOfType(RTA_OIF, byteBuffer); + if (nlAttr != null) { + // Any callers that deal with interface names are responsible for converting + // the interface index to a name themselves. This may not succeed or may be + // incorrect, because the interface might have been deleted, or even deleted + // and re-added with a different index, since the netlink message was sent. + routeMsg.mIfindex = nlAttr.getValueAsInt(0 /* 0 isn't a valid ifindex */); + } + + return routeMsg; + } + + /** + * Write a rtnetlink address message to {@link ByteBuffer}. + */ + @VisibleForTesting + protected void pack(ByteBuffer byteBuffer) { + getHeader().pack(byteBuffer); + mRtmsg.pack(byteBuffer); + + final StructNlAttr destination = new StructNlAttr(RTA_DST, mDestination.getAddress()); + destination.pack(byteBuffer); + + if (mGateway != null) { + final StructNlAttr gateway = new StructNlAttr(RTA_GATEWAY, mGateway.getAddress()); + gateway.pack(byteBuffer); + } + if (mIfindex != 0) { + final StructNlAttr ifindex = new StructNlAttr(RTA_OIF, mIfindex); + ifindex.pack(byteBuffer); + } + } + + @Override + public String toString() { + return "RtNetlinkRouteMessage{ " + + "nlmsghdr{" + mHeader.toString(OsConstants.NETLINK_ROUTE) + "}, " + + "Rtmsg{" + mRtmsg.toString() + "}, " + + "destination{" + mDestination.getAddress().getHostAddress() + "}, " + + "gateway{" + (mGateway == null ? "" : mGateway.getHostAddress()) + "}, " + + "ifindex{" + mIfindex + "} " + + "}"; + } +} diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructRtMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructRtMsg.java new file mode 100644 index 0000000000..3cd729222b --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/StructRtMsg.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.netlink; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.nio.ByteBuffer; + +/** + * struct rtmsg + * + * see also: + * + * include/uapi/linux/rtnetlink.h + * + * @hide + */ +public class StructRtMsg extends Struct { + // Already aligned. + public static final int STRUCT_SIZE = 12; + + @Field(order = 0, type = Type.U8) + public final short family; // Address family of route. + @Field(order = 1, type = Type.U8) + public final short dstLen; // Length of destination. + @Field(order = 2, type = Type.U8) + public final short srcLen; // Length of source. + @Field(order = 3, type = Type.U8) + public final short tos; // TOS filter. + @Field(order = 4, type = Type.U8) + public final short table; // Routing table ID. + @Field(order = 5, type = Type.U8) + public final short protocol; // Routing protocol. + @Field(order = 6, type = Type.U8) + public final short scope; // distance to the destination. + @Field(order = 7, type = Type.U8) + public final short type; // route type + @Field(order = 8, type = Type.U32) + public final long flags; + + StructRtMsg(short family, short dstLen, short srcLen, short tos, short table, short protocol, + short scope, short type, long flags) { + this.family = family; + this.dstLen = dstLen; + this.srcLen = srcLen; + this.tos = tos; + this.table = table; + this.protocol = protocol; + this.scope = scope; + this.type = type; + this.flags = flags; + } + + /** + * Parse a rtmsg struct from a {@link ByteBuffer}. + * + * @param byteBuffer The buffer from which to parse the rtmsg struct. + * @return the parsed rtmsg struct, or {@code null} if the rtmsg struct could not be + * parsed successfully (for example, if it was truncated). + */ + @Nullable + public static StructRtMsg parse(@NonNull final ByteBuffer byteBuffer) { + if (byteBuffer.remaining() < STRUCT_SIZE) return null; + + // The ByteOrder must already have been set to native order. + return Struct.parse(StructRtMsg.class, byteBuffer); + } + + /** + * Write the rtmsg struct to {@link ByteBuffer}. + */ + public void pack(@NonNull final ByteBuffer byteBuffer) { + // The ByteOrder must already have been set to native order. + this.writeToByteBuffer(byteBuffer); + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java new file mode 100644 index 0000000000..392314fbb4 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.netlink; + +import static android.system.OsConstants.NETLINK_ROUTE; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.net.InetAddresses; +import android.net.IpPrefix; +import android.system.OsConstants; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.net.module.util.HexDump; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet6Address; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class RtNetlinkRouteMessageTest { + private static final IpPrefix TEST_IPV6_GLOBAL_PREFIX = new IpPrefix("2001:db8:1::/64"); + private static final Inet6Address TEST_IPV6_LINK_LOCAL_GATEWAY = + (Inet6Address) InetAddresses.parseNumericAddress("fe80::1"); + + // An example of the full RTM_NEWROUTE message. + private static final String RTM_NEWROUTE_HEX = + "88000000180000060000000000000000" // struct nlmsghr + + "0A400000FC02000100000000" // struct rtmsg + + "08000F00C7060000" // RTA_TABLE + + "1400010020010DB8000100000000000000000000" // RTA_DST + + "08000400DF020000" // RTA_OIF + + "0800060000010000" // RTA_PRIORITY + + "24000C0000000000000000005EEA000000000000" // RTA_CACHEINFO + + "00000000000000000000000000000000" + + "14000500FE800000000000000000000000000001" // RTA_GATEWAY + + "0500140000000000"; // RTA_PREF + + private ByteBuffer toByteBuffer(final String hexString) { + return ByteBuffer.wrap(HexDump.hexStringToByteArray(hexString)); + } + + @Test + public void testParseRtmRouteAddress() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkRouteMessage); + final RtNetlinkRouteMessage routeMsg = (RtNetlinkRouteMessage) msg; + + final StructNlMsgHdr hdr = routeMsg.getHeader(); + assertNotNull(hdr); + assertEquals(136, hdr.nlmsg_len); + assertEquals(NetlinkConstants.RTM_NEWROUTE, hdr.nlmsg_type); + assertEquals(0x600, hdr.nlmsg_flags); + assertEquals(0, hdr.nlmsg_seq); + assertEquals(0, hdr.nlmsg_pid); + + final StructRtMsg rtmsg = routeMsg.getRtMsgHeader(); + assertNotNull(rtmsg); + assertEquals((byte) OsConstants.AF_INET6, rtmsg.family); + assertEquals(64, rtmsg.dstLen); + assertEquals(0, rtmsg.srcLen); + assertEquals(0, rtmsg.tos); + assertEquals(0xFC, rtmsg.table); + assertEquals(NetlinkConstants.RTPROT_KERNEL, rtmsg.protocol); + assertEquals(NetlinkConstants.RT_SCOPE_UNIVERSE, rtmsg.scope); + assertEquals(NetlinkConstants.RTN_UNICAST, rtmsg.type); + assertEquals(0, rtmsg.flags); + + assertEquals(routeMsg.getDestination(), TEST_IPV6_GLOBAL_PREFIX); + assertEquals(735, routeMsg.getInterfaceIndex()); + assertEquals((Inet6Address) routeMsg.getGateway(), TEST_IPV6_LINK_LOCAL_GATEWAY); + } + + private static final String RTM_NEWROUTE_PACK_HEX = + "4C000000180000060000000000000000" // struct nlmsghr + + "0A400000FC02000100000000" // struct rtmsg + + "1400010020010DB8000100000000000000000000" // RTA_DST + + "14000500FE800000000000000000000000000001" // RTA_GATEWAY + + "08000400DF020000"; // RTA_OIF + + @Test + public void testPackRtmNewRoute() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_PACK_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkRouteMessage); + final RtNetlinkRouteMessage routeMsg = (RtNetlinkRouteMessage) msg; + + final ByteBuffer packBuffer = ByteBuffer.allocate(76); + packBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + routeMsg.pack(packBuffer); + assertEquals(RTM_NEWROUTE_PACK_HEX, HexDump.toHexString(packBuffer.array())); + } + + private static final String RTM_NEWROUTE_TRUNCATED_HEX = + "48000000180000060000000000000000" // struct nlmsghr + + "0A400000FC02000100000000" // struct rtmsg + + "1400010020010DB8000100000000000000000000" // RTA_DST + + "10000500FE8000000000000000000000" // RTA_GATEWAY(truncated) + + "08000400DF020000"; // RTA_OIF + + @Test + public void testTruncatedRtmNewRoute() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_TRUNCATED_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + // Parsing RTM_NEWROUTE with truncated RTA_GATEWAY attribute returns null. + assertNull(msg); + } + + private static final String RTM_NEWROUTE_IPV4_MAPPED_IPV6_GATEWAY_HEX = + "4C000000180000060000000000000000" // struct nlmsghr + + "0A400000FC02000100000000" // struct rtmsg + + "1400010020010DB8000100000000000000000000" // RTA_DST(2001:db8:1::/64) + + "1400050000000000000000000000FFFF0A010203" // RTA_GATEWAY(::ffff:10.1.2.3) + + "08000400DF020000"; // RTA_OIF + + @Test + public void testParseRtmRouteAddress_IPv4MappedIPv6Gateway() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_IPV4_MAPPED_IPV6_GATEWAY_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + // Parsing RTM_NEWROUTE with IPv4-mapped IPv6 gateway address, which doesn't match + // rtm_family after address parsing. + assertNull(msg); + } + + private static final String RTM_NEWROUTE_IPV4_MAPPED_IPV6_DST_HEX = + "4C000000180000060000000000000000" // struct nlmsghr + + "0A780000FC02000100000000" // struct rtmsg + + "1400010000000000000000000000FFFF0A000000" // RTA_DST(::ffff:10.0.0.0/120) + + "14000500FE800000000000000000000000000001" // RTA_GATEWAY(fe80::1) + + "08000400DF020000"; // RTA_OIF + + @Test + public void testParseRtmRouteAddress_IPv4MappedIPv6Destination() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_IPV4_MAPPED_IPV6_DST_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + // Parsing RTM_NEWROUTE with IPv4-mapped IPv6 destination prefix, which doesn't match + // rtm_family after address parsing. + assertNull(msg); + } + + @Test + public void testToString() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkRouteMessage); + final RtNetlinkRouteMessage routeMsg = (RtNetlinkRouteMessage) msg; + final String expected = "RtNetlinkRouteMessage{ " + + "nlmsghdr{" + + "StructNlMsgHdr{ nlmsg_len{136}, nlmsg_type{24(RTM_NEWROUTE)}, " + + "nlmsg_flags{1536(NLM_F_MATCH)}, nlmsg_seq{0}, nlmsg_pid{0} }}, " + + "Rtmsg{" + + "family: 10, dstLen: 64, srcLen: 0, tos: 0, table: 252, protocol: 2, " + + "scope: 0, type: 1, flags: 0}, " + + "destination{2001:db8:1::}, " + + "gateway{fe80::1}, " + + "ifindex{735} " + + "}"; + assertEquals(expected, routeMsg.toString()); + } +} From 6e33f78dfdd3a9a9018df831bab2c07e5d20b078 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 12 Aug 2021 14:21:52 +0900 Subject: [PATCH 270/777] Move TETHERING_MODULE_NAME to libs/net The constant is useful for both Connectivity and Tethering when they want to check the APEX version. Include it in DeviceConfigUtils, as this is what it will be used for. Bug: Test: atest ConnectivityServiceTest Change-Id: Ib7a7677ca2954974613df25a105a65fe5d971afc --- .../com/android/net/module/util/DeviceConfigUtils.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index 77b7835b9e..30a1c33208 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -35,6 +35,12 @@ public final class DeviceConfigUtils { private DeviceConfigUtils() {} private static final String TAG = DeviceConfigUtils.class.getSimpleName(); + /** + * DO NOT MODIFY: this may be used by multiple modules that will not see the updated value + * until they are recompiled, so modifying this constant means that different modules may + * be referencing a different tethering module variant, or having a stale reference. + */ + public static final String TETHERING_MODULE_NAME = "com.android.tethering"; @VisibleForTesting public static void resetPackageVersionCacheForTest() { From a14fb38df4d1dd02ebc3e8ab08fe2bc8ac951965 Mon Sep 17 00:00:00 2001 From: markchien Date: Mon, 8 Nov 2021 21:25:36 +0800 Subject: [PATCH 271/777] Add JniUtil to identify jni library by package name Bug: 205088391 Test: atest NetworkStaticLibTests Change-Id: I4ace7803f246bb396f53d878064fec1204e7c1ef --- staticlibs/Android.bp | 1 + .../com/android/net/module/util/JniUtil.java | 35 +++++++++++++++++ .../android/net/module/util/JniUtilTest.kt | 38 +++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/JniUtil.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/JniUtilTest.kt diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index f1e7c85e55..93084ccaef 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -103,6 +103,7 @@ java_library { "device/com/android/net/module/util/BpfMap.java", "device/com/android/net/module/util/HexDump.java", "device/com/android/net/module/util/Ipv6Utils.java", + "device/com/android/net/module/util/JniUtil.java", "device/com/android/net/module/util/Struct.java", "device/com/android/net/module/util/netlink/*.java", "device/com/android/net/module/util/structs/*.java", diff --git a/staticlibs/device/com/android/net/module/util/JniUtil.java b/staticlibs/device/com/android/net/module/util/JniUtil.java new file mode 100644 index 0000000000..5210a3ef0e --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/JniUtil.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util; + +/** + * Utilities for modules to use jni. + */ +public final class JniUtil { + /** + * The method to find jni library accroding to the giving package name. + * + * The jni library name would be packageName + _jni.so. E.g. + * com_android_networkstack_tethering_util_jni for tethering, + * com_android_connectivity_util_jni for connectivity. + */ + public static String getJniLibraryName(final Package pkg) { + final String libPrefix = pkg.getName().replaceAll("\\.", "_"); + + return libPrefix + "_jni"; + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/JniUtilTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/JniUtilTest.kt new file mode 100644 index 0000000000..7574087780 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/JniUtilTest.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util + +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import kotlin.test.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@SmallTest +public final class JniUtilTest { + private val TEST_JAVA_UTIL_NAME = "java_util_jni" + private val TEST_ORG_JUNIT_NAME = "org_junit_jni" + + @Test + fun testGetJniLibraryName() { + assertEquals(TEST_JAVA_UTIL_NAME, + JniUtil.getJniLibraryName(java.util.Set::class.java.getPackage())) + assertEquals(TEST_ORG_JUNIT_NAME, + JniUtil.getJniLibraryName(org.junit.Before::class.java.getPackage())) + } +} From a5cbda3ca8e52194bc3f094a9a6f3d047291def0 Mon Sep 17 00:00:00 2001 From: markchien Date: Tue, 9 Nov 2021 16:59:50 +0800 Subject: [PATCH 272/777] Use JniUtil.getJniLibraryName to find library name Bug: 205088391 Test: atest TetheringTests atest CtsTetheringTest atest TetheringPrivilegedTests Change-Id: Ie865f6ef828a7a706ed76cafadc0403511a28cff --- staticlibs/device/com/android/net/module/util/BpfMap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java index aa74152833..5f05c7c90b 100644 --- a/staticlibs/device/com/android/net/module/util/BpfMap.java +++ b/staticlibs/device/com/android/net/module/util/BpfMap.java @@ -42,7 +42,7 @@ import java.util.function.BiConsumer; */ public class BpfMap implements AutoCloseable { static { - System.loadLibrary("tetherutilsjni"); + System.loadLibrary(JniUtil.getJniLibraryName(BpfMap.class.getPackage())); } // Following definitions from kernel include/uapi/linux/bpf.h From f3448f905a1b18087475657d3d237de8e388565b Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 10 Nov 2021 01:06:51 +0800 Subject: [PATCH 273/777] Separate bpf and struct util from netlink util library 1. Separate bpf and struct libraries from netlink library. 2. Rename bpfmap jni library to respect its java side library. 3. Add README to explain the rules of adding shared jni library. 4. Also allow packages/modules/Connectivity to use bpf library. Bug: 205088391 Test: atest TetheringTests atest CtsTetheringTest atest TetheringPrivilegedTests atest ConnectivityCoverageTests Change-Id: I6e668818bede63b241cd901c0967f401613ddaf6 --- staticlibs/Android.bp | 56 +++++++++++++++++++++++--- staticlibs/native/README.md | 27 +++++++++++++ staticlibs/native/bpfmapjni/Android.bp | 4 +- staticlibs/tests/unit/Android.bp | 1 + 4 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 staticlibs/native/README.md diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 93084ccaef..68decf67fb 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -95,17 +95,37 @@ filegroup { } java_library { - name: "net-utils-device-common-netlink", - // TODO: Ipv6Utils and Struct stuff could be separated out of the netlink library into - // an individual Struct library, and remove the net-utils-framework-common lib dependency. - // But there is no need doing this at the moment. + name: "net-utils-device-common-bpf", srcs: [ "device/com/android/net/module/util/BpfMap.java", + "device/com/android/net/module/util/JniUtil.java", + ], + sdk_version: "system_current", + min_sdk_version: "29", + visibility: [ + "//frameworks/libs/net/common/tests:__subpackages__", + "//frameworks/libs/net/common/testutils:__subpackages__", + "//packages/modules/Connectivity:__subpackages__", + "//packages/modules/NetworkStack:__subpackages__", + ], + static_libs: [ + "net-utils-device-common-struct", + ], + libs: [ + "androidx.annotation_annotation", + ], + apex_available: [ + "com.android.tethering", + "//apex_available:platform", + ], +} + +java_library { + name: "net-utils-device-common-struct", + srcs: [ "device/com/android/net/module/util/HexDump.java", "device/com/android/net/module/util/Ipv6Utils.java", - "device/com/android/net/module/util/JniUtil.java", "device/com/android/net/module/util/Struct.java", - "device/com/android/net/module/util/netlink/*.java", "device/com/android/net/module/util/structs/*.java", ], sdk_version: "system_current", @@ -127,6 +147,30 @@ java_library { ], } +java_library { + name: "net-utils-device-common-netlink", + srcs: [ + "device/com/android/net/module/util/netlink/*.java", + ], + sdk_version: "system_current", + min_sdk_version: "29", + visibility: [ + "//frameworks/libs/net/common/testutils:__subpackages__", + "//packages/modules/Connectivity:__subpackages__", + "//packages/modules/NetworkStack:__subpackages__", + ], + static_libs: [ + "net-utils-device-common-struct", + ], + libs: [ + "androidx.annotation_annotation", + ], + apex_available: [ + "com.android.tethering", + "//apex_available:platform", + ], +} + java_library { // TODO : this target should probably be folded into net-utils-device-common name: "net-utils-device-common-ip", diff --git a/staticlibs/native/README.md b/staticlibs/native/README.md new file mode 100644 index 0000000000..18d19c464e --- /dev/null +++ b/staticlibs/native/README.md @@ -0,0 +1,27 @@ +# JNI +As a general rule, jarjar every static library dependency used in a mainline module into the +modules's namespace (especially if it is also used by other modules) + +Fully-qualified name of java class needs to be hard-coded into the JNI .so, because JNI_OnLoad +does not take any parameters. This means that there needs to be a different .so target for each +post-jarjared package, so for each module. + +This is the guideline to provide JNI library shared with modules: + +* provide a common java library in frameworks/libs/net with the Java class (e.g. BpfMap.java). + +* provide a common native library in frameworks/libs/net with the JNI and provide the native + register function with class_name parameter. See register_com_android_net_module_util_BpfMap + function in frameworks/libs/net/common/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp + as an example. + +When you want to use JNI library from frameworks/lib/net: + +* Each module includes the java library (e.g. net-utils-device-common-bpf) and applies its jarjar + rules after build. + +* Each module creates a native library in their directory, which statically links against the + common native library (e.g. libnet_utils_device_common_bpf), and calls the native registered + function by hardcoding the post-jarjar class_name. + + diff --git a/staticlibs/native/bpfmapjni/Android.bp b/staticlibs/native/bpfmapjni/Android.bp index edbae7ced2..b7af22d335 100644 --- a/staticlibs/native/bpfmapjni/Android.bp +++ b/staticlibs/native/bpfmapjni/Android.bp @@ -17,7 +17,7 @@ package { } cc_library_static { - name: "libbpfmapjni", + name: "libnet_utils_device_common_bpfjni", srcs: ["com_android_net_module_util_BpfMap.cpp"], header_libs: [ "bpf_syscall_wrappers", @@ -39,6 +39,6 @@ cc_library_static { "//apex_available:platform", ], visibility: [ - "//packages/modules/Connectivity/Tethering", + "//packages/modules/Connectivity:__subpackages__", ], } diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index a9f9d70b27..07a8200cab 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -17,6 +17,7 @@ android_library { "androidx.test.rules", "mockito-target-extended-minus-junit4", "net-utils-device-common", + "net-utils-device-common-bpf", "net-tests-utils", "netd-client", ], From 891a3b9fb7465096e4f5db71b5375e0dd6618082 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Thu, 11 Nov 2021 10:10:56 -0800 Subject: [PATCH 274/777] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/libs/net Added SPDX-license-identifier-Apache-2.0 to: common/testutils/app/connectivitychecker/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Change-Id: I9e25f435ce9835f12a167e6c57e33f6d87c159de --- staticlibs/testutils/app/connectivitychecker/Android.bp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/staticlibs/testutils/app/connectivitychecker/Android.bp b/staticlibs/testutils/app/connectivitychecker/Android.bp index 55b585aec5..79a4343fc3 100644 --- a/staticlibs/testutils/app/connectivitychecker/Android.bp +++ b/staticlibs/testutils/app/connectivitychecker/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + android_test_helper_app { name: "ConnectivityChecker", srcs: ["src/**/*.kt"], @@ -26,4 +30,4 @@ android_test_helper_app { "net-tests-utils", ], host_required: ["net-tests-utils-host-common"], -} \ No newline at end of file +} From 307c3db71db8ba4ef1219e50aca2a1431598a282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 17 Nov 2021 10:57:50 -0800 Subject: [PATCH 275/777] switch to using OWNERS from master branch of Connectivity module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: N/A Signed-off-by: Maciej Żenczykowski Change-Id: If8c59abaf706b4c787be6454c08be3e26212ba21 --- staticlibs/native/OWNERS | 1 - 1 file changed, 1 deletion(-) delete mode 100644 staticlibs/native/OWNERS diff --git a/staticlibs/native/OWNERS b/staticlibs/native/OWNERS deleted file mode 100644 index 76553385b4..0000000000 --- a/staticlibs/native/OWNERS +++ /dev/null @@ -1 +0,0 @@ -maze@google.com From 7068c88921032b6d49ff5428b5b225e7a773cb2f Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Fri, 19 Nov 2021 15:37:30 +0800 Subject: [PATCH 276/777] Enable strict_updatability_linting in frameworks/libs/net Enable the strict_updatability_linting here first as a prior commit to enable strict_updatability_linting in connectivity modules. Bug: 188851968 Test: m lint-check ; atest NetworkStaticLibTests Change-Id: Idac98a1c85bf5bb86269b1daad2b444cfb58db8a --- staticlibs/Android.bp | 8 ++++ staticlibs/tests/unit/Android.bp | 4 +- staticlibs/tests/unit/lint-baseline.xml | 48 ------------------- .../util/LocationPermissionCheckerTest.java | 3 ++ .../util/NetworkCapabilitiesUtilsTest.kt | 6 ++- staticlibs/testutils/Android.bp | 4 +- .../app/connectivitychecker/Android.bp | 1 + 7 files changed, 23 insertions(+), 51 deletions(-) delete mode 100644 staticlibs/tests/unit/lint-baseline.xml diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index a9689f16bd..c6d64e4e14 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -70,6 +70,7 @@ java_library { "androidx.annotation_annotation", "framework-annotations-lib", ], + lint: { strict_updatability_linting: true }, } java_defaults { @@ -118,6 +119,7 @@ java_library { "com.android.tethering", "//apex_available:platform", ], + lint: { strict_updatability_linting: true }, } java_library { @@ -145,6 +147,7 @@ java_library { "com.android.tethering", "//apex_available:platform", ], + lint: { strict_updatability_linting: true }, } java_library { @@ -169,6 +172,7 @@ java_library { "com.android.tethering", "//apex_available:platform", ], + lint: { strict_updatability_linting: true }, } java_library { @@ -199,6 +203,7 @@ java_library { "com.android.tethering", "//apex_available:platform", ], + lint: { strict_updatability_linting: true }, } java_library { @@ -229,6 +234,7 @@ java_library { "//frameworks/libs/net/common/device", "//packages/modules/Wifi/framework/tests:__subpackages__", ], + lint: { strict_updatability_linting: true }, } filegroup { name: "net-utils-services-common-srcs", @@ -260,6 +266,7 @@ java_library { visibility: [ "//frameworks/base/services/net", ], + lint: { strict_updatability_linting: true }, } // Use a filegroup and not a library for telephony sources, as framework-annotations cannot be @@ -339,4 +346,5 @@ java_library { "//apex_available:anyapex", "//apex_available:platform", ], + lint: { strict_updatability_linting: true }, } diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index 07a8200cab..21e8c641a3 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -30,7 +30,8 @@ android_library { "//packages/modules/Connectivity/tests:__subpackages__", "//packages/modules/Connectivity/Tethering/tests:__subpackages__", "//packages/modules/NetworkStack/tests/integration", - ] + ], + lint: { strict_updatability_linting: true }, } android_test { @@ -46,4 +47,5 @@ android_test { ], jarjar_rules: "jarjar-rules.txt", test_suites: ["device-tests"], + lint: { strict_updatability_linting: true }, } diff --git a/staticlibs/tests/unit/lint-baseline.xml b/staticlibs/tests/unit/lint-baseline.xml deleted file mode 100644 index e3a6c1e184..0000000000 --- a/staticlibs/tests/unit/lint-baseline.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/LocationPermissionCheckerTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/LocationPermissionCheckerTest.java index 3fb1e929fe..84018a52ba 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/LocationPermissionCheckerTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/LocationPermissionCheckerTest.java @@ -42,6 +42,8 @@ import android.os.Process; import android.os.UserHandle; import android.os.UserManager; +import androidx.annotation.RequiresApi; + import com.android.testutils.DevSdkIgnoreRule; import org.junit.Assert; @@ -56,6 +58,7 @@ import org.mockito.stubbing.Answer; import java.util.HashMap; /** Unit tests for {@link LocationPermissionChecker}. */ +@RequiresApi(Build.VERSION_CODES.R) public class LocationPermissionCheckerTest { @Rule public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule( diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt index 5f15c6ac0c..f78c74e607 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt @@ -16,6 +16,7 @@ package com.android.net.module.util +import android.annotation.TargetApi import android.net.NetworkCapabilities import android.net.NetworkCapabilities.NET_CAPABILITY_CBS import android.net.NetworkCapabilities.NET_CAPABILITY_EIMS @@ -29,6 +30,7 @@ import android.net.NetworkCapabilities.TRANSPORT_TEST import android.net.NetworkCapabilities.TRANSPORT_VPN import android.net.NetworkCapabilities.TRANSPORT_WIFI import android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE +import android.os.Build import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import com.android.net.module.util.NetworkCapabilitiesUtils.RESTRICTED_CAPABILITIES @@ -88,7 +90,9 @@ class NetworkCapabilitiesUtilsTest { assertTrue(bits contentEquals unpackBits(packedBits)) } - @Test + // NetworkCapabilities constructor and Builder are not available until R. Mark TargetApi to + // ignore the linter error since it's used in only unit test. + @Test @TargetApi(Build.VERSION_CODES.R) fun testInferRestrictedCapability() { val nc = NetworkCapabilities() // Default capabilities don't have restricted capability. diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index 9fd30f7001..2f0bcc3951 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -38,6 +38,7 @@ java_library { "net-utils-device-common-netlink", "modules-utils-build_system", ], + lint: { strict_updatability_linting: true }, } java_library { @@ -59,7 +60,8 @@ java_library { ], static_libs: [ "kotlin-test" - ] + ], + lint: { strict_updatability_linting: true }, } java_test_host { diff --git a/staticlibs/testutils/app/connectivitychecker/Android.bp b/staticlibs/testutils/app/connectivitychecker/Android.bp index 79a4343fc3..58f22db7c5 100644 --- a/staticlibs/testutils/app/connectivitychecker/Android.bp +++ b/staticlibs/testutils/app/connectivitychecker/Android.bp @@ -30,4 +30,5 @@ android_test_helper_app { "net-tests-utils", ], host_required: ["net-tests-utils-host-common"], + lint: { strict_updatability_linting: true }, } From 0cf724af2777a1ab19e213cf228add022cce600a Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 19 Nov 2021 18:33:12 +0900 Subject: [PATCH 277/777] Fix libs/net tests package Move test classes that were not in the same com.android.module.util package as their associated class into the right package, and make net-utils-service-common visible to tests. Bug: 207020032 Test: atest ConnectivityCoverageTests Change-Id: Iabe86a7d4c2437b3d01d68d53fb01d4e3c05a02b --- staticlibs/Android.bp | 1 + .../src/com/android/{ => net}/module/util/DnsPacketTest.java | 0 .../net => com/android/net/module}/util/IpRangeTest.java | 4 +--- .../android/net/module}/util/LinkPropertiesUtilsTest.java | 3 +-- .../android/net/module}/util/MacAddressUtilsTest.java | 4 +--- .../net => com/android/net/module}/util/NetUtilsTest.java | 4 +--- 6 files changed, 5 insertions(+), 11 deletions(-) rename staticlibs/tests/unit/src/com/android/{ => net}/module/util/DnsPacketTest.java (100%) rename staticlibs/tests/unit/src/{android/net => com/android/net/module}/util/IpRangeTest.java (99%) rename staticlibs/tests/unit/src/{android/net => com/android/net/module}/util/LinkPropertiesUtilsTest.java (99%) rename staticlibs/tests/unit/src/{android/net => com/android/net/module}/util/MacAddressUtilsTest.java (97%) rename staticlibs/tests/unit/src/{android/net => com/android/net/module}/util/NetUtilsTest.java (98%) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 6a56889caf..fde9d3ee86 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -213,6 +213,7 @@ java_library { ], visibility: [ "//frameworks/base/services/net", + "//packages/modules/Connectivity/tests:__subpackages__", ], } diff --git a/staticlibs/tests/unit/src/com/android/module/util/DnsPacketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java similarity index 100% rename from staticlibs/tests/unit/src/com/android/module/util/DnsPacketTest.java rename to staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java diff --git a/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java similarity index 99% rename from staticlibs/tests/unit/src/android/net/util/IpRangeTest.java rename to staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java index 677db6956f..f44b17d751 100644 --- a/staticlibs/tests/unit/src/android/net/util/IpRangeTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -28,8 +28,6 @@ import android.net.IpPrefix; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.net.module.util.IpRange; - import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java similarity index 99% rename from staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java rename to staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java index 45493bd623..3d2d6ebaac 100644 --- a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import static com.android.testutils.MiscAsserts.assertSameElements; @@ -32,7 +32,6 @@ import android.util.ArraySet; import androidx.test.runner.AndroidJUnit4; -import com.android.net.module.util.LinkPropertiesUtils; import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult; import com.android.net.module.util.LinkPropertiesUtils.CompareResult; diff --git a/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/MacAddressUtilsTest.java similarity index 97% rename from staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java rename to staticlibs/tests/unit/src/com/android/net/module/util/MacAddressUtilsTest.java index 8988571d3e..2550756367 100644 --- a/staticlibs/tests/unit/src/android/net/util/MacAddressUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/MacAddressUtilsTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -24,8 +24,6 @@ import android.net.MacAddress; import androidx.test.runner.AndroidJUnit4; -import com.android.net.module.util.MacAddressUtils; - import org.junit.Test; import org.junit.runner.RunWith; diff --git a/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/NetUtilsTest.java similarity index 98% rename from staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java rename to staticlibs/tests/unit/src/com/android/net/module/util/NetUtilsTest.java index d523e14955..902c18ebe0 100644 --- a/staticlibs/tests/unit/src/android/net/util/NetUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetUtilsTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.util; +package com.android.net.module.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -27,8 +27,6 @@ import android.net.RouteInfo; import androidx.test.runner.AndroidJUnit4; -import com.android.net.module.util.NetUtils; - import org.junit.Test; import org.junit.runner.RunWith; From 38cf698179bf7636669e230cf0c9d5b03466dab7 Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Thu, 21 Oct 2021 22:18:59 +0800 Subject: [PATCH 278/777] [NETD-BPF#1] Move libnetdutils to framework/libs/net/... libnetdutils is referenced by netd.c and TrafficController.cpp, which are going to be mainlined. Therefore, move libnetdutils to a common place where both mainline module and platform code (Netd) can refer to. Bug: 202086915 Test: build; flash; cd system/netd; atest No-Typo-Check: Clean code move with no other changes. BYPASS_INCLUSIVE_LANGUAGE_REASON=Clean code move with no other changes. Merged-In: I645bfe35f6543149c9a9f894cd4158d27a481abe Change-Id: I645bfe35f6543149c9a9f894cd4158d27a481abe --- staticlibs/netd/libnetdutils/Android.bp | 65 +++ .../netd/libnetdutils/BackoffSequenceTest.cpp | 186 ++++++ staticlibs/netd/libnetdutils/DumpWriter.cpp | 72 +++ staticlibs/netd/libnetdutils/Fd.cpp | 27 + staticlibs/netd/libnetdutils/FdTest.cpp | 147 +++++ .../netd/libnetdutils/InternetAddresses.cpp | 164 ++++++ .../libnetdutils/InternetAddressesTest.cpp | 541 ++++++++++++++++++ staticlibs/netd/libnetdutils/Log.cpp | 216 +++++++ staticlibs/netd/libnetdutils/LogTest.cpp | 143 +++++ staticlibs/netd/libnetdutils/MemBlockTest.cpp | 146 +++++ staticlibs/netd/libnetdutils/Netfilter.cpp | 30 + staticlibs/netd/libnetdutils/Netlink.cpp | 78 +++ staticlibs/netd/libnetdutils/Slice.cpp | 61 ++ staticlibs/netd/libnetdutils/SliceTest.cpp | 135 +++++ staticlibs/netd/libnetdutils/Socket.cpp | 35 ++ staticlibs/netd/libnetdutils/SocketOption.cpp | 54 ++ staticlibs/netd/libnetdutils/Status.cpp | 45 ++ staticlibs/netd/libnetdutils/StatusTest.cpp | 105 ++++ staticlibs/netd/libnetdutils/Syscalls.cpp | 265 +++++++++ staticlibs/netd/libnetdutils/SyscallsTest.cpp | 202 +++++++ .../netd/libnetdutils/ThreadUtilTest.cpp | 122 ++++ staticlibs/netd/libnetdutils/UniqueFd.cpp | 38 ++ staticlibs/netd/libnetdutils/UniqueFile.cpp | 31 + .../include/netdutils/BackoffSequence.h | 153 +++++ .../include/netdutils/DumpWriter.h | 68 +++ .../netd/libnetdutils/include/netdutils/Fd.h | 54 ++ .../libnetdutils/include/netdutils/Handle.h | 74 +++ .../include/netdutils/InternetAddresses.h | 325 +++++++++++ .../netd/libnetdutils/include/netdutils/Log.h | 211 +++++++ .../libnetdutils/include/netdutils/Math.h | 40 ++ .../libnetdutils/include/netdutils/MemBlock.h | 67 +++ .../libnetdutils/include/netdutils/Misc.h | 63 ++ .../include/netdutils/MockSyscalls.h | 90 +++ .../include/netdutils/Netfilter.h | 28 + .../libnetdutils/include/netdutils/Netlink.h | 55 ++ .../include/netdutils/NetworkConstants.h | 32 ++ .../include/netdutils/ResponseCode.h | 92 +++ .../libnetdutils/include/netdutils/Slice.h | 161 ++++++ .../libnetdutils/include/netdutils/Socket.h | 44 ++ .../include/netdutils/SocketOption.h | 60 ++ .../libnetdutils/include/netdutils/Status.h | 136 +++++ .../libnetdutils/include/netdutils/StatusOr.h | 119 ++++ .../include/netdutils/Stopwatch.h | 53 ++ .../libnetdutils/include/netdutils/Syscalls.h | 204 +++++++ .../include/netdutils/ThreadUtil.h | 83 +++ .../include/netdutils/UidConstants.h | 27 + .../libnetdutils/include/netdutils/UniqueFd.h | 71 +++ .../include/netdutils/UniqueFile.h | 35 ++ 48 files changed, 5253 insertions(+) create mode 100644 staticlibs/netd/libnetdutils/Android.bp create mode 100644 staticlibs/netd/libnetdutils/BackoffSequenceTest.cpp create mode 100644 staticlibs/netd/libnetdutils/DumpWriter.cpp create mode 100644 staticlibs/netd/libnetdutils/Fd.cpp create mode 100644 staticlibs/netd/libnetdutils/FdTest.cpp create mode 100644 staticlibs/netd/libnetdutils/InternetAddresses.cpp create mode 100644 staticlibs/netd/libnetdutils/InternetAddressesTest.cpp create mode 100644 staticlibs/netd/libnetdutils/Log.cpp create mode 100644 staticlibs/netd/libnetdutils/LogTest.cpp create mode 100644 staticlibs/netd/libnetdutils/MemBlockTest.cpp create mode 100644 staticlibs/netd/libnetdutils/Netfilter.cpp create mode 100644 staticlibs/netd/libnetdutils/Netlink.cpp create mode 100644 staticlibs/netd/libnetdutils/Slice.cpp create mode 100644 staticlibs/netd/libnetdutils/SliceTest.cpp create mode 100644 staticlibs/netd/libnetdutils/Socket.cpp create mode 100644 staticlibs/netd/libnetdutils/SocketOption.cpp create mode 100644 staticlibs/netd/libnetdutils/Status.cpp create mode 100644 staticlibs/netd/libnetdutils/StatusTest.cpp create mode 100644 staticlibs/netd/libnetdutils/Syscalls.cpp create mode 100644 staticlibs/netd/libnetdutils/SyscallsTest.cpp create mode 100644 staticlibs/netd/libnetdutils/ThreadUtilTest.cpp create mode 100644 staticlibs/netd/libnetdutils/UniqueFd.cpp create mode 100644 staticlibs/netd/libnetdutils/UniqueFile.cpp create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/BackoffSequence.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/DumpWriter.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Fd.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Handle.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/InternetAddresses.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Log.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Math.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/MemBlock.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Misc.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/MockSyscalls.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Netfilter.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Netlink.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/NetworkConstants.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/ResponseCode.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Slice.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Socket.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/SocketOption.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Status.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/StatusOr.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Stopwatch.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Syscalls.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/ThreadUtil.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/UidConstants.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/UniqueFd.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/UniqueFile.h diff --git a/staticlibs/netd/libnetdutils/Android.bp b/staticlibs/netd/libnetdutils/Android.bp new file mode 100644 index 0000000000..3bb627069a --- /dev/null +++ b/staticlibs/netd/libnetdutils/Android.bp @@ -0,0 +1,65 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_library { + name: "libnetdutils", + srcs: [ + "DumpWriter.cpp", + "Fd.cpp", + "InternetAddresses.cpp", + "Log.cpp", + "Netfilter.cpp", + "Netlink.cpp", + "Slice.cpp", + "Socket.cpp", + "SocketOption.cpp", + "Status.cpp", + "Syscalls.cpp", + "UniqueFd.cpp", + "UniqueFile.cpp", + ], + defaults: ["netd_defaults"], + cflags: ["-Wall", "-Werror"], + shared_libs: [ + "libbase", + "liblog", + ], + export_shared_lib_headers: [ + "libbase", + ], + export_include_dirs: ["include"], + sanitize: { + cfi: true, + }, + + apex_available: [ + "//apex_available:platform", + "com.android.resolv", + ], + min_sdk_version: "29", +} + +cc_test { + name: "netdutils_test", + srcs: [ + "BackoffSequenceTest.cpp", + "FdTest.cpp", + "InternetAddressesTest.cpp", + "LogTest.cpp", + "MemBlockTest.cpp", + "SliceTest.cpp", + "StatusTest.cpp", + "SyscallsTest.cpp", + "ThreadUtilTest.cpp", + ], + defaults: ["netd_defaults"], + test_suites: ["device-tests"], + static_libs: [ + "libgmock", + "libnetdutils", + ], + shared_libs: [ + "libbase", + ], +} diff --git a/staticlibs/netd/libnetdutils/BackoffSequenceTest.cpp b/staticlibs/netd/libnetdutils/BackoffSequenceTest.cpp new file mode 100644 index 0000000000..b6653fe80a --- /dev/null +++ b/staticlibs/netd/libnetdutils/BackoffSequenceTest.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2018 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. + */ + +#include + +#include "netdutils/BackoffSequence.h" + +namespace android { +namespace netdutils { + +TEST(BackoffSequence, defaults) { + BackoffSequence backoff; + + EXPECT_TRUE(backoff.hasNextTimeout()); + EXPECT_EQ(0x00000001U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000002U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000004U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000008U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000010U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000020U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000040U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000080U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000100U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000200U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000400U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000800U, backoff.getNextTimeout()); + EXPECT_EQ(0x00001000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00002000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00004000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00008000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00010000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00020000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00040000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00080000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00100000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00200000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00400000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00800000U, backoff.getNextTimeout()); + EXPECT_EQ(0x01000000U, backoff.getNextTimeout()); + EXPECT_EQ(0x02000000U, backoff.getNextTimeout()); + EXPECT_EQ(0x04000000U, backoff.getNextTimeout()); + EXPECT_EQ(0x08000000U, backoff.getNextTimeout()); + EXPECT_EQ(0x10000000U, backoff.getNextTimeout()); + EXPECT_EQ(0x20000000U, backoff.getNextTimeout()); + EXPECT_EQ(0x40000000U, backoff.getNextTimeout()); + EXPECT_EQ(0x80000000U, backoff.getNextTimeout()); + // Maxes out, and stays there, ad infinitum. + for (int i = 0; i < 10; i++) { + EXPECT_TRUE(backoff.hasNextTimeout()); + EXPECT_EQ(0xffffffffU, backoff.getNextTimeout()); + } +} + +TEST(BackoffSequence, backoffToOncePerHour) { + auto backoff = BackoffSequence::Builder() + .withInitialRetransmissionTime(1) + .withMaximumRetransmissionTime(3600) + .build(); + + EXPECT_TRUE(backoff.hasNextTimeout()); + EXPECT_EQ(0x00000001U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000002U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000004U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000008U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000010U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000020U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000040U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000080U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000100U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000200U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000400U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000800U, backoff.getNextTimeout()); + // Maxes out, and stays there, ad infinitum. + for (int i = 0; i < 10; i++) { + EXPECT_TRUE(backoff.hasNextTimeout()); + EXPECT_EQ(3600U, backoff.getNextTimeout()); + } +} + +TEST(BackoffSequence, simpleMaxRetransCount) { + auto backoff = BackoffSequence::Builder() + .withInitialRetransmissionTime(3) + .withMaximumRetransmissionCount(7) + .build(); + + EXPECT_TRUE(backoff.hasNextTimeout()); + EXPECT_EQ(0x00000003U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000006U, backoff.getNextTimeout()); + EXPECT_EQ(0x0000000cU, backoff.getNextTimeout()); + EXPECT_EQ(0x00000018U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000030U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000060U, backoff.getNextTimeout()); + EXPECT_EQ(0x000000c0U, backoff.getNextTimeout()); + + for (int i = 0; i < 10; i++) { + EXPECT_FALSE(backoff.hasNextTimeout()); + EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout()); + } +} + +TEST(BackoffSequence, simpleMaxDuration) { + auto backoff = BackoffSequence::Builder() + .withInitialRetransmissionTime(3) + .withMaximumRetransmissionDuration(7) + .withEndOfSequenceIndicator(-1) + .build(); + + EXPECT_TRUE(backoff.hasNextTimeout()); + EXPECT_EQ(0x00000003, backoff.getNextTimeout()); + EXPECT_EQ(0x00000004, backoff.getNextTimeout()); + + for (int i = 0; i < 10; i++) { + EXPECT_FALSE(backoff.hasNextTimeout()); + EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout()); + EXPECT_EQ(-1, backoff.getNextTimeout()); + } +} + +TEST(PathologicalBackoffSequence, ZeroInitialRetransTime) { + auto backoff = BackoffSequence::Builder() + .withInitialRetransmissionTime(std::chrono::seconds(0)) + .build(); + + for (int i = 0; i < 10; i++) { + // TODO: Decide whether this needs fixing, and how. + EXPECT_TRUE(backoff.hasNextTimeout()); + EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout()); + } +} + +TEST(PathologicalBackoffSequence, MaxRetransDurationGreaterThanInitialRetransTime) { + auto backoff = BackoffSequence::Builder() + .withInitialRetransmissionTime(std::chrono::milliseconds(5)) + .withMaximumRetransmissionDuration(std::chrono::milliseconds(3)) + .build(); + + EXPECT_EQ(std::chrono::milliseconds(3), backoff.getNextTimeout()); + for (int i = 0; i < 10; i++) { + EXPECT_FALSE(backoff.hasNextTimeout()); + EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout()); + } +} + +TEST(PathologicalBackoffSequence, MaxRetransDurationEqualsInitialRetransTime) { + auto backoff = BackoffSequence::Builder() + .withInitialRetransmissionTime(std::chrono::hours(5)) + .withMaximumRetransmissionDuration(std::chrono::hours(5)) + .build(); + + EXPECT_EQ(std::chrono::hours(5), backoff.getNextTimeout()); + for (int i = 0; i < 10; i++) { + EXPECT_FALSE(backoff.hasNextTimeout()); + EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout()); + } +} + +TEST(PathologicalBackoffSequence, MaxRetransTimeAndDurationGreaterThanInitialRetransTime) { + auto backoff = BackoffSequence::Builder() + .withInitialRetransmissionTime(std::chrono::nanoseconds(7)) + .withMaximumRetransmissionTime(std::chrono::nanoseconds(3)) + .withMaximumRetransmissionDuration(std::chrono::nanoseconds(5)) + .build(); + + EXPECT_EQ(std::chrono::nanoseconds(3), backoff.getNextTimeout()); + EXPECT_EQ(std::chrono::nanoseconds(2), backoff.getNextTimeout()); + for (int i = 0; i < 10; i++) { + EXPECT_FALSE(backoff.hasNextTimeout()); + EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout()); + } +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/DumpWriter.cpp b/staticlibs/netd/libnetdutils/DumpWriter.cpp new file mode 100644 index 0000000000..092ddbae2d --- /dev/null +++ b/staticlibs/netd/libnetdutils/DumpWriter.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 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. + */ + +#include "netdutils/DumpWriter.h" + +#include +#include + +#include +#include + +using android::base::StringAppendV; + +namespace android { +namespace netdutils { + +namespace { + +const char kIndentString[] = " "; +const size_t kIndentStringLen = strlen(kIndentString); + +} // namespace + +DumpWriter::DumpWriter(int fd) : mIndentLevel(0), mFd(fd) {} + +void DumpWriter::incIndent() { + if (mIndentLevel < std::numeric_limits::max()) { + mIndentLevel++; + } +} + +void DumpWriter::decIndent() { + if (mIndentLevel > std::numeric_limits::min()) { + mIndentLevel--; + } +} + +void DumpWriter::println(const std::string& line) { + if (!line.empty()) { + for (int i = 0; i < mIndentLevel; i++) { + ::write(mFd, kIndentString, kIndentStringLen); + } + ::write(mFd, line.c_str(), line.size()); + } + ::write(mFd, "\n", 1); +} + +// NOLINTNEXTLINE(cert-dcl50-cpp): Grandfathered C-style variadic function. +void DumpWriter::println(const char* fmt, ...) { + std::string line; + va_list ap; + va_start(ap, fmt); + StringAppendV(&line, fmt, ap); + va_end(ap); + println(line); +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/Fd.cpp b/staticlibs/netd/libnetdutils/Fd.cpp new file mode 100644 index 0000000000..2651f906e7 --- /dev/null +++ b/staticlibs/netd/libnetdutils/Fd.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 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. + */ + +#include "netdutils/Fd.h" + +namespace android { +namespace netdutils { + +std::ostream& operator<<(std::ostream& os, const Fd& fd) { + return os << "Fd[" << fd.get() << "]"; +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/FdTest.cpp b/staticlibs/netd/libnetdutils/FdTest.cpp new file mode 100644 index 0000000000..7080f831a1 --- /dev/null +++ b/staticlibs/netd/libnetdutils/FdTest.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2017 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. + */ + +#include + +#include + +#include "netdutils/MockSyscalls.h" +#include "netdutils/Status.h" +#include "netdutils/Syscalls.h" + +using testing::Mock; +using testing::Return; +using testing::StrictMock; + +namespace android { +namespace netdutils { +namespace { + +// Force implicit conversion from UniqueFd -> Fd +inline Fd toFd(const UniqueFd& fd) { + return fd; +} + +} // namespace + +TEST(Fd, smoke) { + // Expect the following lines to compile + Fd fd1(1); + Fd fd2(fd1); + Fd fd3 = fd2; + const Fd fd4(8); + const Fd fd5(fd4); + const Fd fd6 = fd5; + EXPECT_TRUE(isWellFormed(fd3)); + EXPECT_TRUE(isWellFormed(fd6)); + + // Corner case + Fd zero(0); + EXPECT_TRUE(isWellFormed(zero)); + + // Invalid file descriptors + Fd bad(-1); + Fd weird(-9); + EXPECT_FALSE(isWellFormed(bad)); + EXPECT_FALSE(isWellFormed(weird)); + + // Default constructor + EXPECT_EQ(Fd(-1), Fd()); + std::stringstream ss; + ss << fd3 << " " << fd6 << " " << bad << " " << weird; + EXPECT_EQ("Fd[1] Fd[8] Fd[-1] Fd[-9]", ss.str()); +} + +class UniqueFdTest : public testing::Test { + protected: + StrictMock mSyscalls; +}; + +TEST_F(UniqueFdTest, operatorOstream) { + UniqueFd u(97); + EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok)); + std::stringstream ss; + ss << u; + EXPECT_EQ("UniqueFd[Fd[97]]", ss.str()); + u.reset(); +} + +TEST_F(UniqueFdTest, destructor) { + { + UniqueFd u(98); + EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok)); + } + // Expectation above should be upon leaving nested scope + Mock::VerifyAndClearExpectations(&mSyscalls); +} + +TEST_F(UniqueFdTest, reset) { + UniqueFd u(99); + EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok)); + u.reset(); + + // Expectation above should be upon reset + Mock::VerifyAndClearExpectations(&mSyscalls); +} + +TEST_F(UniqueFdTest, moveConstructor) { + constexpr Fd kFd(101); + UniqueFd u1(kFd); + { + UniqueFd u2(std::move(u1)); + // NOLINTNEXTLINE bugprone-use-after-move + EXPECT_FALSE(isWellFormed(u1)); + EXPECT_TRUE(isWellFormed(u2)); + EXPECT_CALL(mSyscalls, close(kFd)).WillOnce(Return(status::ok)); + } + // Expectation above should be upon leaving nested scope + Mock::VerifyAndClearExpectations(&mSyscalls); +} + +TEST_F(UniqueFdTest, moveAssignment) { + constexpr Fd kFd(102); + UniqueFd u1(kFd); + { + UniqueFd u2 = std::move(u1); + // NOLINTNEXTLINE bugprone-use-after-move + EXPECT_FALSE(isWellFormed(u1)); + EXPECT_TRUE(isWellFormed(u2)); + UniqueFd u3; + u3 = std::move(u2); + // NOLINTNEXTLINE bugprone-use-after-move + EXPECT_FALSE(isWellFormed(u2)); + EXPECT_TRUE(isWellFormed(u3)); + EXPECT_CALL(mSyscalls, close(kFd)).WillOnce(Return(status::ok)); + } + // Expectation above should be upon leaving nested scope + Mock::VerifyAndClearExpectations(&mSyscalls); +} + +TEST_F(UniqueFdTest, constConstructor) { + constexpr Fd kFd(103); + const UniqueFd u(kFd); + EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok)); +} + +TEST_F(UniqueFdTest, closeFailure) { + constexpr Fd kFd(103); + UniqueFd u(kFd); + EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(statusFromErrno(EINTR, "test"))); + EXPECT_DEBUG_DEATH(u.reset(), ""); +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/InternetAddresses.cpp b/staticlibs/netd/libnetdutils/InternetAddresses.cpp new file mode 100644 index 0000000000..322f1b1d6c --- /dev/null +++ b/staticlibs/netd/libnetdutils/InternetAddresses.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2018 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. + */ + +#include "netdutils/InternetAddresses.h" + +#include + +#include +#include +#include +#include +#include + +namespace android { + +using base::StringPrintf; + +namespace netdutils { + +std::string IPAddress::toString() const noexcept { + char repr[INET6_ADDRSTRLEN] = "\0"; + + switch (mData.family) { + case AF_UNSPEC: + return ""; + case AF_INET: { + const in_addr v4 = mData.ip.v4; + inet_ntop(AF_INET, &v4, repr, sizeof(repr)); + break; + } + case AF_INET6: { + const in6_addr v6 = mData.ip.v6; + inet_ntop(AF_INET6, &v6, repr, sizeof(repr)); + break; + } + default: + return ""; + } + + if (mData.family == AF_INET6 && mData.scope_id > 0) { + return StringPrintf("%s%%%u", repr, mData.scope_id); + } + + return repr; +} + +bool IPAddress::forString(const std::string& repr, IPAddress* ip) { + const addrinfo hints = { + .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV, + }; + addrinfo* res; + const int ret = getaddrinfo(repr.c_str(), nullptr, &hints, &res); + ScopedAddrinfo res_cleanup(res); + if (ret != 0) { + return false; + } + + bool rval = true; + switch (res[0].ai_family) { + case AF_INET: { + sockaddr_in* sin = (sockaddr_in*) res[0].ai_addr; + if (ip) *ip = IPAddress(sin->sin_addr); + break; + } + case AF_INET6: { + sockaddr_in6* sin6 = (sockaddr_in6*) res[0].ai_addr; + if (ip) *ip = IPAddress(sin6->sin6_addr, sin6->sin6_scope_id); + break; + } + default: + rval = false; + break; + } + + return rval; +} + +IPPrefix::IPPrefix(const IPAddress& ip, int length) : IPPrefix(ip) { + // Silently treat CIDR lengths like "-1" as meaning the full bit length + // appropriate to the address family. + if (length < 0) return; + if (length >= mData.cidrlen) return; + + switch (mData.family) { + case AF_UNSPEC: + break; + case AF_INET: { + const in_addr_t mask = (length > 0) ? (~0U) << (IPV4_ADDR_BITS - length) : 0U; + mData.ip.v4.s_addr &= htonl(mask); + mData.cidrlen = static_cast(length); + break; + } + case AF_INET6: { + // The byte in which this CIDR length falls. + const int which = length / 8; + const int mask = (length % 8 == 0) ? 0 : 0xff << (8 - length % 8); + mData.ip.v6.s6_addr[which] &= mask; + for (int i = which + 1; i < IPV6_ADDR_LEN; i++) { + mData.ip.v6.s6_addr[i] = 0U; + } + mData.cidrlen = static_cast(length); + break; + } + default: + // TODO: Complain bitterly about possible data corruption? + return; + } +} + +bool IPPrefix::isUninitialized() const noexcept { + static const internal_::compact_ipdata empty{}; + return mData == empty; +} + +bool IPPrefix::forString(const std::string& repr, IPPrefix* prefix) { + size_t index = repr.find('/'); + if (index == std::string::npos) return false; + + // Parse the IP address. + IPAddress ip; + if (!IPAddress::forString(repr.substr(0, index), &ip)) return false; + + // Parse the prefix length. Can't use base::ParseUint because it accepts non-base 10 input. + const char* prefixString = repr.c_str() + index + 1; + if (!isdigit(*prefixString)) return false; + char* endptr; + unsigned long prefixlen = strtoul(prefixString, &endptr, 10); + if (*endptr != '\0') return false; + + uint8_t maxlen = (ip.family() == AF_INET) ? 32 : 128; + if (prefixlen > maxlen) return false; + + *prefix = IPPrefix(ip, prefixlen); + return true; +} + +std::string IPPrefix::toString() const noexcept { + return StringPrintf("%s/%d", ip().toString().c_str(), mData.cidrlen); +} + +std::string IPSockAddr::toString() const noexcept { + switch (mData.family) { + case AF_INET6: + return StringPrintf("[%s]:%u", ip().toString().c_str(), mData.port); + default: + return StringPrintf("%s:%u", ip().toString().c_str(), mData.port); + } +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/InternetAddressesTest.cpp b/staticlibs/netd/libnetdutils/InternetAddressesTest.cpp new file mode 100644 index 0000000000..f75fa769ee --- /dev/null +++ b/staticlibs/netd/libnetdutils/InternetAddressesTest.cpp @@ -0,0 +1,541 @@ +/* + * Copyright (C) 2018 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. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "netdutils/InternetAddresses.h" + +namespace android { +namespace netdutils { +namespace { + +enum Relation { EQ, LT }; + +std::ostream& operator<<(std::ostream& os, Relation relation) { + switch (relation) { + case EQ: os << "eq"; break; + case LT: os << "lt"; break; + default: os << "?!"; break; + } + return os; +} + +template +struct OperatorExpectation { + const Relation relation; + const T obj1; + const T obj2; + + std::string toString() const { + std::stringstream output; + output << obj1 << " " << relation << " " << obj2; + return output.str(); + } +}; + +template +void testGamutOfOperators(const OperatorExpectation& expectation) { + switch (expectation.relation) { + case EQ: + EXPECT_TRUE(expectation.obj1 == expectation.obj2); + EXPECT_TRUE(expectation.obj1 <= expectation.obj2); + EXPECT_TRUE(expectation.obj1 >= expectation.obj2); + EXPECT_FALSE(expectation.obj1 != expectation.obj2); + EXPECT_FALSE(expectation.obj1 < expectation.obj2); + EXPECT_FALSE(expectation.obj1 > expectation.obj2); + break; + + case LT: + EXPECT_TRUE(expectation.obj1 < expectation.obj2); + EXPECT_TRUE(expectation.obj1 <= expectation.obj2); + EXPECT_TRUE(expectation.obj1 != expectation.obj2); + EXPECT_FALSE(expectation.obj1 > expectation.obj2); + EXPECT_FALSE(expectation.obj1 >= expectation.obj2); + EXPECT_FALSE(expectation.obj1 == expectation.obj2); + break; + + default: + FAIL() << "Unknown relation given in test expectation"; + } +} + +const in_addr IPV4_ANY{htonl(INADDR_ANY)}; +const in_addr IPV4_LOOPBACK{htonl(INADDR_LOOPBACK)}; +const in_addr IPV4_ONES{~0U}; +const in6_addr IPV6_ANY = IN6ADDR_ANY_INIT; +const in6_addr IPV6_LOOPBACK = IN6ADDR_LOOPBACK_INIT; +const in6_addr FE80{{{0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}; +const in6_addr FE80_1{{{0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,1}}}; +const in6_addr FE80_2{{{0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,2}}}; +const uint8_t ff = std::numeric_limits::max(); +const in6_addr IPV6_ONES{{{ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff}}}; + +TEST(IPAddressTest, GamutOfOperators) { + const std::vector> kExpectations{ + {EQ, IPAddress(), IPAddress()}, + {EQ, IPAddress(IPV4_ONES), IPAddress(IPV4_ONES)}, + {EQ, IPAddress(IPV6_ONES), IPAddress(IPV6_ONES)}, + {EQ, IPAddress(FE80_1), IPAddress(FE80_1)}, + {EQ, IPAddress(FE80_2), IPAddress(FE80_2)}, + {LT, IPAddress(), IPAddress(IPV4_ANY)}, + {LT, IPAddress(), IPAddress(IPV4_ONES)}, + {LT, IPAddress(), IPAddress(IPV6_ANY)}, + {LT, IPAddress(), IPAddress(IPV6_ONES)}, + {LT, IPAddress(IPV4_ANY), IPAddress(IPV4_ONES)}, + {LT, IPAddress(IPV4_ANY), IPAddress(IPV6_ANY)}, + {LT, IPAddress(IPV4_ONES), IPAddress(IPV6_ANY)}, + {LT, IPAddress(IPV4_ONES), IPAddress(IPV6_ONES)}, + {LT, IPAddress(IPV6_ANY), IPAddress(IPV6_LOOPBACK)}, + {LT, IPAddress(IPV6_ANY), IPAddress(IPV6_ONES)}, + {LT, IPAddress(IPV6_LOOPBACK), IPAddress(IPV6_ONES)}, + {LT, IPAddress(FE80_1), IPAddress(FE80_2)}, + {LT, IPAddress(FE80_1), IPAddress(IPV6_ONES)}, + {LT, IPAddress(FE80_2), IPAddress(IPV6_ONES)}, + // Sort by scoped_id within the same address. + {LT, IPAddress(FE80_1), IPAddress(FE80_1, 1)}, + {LT, IPAddress(FE80_1, 1), IPAddress(FE80_1, 2)}, + // Sort by address first, scope_id second. + {LT, IPAddress(FE80_1, 2), IPAddress(FE80_2, 1)}, + }; + + size_t tests_run = 0; + for (const auto& expectation : kExpectations) { + SCOPED_TRACE(expectation.toString()); + EXPECT_NO_FATAL_FAILURE(testGamutOfOperators(expectation)); + tests_run++; + } + EXPECT_EQ(kExpectations.size(), tests_run); +} + +TEST(IPAddressTest, ScopeIds) { + // Scope IDs ignored for IPv4 addresses. + const IPAddress ones(IPV4_ONES); + EXPECT_EQ(0U, ones.scope_id()); + const IPAddress ones22(ones, 22); + EXPECT_EQ(0U, ones22.scope_id()); + EXPECT_EQ(ones, ones22); + const IPAddress ones23(ones, 23); + EXPECT_EQ(0U, ones23.scope_id()); + EXPECT_EQ(ones22, ones23); + + EXPECT_EQ("fe80::1%22", IPAddress(FE80_1, 22).toString()); + EXPECT_EQ("fe80::2%23", IPAddress(FE80_2, 23).toString()); + + // Verify that given an IPAddress with a scope_id an address without a + // scope_id can be constructed (just in case it's useful). + const IPAddress fe80_intf22(FE80_1, 22); + EXPECT_EQ(22U, fe80_intf22.scope_id()); + EXPECT_EQ(fe80_intf22, IPAddress(fe80_intf22)); + EXPECT_EQ(IPAddress(FE80_1), IPAddress(fe80_intf22, 0)); +} + +TEST(IPAddressTest, forString) { + IPAddress ip; + + EXPECT_FALSE(IPAddress::forString("not_an_ip", &ip)); + EXPECT_FALSE(IPAddress::forString("not_an_ip", nullptr)); + EXPECT_EQ(IPAddress(), IPAddress::forString("not_an_ip")); + + EXPECT_EQ(IPAddress(IPV4_ANY), IPAddress::forString("0.0.0.0")); + EXPECT_EQ(IPAddress(IPV4_ONES), IPAddress::forString("255.255.255.255")); + EXPECT_EQ(IPAddress(IPV4_LOOPBACK), IPAddress::forString("127.0.0.1")); + + EXPECT_EQ(IPAddress(IPV6_ANY), IPAddress::forString("::")); + EXPECT_EQ(IPAddress(IPV6_ANY), IPAddress::forString("::0")); + EXPECT_EQ(IPAddress(IPV6_ANY), IPAddress::forString("0::")); + EXPECT_EQ(IPAddress(IPV6_LOOPBACK), IPAddress::forString("::1")); + EXPECT_EQ(IPAddress(IPV6_LOOPBACK), IPAddress::forString("0::1")); + EXPECT_EQ(IPAddress(FE80_1), IPAddress::forString("fe80::1")); + EXPECT_EQ(IPAddress(FE80_1, 22), IPAddress::forString("fe80::1%22")); + // This relies upon having a loopback interface named "lo" with ifindex 1. + EXPECT_EQ(IPAddress(FE80_1, 1), IPAddress::forString("fe80::1%lo")); +} + +TEST(IPPrefixTest, forString) { + IPPrefix prefix; + + EXPECT_FALSE(IPPrefix::forString("", &prefix)); + EXPECT_FALSE(IPPrefix::forString("invalid", &prefix)); + EXPECT_FALSE(IPPrefix::forString("192.0.2.0", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001::db8::", &prefix)); + + EXPECT_FALSE(IPPrefix::forString("2001:db8::/", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8:://32", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8::/32z", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8::/32/", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8::/0x20", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8:: /32", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8::/ 32", &prefix)); + EXPECT_FALSE(IPPrefix::forString(" 2001:db8::/32", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8::/32 ", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8::/+32", &prefix)); + + EXPECT_FALSE(IPPrefix::forString("192.0.2.0/33", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8::/129", &prefix)); + EXPECT_FALSE(IPPrefix::forString("192.0.2.0/-1", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8::/-1", &prefix)); + + EXPECT_TRUE(IPPrefix::forString("2001:db8::/32", &prefix)); + EXPECT_EQ("2001:db8::/32", prefix.toString()); + EXPECT_EQ(IPPrefix(IPAddress::forString("2001:db8::"), 32), prefix); + + EXPECT_EQ(IPPrefix(), IPPrefix::forString("invalid")); + + EXPECT_EQ("0.0.0.0/0", IPPrefix::forString("0.0.0.0/0").toString()); + EXPECT_EQ("::/0", IPPrefix::forString("::/0").toString()); + EXPECT_EQ("192.0.2.128/25", IPPrefix::forString("192.0.2.131/25").toString()); + EXPECT_EQ("2001:db8:1:2:3:4:5:4/126", + IPPrefix::forString("2001:db8:1:2:3:4:5:6/126").toString()); +} + +TEST(IPPrefixTest, IPv4Truncation) { + const auto prefixStr = [](int length) -> std::string { + return IPPrefix(IPAddress(IPV4_ONES), length).toString(); + }; + + EXPECT_EQ("0.0.0.0/0", prefixStr(0)); + + EXPECT_EQ("128.0.0.0/1", prefixStr(1)); + EXPECT_EQ("192.0.0.0/2", prefixStr(2)); + EXPECT_EQ("224.0.0.0/3", prefixStr(3)); + EXPECT_EQ("240.0.0.0/4", prefixStr(4)); + EXPECT_EQ("248.0.0.0/5", prefixStr(5)); + EXPECT_EQ("252.0.0.0/6", prefixStr(6)); + EXPECT_EQ("254.0.0.0/7", prefixStr(7)); + EXPECT_EQ("255.0.0.0/8", prefixStr(8)); + + EXPECT_EQ("255.128.0.0/9", prefixStr(9)); + EXPECT_EQ("255.192.0.0/10", prefixStr(10)); + EXPECT_EQ("255.224.0.0/11", prefixStr(11)); + EXPECT_EQ("255.240.0.0/12", prefixStr(12)); + EXPECT_EQ("255.248.0.0/13", prefixStr(13)); + EXPECT_EQ("255.252.0.0/14", prefixStr(14)); + EXPECT_EQ("255.254.0.0/15", prefixStr(15)); + EXPECT_EQ("255.255.0.0/16", prefixStr(16)); + + EXPECT_EQ("255.255.128.0/17", prefixStr(17)); + EXPECT_EQ("255.255.192.0/18", prefixStr(18)); + EXPECT_EQ("255.255.224.0/19", prefixStr(19)); + EXPECT_EQ("255.255.240.0/20", prefixStr(20)); + EXPECT_EQ("255.255.248.0/21", prefixStr(21)); + EXPECT_EQ("255.255.252.0/22", prefixStr(22)); + EXPECT_EQ("255.255.254.0/23", prefixStr(23)); + EXPECT_EQ("255.255.255.0/24", prefixStr(24)); + + EXPECT_EQ("255.255.255.128/25", prefixStr(25)); + EXPECT_EQ("255.255.255.192/26", prefixStr(26)); + EXPECT_EQ("255.255.255.224/27", prefixStr(27)); + EXPECT_EQ("255.255.255.240/28", prefixStr(28)); + EXPECT_EQ("255.255.255.248/29", prefixStr(29)); + EXPECT_EQ("255.255.255.252/30", prefixStr(30)); + EXPECT_EQ("255.255.255.254/31", prefixStr(31)); + EXPECT_EQ("255.255.255.255/32", prefixStr(32)); +} + +TEST(IPPrefixTest, IPv6Truncation) { + const auto prefixStr = [](int length) -> std::string { + return IPPrefix(IPAddress(IPV6_ONES), length).toString(); + }; + + EXPECT_EQ("::/0", prefixStr(0)); + + EXPECT_EQ("8000::/1", prefixStr(1)); + EXPECT_EQ("c000::/2", prefixStr(2)); + EXPECT_EQ("e000::/3", prefixStr(3)); + EXPECT_EQ("f000::/4", prefixStr(4)); + EXPECT_EQ("f800::/5", prefixStr(5)); + EXPECT_EQ("fc00::/6", prefixStr(6)); + EXPECT_EQ("fe00::/7", prefixStr(7)); + EXPECT_EQ("ff00::/8", prefixStr(8)); + + EXPECT_EQ("ff80::/9", prefixStr(9)); + EXPECT_EQ("ffc0::/10", prefixStr(10)); + EXPECT_EQ("ffe0::/11", prefixStr(11)); + EXPECT_EQ("fff0::/12", prefixStr(12)); + EXPECT_EQ("fff8::/13", prefixStr(13)); + EXPECT_EQ("fffc::/14", prefixStr(14)); + EXPECT_EQ("fffe::/15", prefixStr(15)); + EXPECT_EQ("ffff::/16", prefixStr(16)); + + EXPECT_EQ("ffff:8000::/17", prefixStr(17)); + EXPECT_EQ("ffff:c000::/18", prefixStr(18)); + EXPECT_EQ("ffff:e000::/19", prefixStr(19)); + EXPECT_EQ("ffff:f000::/20", prefixStr(20)); + EXPECT_EQ("ffff:f800::/21", prefixStr(21)); + EXPECT_EQ("ffff:fc00::/22", prefixStr(22)); + EXPECT_EQ("ffff:fe00::/23", prefixStr(23)); + EXPECT_EQ("ffff:ff00::/24", prefixStr(24)); + + EXPECT_EQ("ffff:ff80::/25", prefixStr(25)); + EXPECT_EQ("ffff:ffc0::/26", prefixStr(26)); + EXPECT_EQ("ffff:ffe0::/27", prefixStr(27)); + EXPECT_EQ("ffff:fff0::/28", prefixStr(28)); + EXPECT_EQ("ffff:fff8::/29", prefixStr(29)); + EXPECT_EQ("ffff:fffc::/30", prefixStr(30)); + EXPECT_EQ("ffff:fffe::/31", prefixStr(31)); + EXPECT_EQ("ffff:ffff::/32", prefixStr(32)); + + EXPECT_EQ("ffff:ffff:8000::/33", prefixStr(33)); + EXPECT_EQ("ffff:ffff:c000::/34", prefixStr(34)); + EXPECT_EQ("ffff:ffff:e000::/35", prefixStr(35)); + EXPECT_EQ("ffff:ffff:f000::/36", prefixStr(36)); + EXPECT_EQ("ffff:ffff:f800::/37", prefixStr(37)); + EXPECT_EQ("ffff:ffff:fc00::/38", prefixStr(38)); + EXPECT_EQ("ffff:ffff:fe00::/39", prefixStr(39)); + EXPECT_EQ("ffff:ffff:ff00::/40", prefixStr(40)); + + EXPECT_EQ("ffff:ffff:ff80::/41", prefixStr(41)); + EXPECT_EQ("ffff:ffff:ffc0::/42", prefixStr(42)); + EXPECT_EQ("ffff:ffff:ffe0::/43", prefixStr(43)); + EXPECT_EQ("ffff:ffff:fff0::/44", prefixStr(44)); + EXPECT_EQ("ffff:ffff:fff8::/45", prefixStr(45)); + EXPECT_EQ("ffff:ffff:fffc::/46", prefixStr(46)); + EXPECT_EQ("ffff:ffff:fffe::/47", prefixStr(47)); + EXPECT_EQ("ffff:ffff:ffff::/48", prefixStr(48)); + + EXPECT_EQ("ffff:ffff:ffff:8000::/49", prefixStr(49)); + EXPECT_EQ("ffff:ffff:ffff:c000::/50", prefixStr(50)); + EXPECT_EQ("ffff:ffff:ffff:e000::/51", prefixStr(51)); + EXPECT_EQ("ffff:ffff:ffff:f000::/52", prefixStr(52)); + EXPECT_EQ("ffff:ffff:ffff:f800::/53", prefixStr(53)); + EXPECT_EQ("ffff:ffff:ffff:fc00::/54", prefixStr(54)); + EXPECT_EQ("ffff:ffff:ffff:fe00::/55", prefixStr(55)); + EXPECT_EQ("ffff:ffff:ffff:ff00::/56", prefixStr(56)); + + EXPECT_EQ("ffff:ffff:ffff:ff80::/57", prefixStr(57)); + EXPECT_EQ("ffff:ffff:ffff:ffc0::/58", prefixStr(58)); + EXPECT_EQ("ffff:ffff:ffff:ffe0::/59", prefixStr(59)); + EXPECT_EQ("ffff:ffff:ffff:fff0::/60", prefixStr(60)); + EXPECT_EQ("ffff:ffff:ffff:fff8::/61", prefixStr(61)); + EXPECT_EQ("ffff:ffff:ffff:fffc::/62", prefixStr(62)); + EXPECT_EQ("ffff:ffff:ffff:fffe::/63", prefixStr(63)); + EXPECT_EQ("ffff:ffff:ffff:ffff::/64", prefixStr(64)); + + EXPECT_EQ("ffff:ffff:ffff:ffff:8000::/65", prefixStr(65)); + EXPECT_EQ("ffff:ffff:ffff:ffff:c000::/66", prefixStr(66)); + EXPECT_EQ("ffff:ffff:ffff:ffff:e000::/67", prefixStr(67)); + EXPECT_EQ("ffff:ffff:ffff:ffff:f000::/68", prefixStr(68)); + EXPECT_EQ("ffff:ffff:ffff:ffff:f800::/69", prefixStr(69)); + EXPECT_EQ("ffff:ffff:ffff:ffff:fc00::/70", prefixStr(70)); + EXPECT_EQ("ffff:ffff:ffff:ffff:fe00::/71", prefixStr(71)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ff00::/72", prefixStr(72)); + + EXPECT_EQ("ffff:ffff:ffff:ffff:ff80::/73", prefixStr(73)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffc0::/74", prefixStr(74)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffe0::/75", prefixStr(75)); + EXPECT_EQ("ffff:ffff:ffff:ffff:fff0::/76", prefixStr(76)); + EXPECT_EQ("ffff:ffff:ffff:ffff:fff8::/77", prefixStr(77)); + EXPECT_EQ("ffff:ffff:ffff:ffff:fffc::/78", prefixStr(78)); + EXPECT_EQ("ffff:ffff:ffff:ffff:fffe::/79", prefixStr(79)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff::/80", prefixStr(80)); + + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:8000::/81", prefixStr(81)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:c000::/82", prefixStr(82)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:e000::/83", prefixStr(83)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:f000::/84", prefixStr(84)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:f800::/85", prefixStr(85)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fc00::/86", prefixStr(86)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fe00::/87", prefixStr(87)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ff00::/88", prefixStr(88)); + + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ff80::/89", prefixStr(89)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffc0::/90", prefixStr(90)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffe0::/91", prefixStr(91)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fff0::/92", prefixStr(92)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fff8::/93", prefixStr(93)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fffc::/94", prefixStr(94)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fffe::/95", prefixStr(95)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff::/96", prefixStr(96)); + + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:8000:0/97", prefixStr(97)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:c000:0/98", prefixStr(98)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:e000:0/99", prefixStr(99)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:f000:0/100", prefixStr(100)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:f800:0/101", prefixStr(101)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fc00:0/102", prefixStr(102)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fe00:0/103", prefixStr(103)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ff00:0/104", prefixStr(104)); + + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ff80:0/105", prefixStr(105)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffc0:0/106", prefixStr(106)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffe0:0/107", prefixStr(107)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fff0:0/108", prefixStr(108)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fff8:0/109", prefixStr(109)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fffc:0/110", prefixStr(110)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fffe:0/111", prefixStr(111)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0/112", prefixStr(112)); + + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:8000/113", prefixStr(113)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:c000/114", prefixStr(114)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:e000/115", prefixStr(115)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:f000/116", prefixStr(116)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:f800/117", prefixStr(117)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fc00/118", prefixStr(118)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fe00/119", prefixStr(119)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00/120", prefixStr(120)); + + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff80/121", prefixStr(121)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffc0/122", prefixStr(122)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffe0/123", prefixStr(123)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0/124", prefixStr(124)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff8/125", prefixStr(125)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc/126", prefixStr(126)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe/127", prefixStr(127)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128", prefixStr(128)); +} + +TEST(IPPrefixTest, TruncationOther) { + const struct { + const char* ip; + const int cidrLen; + const char* ipTruncated; + } testExpectations[] = { + {"192.0.2.0", 24, "192.0.2.0"}, + {"192.0.2.0", 23, "192.0.2.0"}, + {"192.0.2.0", 22, "192.0.0.0"}, + {"192.0.2.0", 1, "128.0.0.0"}, + {"2001:db8:cafe:d00d::", 56, "2001:db8:cafe:d000::"}, + {"2001:db8:cafe:d00d::", 48, "2001:db8:cafe::"}, + {"2001:db8:cafe:d00d::", 47, "2001:db8:cafe::"}, + {"2001:db8:cafe:d00d::", 46, "2001:db8:cafc::"}, + }; + + for (const auto& expectation : testExpectations) { + IPAddress ip; + EXPECT_TRUE(IPAddress::forString(expectation.ip, &ip)) + << "Failed to parse IP address " << expectation.ip; + + IPAddress ipTruncated; + EXPECT_TRUE(IPAddress::forString(expectation.ipTruncated, &ipTruncated)) + << "Failed to parse IP address " << expectation.ipTruncated; + + IPPrefix prefix(ip, expectation.cidrLen); + + EXPECT_EQ(expectation.cidrLen, prefix.length()) + << "Unexpected cidrLen " << expectation.cidrLen; + EXPECT_EQ(ipTruncated, prefix.ip()) + << "Unexpected IP truncation: " << prefix.ip() << ", expected: " << ipTruncated; + } +} + +TEST(IPPrefixTest, GamutOfOperators) { + const std::vector> kExpectations{ + {EQ, IPPrefix(), IPPrefix()}, + {EQ, IPPrefix(IPAddress(IPV4_ANY), 0), IPPrefix(IPAddress(IPV4_ANY), 0)}, + {EQ, IPPrefix(IPAddress(IPV4_ANY), IPV4_ADDR_BITS), IPPrefix(IPAddress(IPV4_ANY))}, + {EQ, IPPrefix(IPAddress(IPV6_ANY), 0), IPPrefix(IPAddress(IPV6_ANY), 0)}, + {EQ, IPPrefix(IPAddress(IPV6_ANY), IPV6_ADDR_BITS), IPPrefix(IPAddress(IPV6_ANY))}, + // Needlessly fully-specified IPv6 link-local address. + {EQ, IPPrefix(IPAddress(FE80_1)), IPPrefix(IPAddress(FE80_1, 0), IPV6_ADDR_BITS)}, + // Different IPv6 link-local addresses within the same /64, no scoped_id: same /64. + {EQ, IPPrefix(IPAddress(FE80_1), 64), IPPrefix(IPAddress(FE80_2), 64)}, + // Different IPv6 link-local address within the same /64, same scoped_id: same /64. + {EQ, IPPrefix(IPAddress(FE80_1, 17), 64), IPPrefix(IPAddress(FE80_2, 17), 64)}, + // Unspecified < IPv4. + {LT, IPPrefix(), IPPrefix(IPAddress(IPV4_ANY), 0)}, + // Same IPv4 base address sorts by prefix length. + {LT, IPPrefix(IPAddress(IPV4_ANY), 0), IPPrefix(IPAddress(IPV4_ANY), 1)}, + {LT, IPPrefix(IPAddress(IPV4_ANY), 1), IPPrefix(IPAddress(IPV4_ANY), IPV4_ADDR_BITS)}, + // Truncation means each base IPv4 address is different. + {LT, IPPrefix(IPAddress(IPV4_ONES), 0), IPPrefix(IPAddress(IPV4_ONES), 1)}, + {LT, IPPrefix(IPAddress(IPV4_ONES), 1), IPPrefix(IPAddress(IPV4_ONES), IPV4_ADDR_BITS)}, + // Sort by base IPv4 addresses first. + {LT, IPPrefix(IPAddress(IPV4_ANY), 0), IPPrefix(IPAddress::forString("0.0.0.1"))}, + {LT, IPPrefix(IPAddress(IPV4_ANY), 1), IPPrefix(IPAddress::forString("0.0.0.1"))}, + {LT, IPPrefix(IPAddress(IPV4_ANY), 24), IPPrefix(IPAddress::forString("0.0.0.1"))}, + // IPv4 < IPv6. + {LT, IPPrefix(IPAddress(IPV4_ANY), 0), IPPrefix(IPAddress(IPV6_ANY), 0)}, + {LT, IPPrefix(IPAddress(IPV4_ONES)), IPPrefix(IPAddress(IPV6_ANY))}, + // Unspecified < IPv6. + {LT, IPPrefix(), IPPrefix(IPAddress(IPV6_ANY), 0)}, + // Same IPv6 base address sorts by prefix length. + {LT, IPPrefix(IPAddress(IPV6_ANY), 0), IPPrefix(IPAddress(IPV6_ANY), 1)}, + {LT, IPPrefix(IPAddress(IPV6_ANY), 1), IPPrefix(IPAddress(IPV6_ANY), IPV6_ADDR_BITS)}, + // Truncation means each base IPv6 address is different. + {LT, IPPrefix(IPAddress(IPV6_ONES), 0), IPPrefix(IPAddress(IPV6_ONES), 1)}, + {LT, IPPrefix(IPAddress(IPV6_ONES), 1), IPPrefix(IPAddress(IPV6_ONES), IPV6_ADDR_BITS)}, + // Different IPv6 link-local address in same /64, different scoped_id: different /64. + {LT, IPPrefix(IPAddress(FE80_1, 17), 64), IPPrefix(IPAddress(FE80_2, 22), 64)}, + {LT, IPPrefix(IPAddress(FE80_1, 17), 64), IPPrefix(IPAddress(FE80_1, 18), 64)}, + {LT, IPPrefix(IPAddress(FE80_1, 18), 64), IPPrefix(IPAddress(FE80_1, 19), 64)}, + }; + + size_t tests_run = 0; + for (const auto& expectation : kExpectations) { + SCOPED_TRACE(expectation.toString()); + EXPECT_NO_FATAL_FAILURE(testGamutOfOperators(expectation)); + tests_run++; + } + EXPECT_EQ(kExpectations.size(), tests_run); +} + +TEST(IPSockAddrTest, GamutOfOperators) { + const std::vector> kExpectations{ + {EQ, IPSockAddr(), IPSockAddr()}, + {EQ, IPSockAddr(IPAddress(IPV4_ANY)), IPSockAddr(IPAddress(IPV4_ANY), 0)}, + {EQ, IPSockAddr(IPAddress(IPV6_ANY)), IPSockAddr(IPAddress(IPV6_ANY), 0)}, + {EQ, IPSockAddr(IPAddress(FE80_1), 80), IPSockAddr(IPAddress(FE80_1), 80)}, + {EQ, IPSockAddr(IPAddress(FE80_1, 17)), IPSockAddr(IPAddress(FE80_1, 17), 0)}, + {LT, IPSockAddr(IPAddress(IPV4_ANY), 0), IPSockAddr(IPAddress(IPV4_ANY), 1)}, + {LT, IPSockAddr(IPAddress(IPV4_ANY), 53), IPSockAddr(IPAddress(IPV4_ANY), 123)}, + {LT, IPSockAddr(IPAddress(IPV4_ONES), 123), IPSockAddr(IPAddress(IPV6_ANY), 53)}, + {LT, IPSockAddr(IPAddress(IPV6_ANY), 0), IPSockAddr(IPAddress(IPV6_ANY), 1)}, + {LT, IPSockAddr(IPAddress(IPV6_ANY), 53), IPSockAddr(IPAddress(IPV6_ANY), 123)}, + {LT, IPSockAddr(IPAddress(FE80_1), 80), IPSockAddr(IPAddress(FE80_1, 17), 80)}, + {LT, IPSockAddr(IPAddress(FE80_1, 17), 80), IPSockAddr(IPAddress(FE80_1, 22), 80)}, + }; + + size_t tests_run = 0; + for (const auto& expectation : kExpectations) { + SCOPED_TRACE(expectation.toString()); + EXPECT_NO_FATAL_FAILURE(testGamutOfOperators(expectation)); + tests_run++; + } + EXPECT_EQ(kExpectations.size(), tests_run); +} + +TEST(IPSockAddrTest, toString) { + EXPECT_EQ(":0", IPSockAddr().toString()); + EXPECT_EQ("0.0.0.0:0", IPSockAddr(IPAddress(IPV4_ANY)).toString()); + EXPECT_EQ("255.255.255.255:67", IPSockAddr(IPAddress(IPV4_ONES), 67).toString()); + EXPECT_EQ("[::]:0", IPSockAddr(IPAddress(IPV6_ANY)).toString()); + EXPECT_EQ("[::1]:53", IPSockAddr(IPAddress(IPV6_LOOPBACK), 53).toString()); + EXPECT_EQ("[fe80::1]:0", IPSockAddr(IPAddress(FE80_1)).toString()); + EXPECT_EQ("[fe80::2%17]:123", IPSockAddr(IPAddress(FE80_2, 17), 123).toString()); +} + +TEST(CompatIPDataTest, ConversionsClearUnneededValues) { + const uint32_t idx = 17; + const IPSockAddr linkLocalNtpSockaddr(IPAddress(FE80_2, idx), 123); + EXPECT_EQ(IPAddress(FE80_2, idx), linkLocalNtpSockaddr.ip()); + // IPSockAddr(IPSockaddr.ip()) see the port cleared. + EXPECT_EQ(0, IPSockAddr(linkLocalNtpSockaddr.ip()).port()); + const IPPrefix linkLocalPrefix(linkLocalNtpSockaddr.ip(), 64); + EXPECT_EQ(IPAddress(FE80, idx), linkLocalPrefix.ip()); + // IPPrefix(IPPrefix.ip()) see the CIDR length cleared. + EXPECT_EQ(IPV6_ADDR_BITS, IPPrefix(linkLocalPrefix.ip()).length()); +} + +} // namespace +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/Log.cpp b/staticlibs/netd/libnetdutils/Log.cpp new file mode 100644 index 0000000000..d2ce98f094 --- /dev/null +++ b/staticlibs/netd/libnetdutils/Log.cpp @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2018 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. + */ + +#include "netdutils/Log.h" +#include "netdutils/Slice.h" + +#include +#include +#include +#include +#include + +#include +#include + +using ::android::base::Join; +using ::android::base::StringPrintf; + +namespace android { +namespace netdutils { + +namespace { + +std::string makeTimestampedEntry(const std::string& entry) { + using ::std::chrono::duration_cast; + using ::std::chrono::milliseconds; + using ::std::chrono::system_clock; + + std::stringstream tsEntry; + const auto now = system_clock::now(); + const auto time_sec = system_clock::to_time_t(now); + tsEntry << std::put_time(std::localtime(&time_sec), "%m-%d %H:%M:%S.") << std::setw(3) + << std::setfill('0') + << duration_cast(now - system_clock::from_time_t(time_sec)).count() << " " + << entry; + + return tsEntry.str(); +} + +} // namespace + +std::string LogEntry::toString() const { + std::vector text; + + if (!mMsg.empty()) text.push_back(mMsg); + if (!mFunc.empty()) { + text.push_back(StringPrintf("%s(%s)", mFunc.c_str(), Join(mArgs, ", ").c_str())); + } + if (!mReturns.empty()) { + text.push_back("->"); + text.push_back(StringPrintf("(%s)", Join(mReturns, ", ").c_str())); + } + if (!mUid.empty()) text.push_back(mUid); + if (!mDuration.empty()) text.push_back(StringPrintf("(%s)", mDuration.c_str())); + + return Join(text, " "); +} + +LogEntry& LogEntry::message(const std::string& message) { + mMsg = message; + return *this; +} + +LogEntry& LogEntry::function(const std::string& function_name) { + mFunc = function_name; + return *this; +} + +LogEntry& LogEntry::prettyFunction(const std::string& pretty_function) { + // __PRETTY_FUNCTION__ generally seems to be of the form: + // + // qualifed::returnType qualified::function(args...) + // + // where the qualified forms include "(anonymous namespace)" in the + // "::"-delimited list and keywords like "virtual" (where applicable). + // + // Here we try to convert strings like: + // + // virtual binder::Status android::net::NetdNativeService::isAlive(bool *) + // netdutils::LogEntry android::netd::(anonymous namespace)::AAA::BBB::function() + // + // into just "NetdNativeService::isAlive" or "BBB::function". Note that + // without imposing convention, how to easily identify any namespace/class + // name boundary is not obvious. + const size_t endFuncName = pretty_function.rfind('('); + const size_t precedingSpace = pretty_function.rfind(' ', endFuncName); + size_t substrStart = (precedingSpace != std::string::npos) ? precedingSpace + 1 : 0; + + const size_t beginFuncName = pretty_function.rfind("::", endFuncName); + if (beginFuncName != std::string::npos && substrStart < beginFuncName) { + const size_t previousNameBoundary = pretty_function.rfind("::", beginFuncName - 1); + if (previousNameBoundary < beginFuncName && substrStart < previousNameBoundary) { + substrStart = previousNameBoundary + 2; + } else { + substrStart = beginFuncName + 2; + } + } + + mFunc = pretty_function.substr(substrStart, endFuncName - substrStart); + return *this; +} + +LogEntry& LogEntry::arg(const std::string& val) { + mArgs.push_back(val.empty() ? "\"\"" : val); + return *this; +} + +template <> +LogEntry& LogEntry::arg<>(bool val) { + mArgs.push_back(val ? "true" : "false"); + return *this; +} + +LogEntry& LogEntry::arg(const std::vector& val) { + mArgs.push_back(StringPrintf("[%s]", Join(val, ", ").c_str())); + return *this; +} + +LogEntry& LogEntry::arg(const std::vector& val) { + mArgs.push_back('{' + toHex(makeSlice(val)) + '}'); + return *this; +} + +LogEntry& LogEntry::arg(const std::vector& val) { + mArgs.push_back(StringPrintf("[%s]", Join(val, ", ").c_str())); + return *this; +} + +LogEntry& LogEntry::returns(const std::string& rval) { + mReturns.push_back(rval); + return *this; +} + +LogEntry& LogEntry::returns(bool rval) { + mReturns.push_back(rval ? "true" : "false"); + return *this; +} + +LogEntry& LogEntry::returns(const Status& status) { + mReturns.push_back(status.msg()); + return *this; +} + +LogEntry& LogEntry::withUid(uid_t uid) { + mUid = StringPrintf("(uid=%d)", uid); + return *this; +} + +LogEntry& LogEntry::withAutomaticDuration() { + using ms = std::chrono::duration>; + + const std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); + std::stringstream duration; + duration << std::setprecision(1) << std::chrono::duration_cast(end - mStart).count() + << "ms"; + mDuration = duration.str(); + return *this; +} + +LogEntry& LogEntry::withDuration(const std::string& duration) { + mDuration = duration; + return *this; +} + +Log::~Log() { + // TODO: dump the last N entries to the android log for possible posterity. + info(LogEntry().function(__FUNCTION__)); +} + +void Log::forEachEntry(const std::function& perEntryFn) const { + // We make a (potentially expensive) copy of the log buffer (including + // all strings), in case the |perEntryFn| takes its sweet time. + std::deque entries; + { + std::shared_lock guard(mLock); + entries.assign(mEntries.cbegin(), mEntries.cend()); + } + + for (const std::string& entry : entries) perEntryFn(entry); +} + +void Log::record(Log::Level lvl, const std::string& entry) { + switch (lvl) { + case Level::LOG: + break; + case Level::INFO: + ALOG(LOG_INFO, mTag.c_str(), "%s", entry.c_str()); + break; + case Level::WARN: + ALOG(LOG_WARN, mTag.c_str(), "%s", entry.c_str()); + break; + case Level::ERROR: + ALOG(LOG_ERROR, mTag.c_str(), "%s", entry.c_str()); + break; + } + + std::lock_guard guard(mLock); + mEntries.push_back(makeTimestampedEntry(entry)); + while (mEntries.size() > mMaxEntries) mEntries.pop_front(); +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/LogTest.cpp b/staticlibs/netd/libnetdutils/LogTest.cpp new file mode 100644 index 0000000000..127056091b --- /dev/null +++ b/staticlibs/netd/libnetdutils/LogTest.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2018 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. + */ + +#include + +#include "netdutils/Log.h" + +android::netdutils::LogEntry globalFunctionName() { + return android::netdutils::LogEntry().function(__FUNCTION__); +} + +android::netdutils::LogEntry globalPrettyFunctionName() { + return android::netdutils::LogEntry().prettyFunction(__PRETTY_FUNCTION__); +} + +namespace android { +namespace netdutils { + +namespace { + +LogEntry functionName() { + return LogEntry().function(__FUNCTION__); +} + +LogEntry prettyFunctionName() { + return LogEntry().prettyFunction(__PRETTY_FUNCTION__); +} + +} // namespace + +class AAA { + public: + AAA() = default; + + LogEntry functionName() { + return LogEntry().function(__FUNCTION__); + } + + LogEntry prettyFunctionName() { + return LogEntry().prettyFunction(__PRETTY_FUNCTION__); + } + + class BBB { + public: + BBB() = default; + + LogEntry functionName() { + return LogEntry().function(__FUNCTION__); + } + + LogEntry prettyFunctionName() { + return LogEntry().prettyFunction(__PRETTY_FUNCTION__); + } + }; +}; + +TEST(LogEntryTest, Empty) { + LogEntry empty; + EXPECT_EQ("", empty.toString()); +} + +TEST(LogEntryTest, GlobalFunction) { + EXPECT_EQ("globalFunctionName()", ::globalFunctionName().toString()); +} + +TEST(LogEntryTest, GlobalPrettyFunction) { + EXPECT_EQ("globalPrettyFunctionName()", ::globalPrettyFunctionName().toString()); +} + +TEST(LogEntryTest, UnnamedNamespaceFunction) { + const LogEntry entry = functionName(); + EXPECT_EQ("functionName()", entry.toString()); +} + +TEST(LogEntryTest, UnnamedNamespacePrettyFunction) { + const LogEntry entry = prettyFunctionName(); + EXPECT_EQ("prettyFunctionName()", entry.toString()); +} + +TEST(LogEntryTest, ClassFunction) { + const LogEntry entry = AAA().functionName(); + EXPECT_EQ("functionName()", entry.toString()); +} + +TEST(LogEntryTest, ClassPrettyFunction) { + const LogEntry entry = AAA().prettyFunctionName(); + EXPECT_EQ("AAA::prettyFunctionName()", entry.toString()); +} + +TEST(LogEntryTest, InnerClassFunction) { + const LogEntry entry = AAA::BBB().functionName(); + EXPECT_EQ("functionName()", entry.toString()); +} + +TEST(LogEntryTest, InnerClassPrettyFunction) { + const LogEntry entry = AAA::BBB().prettyFunctionName(); + EXPECT_EQ("BBB::prettyFunctionName()", entry.toString()); +} + +TEST(LogEntryTest, PrintChainedArguments) { + const LogEntry entry = LogEntry() + .function("testFunc") + .arg("hello") + .arg(42) + .arg(true); + EXPECT_EQ("testFunc(hello, 42, true)", entry.toString()); +} + +TEST(LogEntryTest, PrintIntegralTypes) { + const LogEntry entry = LogEntry() + .function("testFunc") + .arg('A') + .arg(100U) + .arg(-1000LL); + EXPECT_EQ("testFunc(65, 100, -1000)", entry.toString()); +} + +TEST(LogEntryTest, PrintHex) { + const std::vector buf{0xDE, 0xAD, 0xBE, 0xEF}; + const LogEntry entry = LogEntry().function("testFunc").arg(buf); + EXPECT_EQ("testFunc({deadbeef})", entry.toString()); +} + +TEST(LogEntryTest, PrintArgumentPack) { + const LogEntry entry = LogEntry().function("testFunc").args("hello", 42, false); + EXPECT_EQ("testFunc(hello, 42, false)", entry.toString()); +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/MemBlockTest.cpp b/staticlibs/netd/libnetdutils/MemBlockTest.cpp new file mode 100644 index 0000000000..6455a7e01b --- /dev/null +++ b/staticlibs/netd/libnetdutils/MemBlockTest.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2018 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. + */ + +#include +#include +#include + +#include + +#include "netdutils/MemBlock.h" +#include "netdutils/Slice.h" + +namespace android { +namespace netdutils { + +namespace { + +constexpr unsigned DNS_PACKET_SIZE = 512; +constexpr int ARBITRARY_VALUE = 0x55; + +MemBlock makeArbitraryMemBlock(size_t len) { + MemBlock result(len); + // Do some fictional work before returning. + for (Slice slice = result.get(); !slice.empty(); slice = drop(slice, 1)) { + slice.base()[0] = ARBITRARY_VALUE; + } + return result; +} + +void checkAllZeros(Slice slice) { + for (; !slice.empty(); slice = drop(slice, 1)) { + EXPECT_EQ(0U, slice.base()[0]); + } +} + +void checkArbitraryMemBlock(const MemBlock& block, size_t expectedSize) { + Slice slice = block.get(); + EXPECT_EQ(expectedSize, slice.size()); + EXPECT_NE(nullptr, slice.base()); + for (; !slice.empty(); slice = drop(slice, 1)) { + EXPECT_EQ(ARBITRARY_VALUE, slice.base()[0]); + } +} + +void checkHelloMello(Slice dest, Slice src) { + EXPECT_EQ('h', dest.base()[0]); + EXPECT_EQ('e', dest.base()[1]); + EXPECT_EQ('l', dest.base()[2]); + EXPECT_EQ('l', dest.base()[3]); + EXPECT_EQ('o', dest.base()[4]); + + src.base()[0] = 'm'; + EXPECT_EQ('h', dest.base()[0]); +} + +} // namespace + +TEST(MemBlockTest, Empty) { + MemBlock empty; + EXPECT_TRUE(empty.get().empty()); + EXPECT_EQ(nullptr, empty.get().base()); +} + +TEST(MemBlockTest, ExplicitZero) { + MemBlock zero(0); + EXPECT_TRUE(zero.get().empty()); + EXPECT_EQ(nullptr, zero.get().base()); +} + +TEST(MemBlockTest, BasicAllocation) { + MemBlock dnsPacket(DNS_PACKET_SIZE); + Slice slice = dnsPacket.get(); + EXPECT_EQ(DNS_PACKET_SIZE, slice.size()); + // Verify the space is '\0'-initialized. + ASSERT_NO_FATAL_FAILURE(checkAllZeros(slice)); + EXPECT_NE(nullptr, slice.base()); +} + +TEST(MemBlockTest, MoveConstruction) { + MemBlock block(makeArbitraryMemBlock(DNS_PACKET_SIZE)); + ASSERT_NO_FATAL_FAILURE(checkArbitraryMemBlock(block, DNS_PACKET_SIZE)); +} + +TEST(MemBlockTest, MoveAssignmentOrConstruction) { + MemBlock block = makeArbitraryMemBlock(DNS_PACKET_SIZE); + ASSERT_NO_FATAL_FAILURE(checkArbitraryMemBlock(block, DNS_PACKET_SIZE)); +} + +TEST(MemBlockTest, StdMoveAssignment) { + constexpr unsigned SIZE = 10; + + MemBlock block; + EXPECT_TRUE(block.get().empty()); + EXPECT_EQ(nullptr, block.get().base()); + + { + MemBlock block2 = makeArbitraryMemBlock(SIZE); + EXPECT_EQ(SIZE, block2.get().size()); + // More fictional work. + for (unsigned i = 0; i < SIZE; i++) { + block2.get().base()[i] = i; + } + block = std::move(block2); + } + + EXPECT_EQ(SIZE, block.get().size()); + for (unsigned i = 0; i < SIZE; i++) { + EXPECT_EQ(i, block.get().base()[i]); + } +} + +TEST(MemBlockTest, ConstructionFromSlice) { + uint8_t data[] = {'h', 'e', 'l', 'l', 'o'}; + Slice dataSlice(Slice(data, sizeof(data) / sizeof(data[0]))); + + MemBlock dataCopy(dataSlice); + ASSERT_NO_FATAL_FAILURE(checkHelloMello(dataCopy.get(), dataSlice)); +} + +TEST(MemBlockTest, ImplicitCastToSlice) { + uint8_t data[] = {'h', 'e', 'l', 'l', 'o'}; + Slice dataSlice(Slice(data, sizeof(data) / sizeof(data[0]))); + + MemBlock dataCopy(dataSlice.size()); + // NOTE: no explicit MemBlock::get(). + // Verify the space is '\0'-initialized. + ASSERT_NO_FATAL_FAILURE(checkAllZeros(dataCopy)); + copy(dataCopy, dataSlice); + ASSERT_NO_FATAL_FAILURE(checkHelloMello(dataCopy, dataSlice)); +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/Netfilter.cpp b/staticlibs/netd/libnetdutils/Netfilter.cpp new file mode 100644 index 0000000000..bb43de0ab6 --- /dev/null +++ b/staticlibs/netd/libnetdutils/Netfilter.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2017 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. + */ + +#include +#include +#include +#include +#include + +#include "netdutils/Netfilter.h" + +std::ostream& operator<<(std::ostream& os, const nfgenmsg& msg) { + return os << std::hex << "nfgenmsg[" + << "family: 0x" << static_cast(msg.nfgen_family) << ", version: 0x" + << static_cast(msg.version) << ", res_id: 0x" << ntohs(msg.res_id) << "]" + << std::dec; +} diff --git a/staticlibs/netd/libnetdutils/Netlink.cpp b/staticlibs/netd/libnetdutils/Netlink.cpp new file mode 100644 index 0000000000..824c0f224d --- /dev/null +++ b/staticlibs/netd/libnetdutils/Netlink.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2017 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. + */ + +#include +#include + +#include "netdutils/Math.h" +#include "netdutils/Netlink.h" + +namespace android { +namespace netdutils { + +void forEachNetlinkMessage(const Slice buf, + const std::function& onMsg) { + Slice tail = buf; + while (tail.size() >= sizeof(nlmsghdr)) { + nlmsghdr hdr = {}; + extract(tail, hdr); + const auto len = std::max(hdr.nlmsg_len, sizeof(hdr)); + onMsg(hdr, drop(take(tail, len), sizeof(hdr))); + tail = drop(tail, align(len, 2)); + } +} + +void forEachNetlinkAttribute(const Slice buf, + const std::function& onAttr) { + Slice tail = buf; + while (tail.size() >= sizeof(nlattr)) { + nlattr hdr = {}; + extract(tail, hdr); + const auto len = std::max(hdr.nla_len, sizeof(hdr)); + onAttr(hdr, drop(take(tail, len), sizeof(hdr))); + tail = drop(tail, align(len, 2)); + } +} + +} // namespace netdutils +} // namespace android + +bool operator==(const sockaddr_nl& lhs, const sockaddr_nl& rhs) { + return (lhs.nl_family == rhs.nl_family) && (lhs.nl_pid == rhs.nl_pid) && + (lhs.nl_groups == rhs.nl_groups); +} + +bool operator!=(const sockaddr_nl& lhs, const sockaddr_nl& rhs) { + return !(lhs == rhs); +} + +std::ostream& operator<<(std::ostream& os, const nlmsghdr& hdr) { + return os << std::hex << "nlmsghdr[" + << "len: 0x" << hdr.nlmsg_len << ", type: 0x" << hdr.nlmsg_type << ", flags: 0x" + << hdr.nlmsg_flags << ", seq: 0x" << hdr.nlmsg_seq << ", pid: 0x" << hdr.nlmsg_pid + << "]" << std::dec; +} + +std::ostream& operator<<(std::ostream& os, const nlattr& attr) { + return os << std::hex << "nlattr[" + << "len: 0x" << attr.nla_len << ", type: 0x" << attr.nla_type << "]" << std::dec; +} + +std::ostream& operator<<(std::ostream& os, const sockaddr_nl& addr) { + return os << std::hex << "sockaddr_nl[" + << "family: " << addr.nl_family << ", pid: " << addr.nl_pid + << ", groups: " << addr.nl_groups << "]" << std::dec; +} diff --git a/staticlibs/netd/libnetdutils/Slice.cpp b/staticlibs/netd/libnetdutils/Slice.cpp new file mode 100644 index 0000000000..7a07d477e7 --- /dev/null +++ b/staticlibs/netd/libnetdutils/Slice.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2017 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. + */ + +#include + +#include "netdutils/Slice.h" + +namespace android { +namespace netdutils { +namespace { + +// Convert one byte to a two character hexadecimal string +const std::string toHex(uint8_t byte) { + const std::array kLookup = { + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}}; + return {kLookup[byte >> 4], kLookup[byte & 0xf]}; +} + +} // namespace + +std::string toString(const Slice s) { + return std::string(reinterpret_cast(s.base()), s.size()); +} + +std::string toHex(const Slice s, int wrap) { + Slice tail = s; + int count = 0; + std::stringstream ss; + while (!tail.empty()) { + uint8_t byte = 0; + extract(tail, byte); + ss << toHex(byte); + if ((++count % wrap) == 0) { + ss << "\n"; + } + tail = drop(tail, 1); + } + return ss.str(); +} + +std::ostream& operator<<(std::ostream& os, const Slice& slice) { + return os << std::hex << "Slice[base: " << reinterpret_cast(slice.base()) + << ", limit: " << reinterpret_cast(slice.limit()) << ", size: 0x" + << slice.size() << "]" << std::dec; +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/SliceTest.cpp b/staticlibs/netd/libnetdutils/SliceTest.cpp new file mode 100644 index 0000000000..a4969331bd --- /dev/null +++ b/staticlibs/netd/libnetdutils/SliceTest.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2017 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. + */ + +#include +#include + +#include + +#include "netdutils/Slice.h" +#include "netdutils/Status.h" +#include "netdutils/StatusOr.h" + +namespace android { +namespace netdutils { + +class SliceTest : public testing::Test { + protected: + std::array mRaw = {}; +}; + +TEST_F(SliceTest, smoke) { + Slice s1 = makeSlice(mRaw); + Slice s2 = makeSlice(mRaw); + auto p = split(s1, 14); + s2 = p.first; // avoid warn-unused error + std::stringstream ss; + ss << Slice(); + EXPECT_EQ("Slice[base: 0x0, limit: 0x0, size: 0x0]", ss.str()); + constexpr size_t kBytes = 14; + EXPECT_EQ(s1.base(), take(s1, kBytes).base()); + EXPECT_EQ(kBytes, take(s1, kBytes).size()); + EXPECT_EQ(s1.base() + kBytes, drop(s1, kBytes).base()); + EXPECT_EQ(s1.size() - kBytes, drop(s1, kBytes).size()); + double a = 0; + double b = 0; + int c = 0; + EXPECT_EQ(sizeof(a), extract(s1, a)); + EXPECT_EQ(sizeof(a) + sizeof(b), extract(s1, a, b)); + EXPECT_EQ(sizeof(a) + sizeof(b) + sizeof(c), extract(s1, a, b, c)); +} + +TEST_F(SliceTest, constructor) { + // Expect the following lines to compile + Slice s1 = makeSlice(mRaw); + Slice s2(s1); + Slice s3 = s2; + const Slice s4(s3); + const Slice s5 = s4; + s3 = s5; + Slice s6(mRaw.data(), mRaw.size()); + Slice s7(mRaw.data(), mRaw.data() + mRaw.size()); + struct { + int a; + double b; + float c; + } anon; + makeSlice(anon); + EXPECT_EQ(reinterpret_cast(mRaw.data()), s1.base()); + EXPECT_EQ(reinterpret_cast(mRaw.data()) + mRaw.size(), s1.limit()); + EXPECT_EQ(mRaw.size(), s1.size()); + EXPECT_FALSE(mRaw.empty()); + EXPECT_TRUE(Slice().empty()); + EXPECT_TRUE(Slice(nullptr, static_cast(0)).empty()); + EXPECT_TRUE(Slice(nullptr, nullptr).empty()); +} + +TEST_F(SliceTest, extract) { + struct A { + int a, b; + bool operator==(const A& other) const { return a == other.a && b == other.b; } + }; + struct B { + char str[12]; + bool b; + int i; + bool operator==(const B& other) const { + return b == other.b && i == other.i && 0 == strncmp(str, other.str, 12); + } + }; + + A origA1 = {1, 2}; + A origA2 = {3, 4}; + B origB = {"hello world", true, 1234}; + + // Populate buffer for extracting. + Slice buffer = makeSlice(mRaw); + copy(buffer, makeSlice(origA1)); + copy(drop(buffer, sizeof(origA1)), makeSlice(origB)); + copy(drop(buffer, sizeof(origA1) + sizeof(origB)), makeSlice(origA2)); + + { + // Non-variadic extract + A a1{}; + size_t len = extract(buffer, a1); + EXPECT_EQ(sizeof(A), len); + EXPECT_EQ(origA1, a1); + } + + { + // Variadic extract, 2 destinations + A a1{}; + B b{}; + size_t len = extract(buffer, a1, b); + EXPECT_EQ(sizeof(A) + sizeof(B), len); + EXPECT_EQ(origA1, a1); + EXPECT_EQ(origB, b); + } + + { + // Variadic extract, 3 destinations + A a1{}, a2{}; + B b{}; + size_t len = extract(buffer, a1, b, a2); + EXPECT_EQ(2 * sizeof(A) + sizeof(B), len); + EXPECT_EQ(origA1, a1); + EXPECT_EQ(origB, b); + EXPECT_EQ(origA2, a2); + } +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/Socket.cpp b/staticlibs/netd/libnetdutils/Socket.cpp new file mode 100644 index 0000000000..e962b6e5d3 --- /dev/null +++ b/staticlibs/netd/libnetdutils/Socket.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2017 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. + */ + +#include + +#include "netdutils/Slice.h" +#include "netdutils/Socket.h" + +namespace android { +namespace netdutils { + +StatusOr toString(const in6_addr& addr) { + std::array out = {}; + auto* rv = inet_ntop(AF_INET6, &addr, out.data(), out.size()); + if (rv == nullptr) { + return statusFromErrno(errno, "inet_ntop() failed"); + } + return std::string(out.data()); +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/SocketOption.cpp b/staticlibs/netd/libnetdutils/SocketOption.cpp new file mode 100644 index 0000000000..023df6e8b9 --- /dev/null +++ b/staticlibs/netd/libnetdutils/SocketOption.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018 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. + */ + +#include "netdutils/SocketOption.h" + +#include +#include +#include +#include + +#include "netdutils/Syscalls.h" + +namespace android { +namespace netdutils { + +Status enableSockopt(Fd sock, int level, int optname) { + auto& sys = sSyscalls.get(); + const int on = 1; + return sys.setsockopt(sock, level, optname, &on, sizeof(on)); +} + +Status enableTcpKeepAlives(Fd sock, unsigned idleTime, unsigned numProbes, unsigned probeInterval) { + RETURN_IF_NOT_OK(enableSockopt(sock, SOL_SOCKET, SO_KEEPALIVE)); + + auto& sys = sSyscalls.get(); + if (idleTime != 0) { + RETURN_IF_NOT_OK(sys.setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &idleTime, sizeof(idleTime))); + } + if (numProbes != 0) { + RETURN_IF_NOT_OK(sys.setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &numProbes, sizeof(numProbes))); + } + if (probeInterval != 0) { + RETURN_IF_NOT_OK(sys.setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &probeInterval, + sizeof(probeInterval))); + } + + return status::ok; +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/Status.cpp b/staticlibs/netd/libnetdutils/Status.cpp new file mode 100644 index 0000000000..acd8f11a36 --- /dev/null +++ b/staticlibs/netd/libnetdutils/Status.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2017 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. + */ + +#include "netdutils/Status.h" + +#include + +#include "android-base/stringprintf.h" + +namespace android { +namespace netdutils { + +Status statusFromErrno(int err, const std::string& msg) { + return Status(err, base::StringPrintf("[%s] : %s", strerror(err), msg.c_str())); +} + +bool equalToErrno(const Status& status, int err) { + return status.code() == err; +} + +std::string toString(const Status& status) { + std::stringstream ss; + ss << status; + return ss.str(); +} + +std::ostream& operator<<(std::ostream& os, const Status& s) { + return os << "Status[code: " << s.code() << ", msg: \"" << s.msg() << "\"]"; +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/StatusTest.cpp b/staticlibs/netd/libnetdutils/StatusTest.cpp new file mode 100644 index 0000000000..4cfc3bbbc3 --- /dev/null +++ b/staticlibs/netd/libnetdutils/StatusTest.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2017 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. + */ + +#include "netdutils/Status.h" +#include "netdutils/StatusOr.h" + +#include + +#include + +namespace android { +namespace netdutils { +namespace { + +TEST(StatusTest, valueSemantics) { + // Default constructor + EXPECT_EQ(status::ok, Status()); + + // Copy constructor + Status status1(1); + Status status2(status1); // NOLINT(performance-unnecessary-copy-initialization) + EXPECT_EQ(1, status2.code()); + + // Copy assignment + Status status3; + status3 = status2; + EXPECT_EQ(1, status3.code()); + + // Same with const objects + const Status status4(4); + const Status status5(status4); // NOLINT(performance-unnecessary-copy-initialization) + Status status6; + status6 = status5; + EXPECT_EQ(4, status6.code()); +} + +TEST(StatusTest, errorMessages) { + Status s(42, "for tea too"); + EXPECT_EQ(42, s.code()); + EXPECT_FALSE(s.ok()); + EXPECT_EQ(s.msg(), "for tea too"); +} + +TEST(StatusOrTest, moveSemantics) { + // Status objects should be cheaply movable. + EXPECT_TRUE(std::is_nothrow_move_constructible::value); + EXPECT_TRUE(std::is_nothrow_move_assignable::value); + + // Should move from a temporary Status (twice) + Status s(Status(Status(42, "move me"))); + EXPECT_EQ(42, s.code()); + EXPECT_EQ(s.msg(), "move me"); + + Status s2(666, "EDAEMON"); + EXPECT_NE(s, s2); + s = s2; // Invokes the move-assignment operator. + EXPECT_EQ(666, s.code()); + EXPECT_EQ(s.msg(), "EDAEMON"); + EXPECT_EQ(s, s2); + + // A moved-from Status can be re-used. + s2 = s; + + // Now both objects are valid. + EXPECT_EQ(666, s.code()); + EXPECT_EQ(s.msg(), "EDAEMON"); + EXPECT_EQ(s, s2); +} + +TEST(StatusTest, ignoredStatus) { + statusFromErrno(ENOTTY, "Not a typewriter, what did you expect?").ignoreError(); +} + +TEST(StatusOrTest, ostream) { + { + StatusOr so(11); + std::stringstream ss; + ss << so; + // TODO: Fix StatusOr to optionally output "value:". + EXPECT_EQ("StatusOr[status: Status[code: 0, msg: \"\"]]", ss.str()); + } + { + StatusOr err(status::undefined); + std::stringstream ss; + ss << err; + EXPECT_EQ("StatusOr[status: Status[code: 2147483647, msg: \"undefined\"]]", ss.str()); + } +} + +} // namespace +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/Syscalls.cpp b/staticlibs/netd/libnetdutils/Syscalls.cpp new file mode 100644 index 0000000000..9f653f70c7 --- /dev/null +++ b/staticlibs/netd/libnetdutils/Syscalls.cpp @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2017 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. + */ + +#include "netdutils/Syscalls.h" + +#include +#include +#include + +namespace android { +namespace netdutils { +namespace { + +// Retry syscall fn as long as it returns -1 with errno == EINTR +template +typename std::result_of::type syscallRetry(FnT fn, Params&&... params) { + auto rv = fn(std::forward(params)...); + while ((rv == -1) && (errno == EINTR)) { + rv = fn(std::forward(params)...); + } + return rv; +} + +} // namespace + +// Production implementation of Syscalls that forwards to libc syscalls. +class RealSyscalls final : public Syscalls { + public: + ~RealSyscalls() override = default; + + StatusOr open(const std::string& pathname, int flags, mode_t mode) const override { + UniqueFd fd(::open(pathname.c_str(), flags, mode)); + if (!isWellFormed(fd)) { + return statusFromErrno(errno, "open(\"" + pathname + "\"...) failed"); + } + return fd; + } + + StatusOr socket(int domain, int type, int protocol) const override { + UniqueFd sock(::socket(domain, type, protocol)); + if (!isWellFormed(sock)) { + return statusFromErrno(errno, "socket() failed"); + } + return sock; + } + + Status getsockname(Fd sock, sockaddr* addr, socklen_t* addrlen) const override { + auto rv = ::getsockname(sock.get(), addr, addrlen); + if (rv == -1) { + return statusFromErrno(errno, "getsockname() failed"); + } + return status::ok; + } + + Status getsockopt(Fd sock, int level, int optname, void* optval, + socklen_t* optlen) const override { + auto rv = ::getsockopt(sock.get(), level, optname, optval, optlen); + if (rv == -1) { + return statusFromErrno(errno, "getsockopt() failed"); + } + return status::ok; + } + + Status setsockopt(Fd sock, int level, int optname, const void* optval, + socklen_t optlen) const override { + auto rv = ::setsockopt(sock.get(), level, optname, optval, optlen); + if (rv == -1) { + return statusFromErrno(errno, "setsockopt() failed"); + } + return status::ok; + } + + Status bind(Fd sock, const sockaddr* addr, socklen_t addrlen) const override { + auto rv = ::bind(sock.get(), addr, addrlen); + if (rv == -1) { + return statusFromErrno(errno, "bind() failed"); + } + return status::ok; + } + + Status connect(Fd sock, const sockaddr* addr, socklen_t addrlen) const override { + auto rv = syscallRetry(::connect, sock.get(), addr, addrlen); + if (rv == -1) { + return statusFromErrno(errno, "connect() failed"); + } + return status::ok; + } + + StatusOr ioctl(Fd sock, unsigned long request, ifreq* ifr) const override { + auto rv = ::ioctl(sock.get(), request, ifr); + if (rv == -1) { + return statusFromErrno(errno, "ioctl() failed"); + } + return *ifr; + } + + StatusOr eventfd(unsigned int initval, int flags) const override { + UniqueFd fd(::eventfd(initval, flags)); + if (!isWellFormed(fd)) { + return statusFromErrno(errno, "eventfd() failed"); + } + return fd; + } + + StatusOr ppoll(pollfd* fds, nfds_t nfds, double timeout) const override { + timespec ts = {}; + ts.tv_sec = timeout; + ts.tv_nsec = (timeout - ts.tv_sec) * 1e9; + auto rv = syscallRetry(::ppoll, fds, nfds, &ts, nullptr); + if (rv == -1) { + return statusFromErrno(errno, "ppoll() failed"); + } + return rv; + } + + StatusOr writev(Fd fd, const std::vector& iov) const override { + auto rv = syscallRetry(::writev, fd.get(), iov.data(), iov.size()); + if (rv == -1) { + return statusFromErrno(errno, "writev() failed"); + } + return rv; + } + + StatusOr write(Fd fd, const Slice buf) const override { + auto rv = syscallRetry(::write, fd.get(), buf.base(), buf.size()); + if (rv == -1) { + return statusFromErrno(errno, "write() failed"); + } + return static_cast(rv); + } + + StatusOr read(Fd fd, const Slice buf) const override { + auto rv = syscallRetry(::read, fd.get(), buf.base(), buf.size()); + if (rv == -1) { + return statusFromErrno(errno, "read() failed"); + } + return Slice(buf.base(), rv); + } + + StatusOr sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst, + socklen_t dstlen) const override { + auto rv = syscallRetry(::sendto, sock.get(), buf.base(), buf.size(), flags, dst, dstlen); + if (rv == -1) { + return statusFromErrno(errno, "sendto() failed"); + } + return static_cast(rv); + } + + StatusOr recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src, + socklen_t* srclen) const override { + auto rv = syscallRetry(::recvfrom, sock.get(), dst.base(), dst.size(), flags, src, srclen); + if (rv == -1) { + return statusFromErrno(errno, "recvfrom() failed"); + } + if (rv == 0) { + return status::eof; + } + return take(dst, rv); + } + + Status shutdown(Fd fd, int how) const override { + auto rv = ::shutdown(fd.get(), how); + if (rv == -1) { + return statusFromErrno(errno, "shutdown() failed"); + } + return status::ok; + } + + Status close(Fd fd) const override { + auto rv = ::close(fd.get()); + if (rv == -1) { + return statusFromErrno(errno, "close() failed"); + } + return status::ok; + } + + StatusOr fopen(const std::string& path, const std::string& mode) const override { + UniqueFile file(::fopen(path.c_str(), mode.c_str())); + if (file == nullptr) { + return statusFromErrno(errno, "fopen(\"" + path + "\", \"" + mode + "\") failed"); + } + return file; + } + + StatusOr fork() const override { + pid_t rv = ::fork(); + if (rv == -1) { + return statusFromErrno(errno, "fork() failed"); + } + return rv; + } + + StatusOr vfprintf(FILE* file, const char* format, va_list ap) const override { + auto rv = ::vfprintf(file, format, ap); + if (rv == -1) { + return statusFromErrno(errno, "vfprintf() failed"); + } + return rv; + } + + StatusOr vfscanf(FILE* file, const char* format, va_list ap) const override { + auto rv = ::vfscanf(file, format, ap); + if (rv == -1) { + return statusFromErrno(errno, "vfscanf() failed"); + } + return rv; + } + + Status fclose(FILE* file) const override { + auto rv = ::fclose(file); + if (rv == -1) { + return statusFromErrno(errno, "fclose() failed"); + } + return status::ok; + } +}; + +SyscallsHolder::~SyscallsHolder() { + delete &get(); +} + +Syscalls& SyscallsHolder::get() { + while (true) { + // memory_order_relaxed gives the compiler and hardware more + // freedom. If we get a stale value (this should only happen + // early in the execution of a program) the exchange code below + // will loop until we get the most current value. + auto* syscalls = mSyscalls.load(std::memory_order_relaxed); + // Common case returns existing syscalls + if (syscalls) { + return *syscalls; + } + + // This code will execute on first get() + std::unique_ptr tmp(new RealSyscalls()); + Syscalls* expected = nullptr; + bool success = mSyscalls.compare_exchange_strong(expected, tmp.get()); + if (success) { + // Ownership was transferred to mSyscalls already, must release() + return *tmp.release(); + } + } +} + +Syscalls& SyscallsHolder::swap(Syscalls& syscalls) { + return *mSyscalls.exchange(&syscalls); +} + +SyscallsHolder sSyscalls; + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/SyscallsTest.cpp b/staticlibs/netd/libnetdutils/SyscallsTest.cpp new file mode 100644 index 0000000000..78ffab5e25 --- /dev/null +++ b/staticlibs/netd/libnetdutils/SyscallsTest.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2017 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. + */ + +#include +#include +#include + +#include + +#include "netdutils/Handle.h" +#include "netdutils/Math.h" +#include "netdutils/MockSyscalls.h" +#include "netdutils/Netfilter.h" +#include "netdutils/Netlink.h" +#include "netdutils/Slice.h" +#include "netdutils/Status.h" +#include "netdutils/StatusOr.h" +#include "netdutils/Syscalls.h" + +using testing::_; +using testing::ByMove; +using testing::Invoke; +using testing::Return; +using testing::StrictMock; + +namespace android { +namespace netdutils { + +class SyscallsTest : public testing::Test { + protected: + StrictMock mSyscalls; +}; + +TEST(syscalls, scopedMock) { + auto& old = sSyscalls.get(); + { + StrictMock s; + EXPECT_EQ(&s, &sSyscalls.get()); + } + EXPECT_EQ(&old, &sSyscalls.get()); +} + +TEST_F(SyscallsTest, open) { + const char kPath[] = "/test/path/please/ignore"; + constexpr Fd kFd(40); + constexpr int kFlags = 883; + constexpr mode_t kMode = 37373; + const auto& sys = sSyscalls.get(); + EXPECT_CALL(mSyscalls, open(kPath, kFlags, kMode)).WillOnce(Return(ByMove(UniqueFd(kFd)))); + EXPECT_CALL(mSyscalls, close(kFd)).WillOnce(Return(status::ok)); + auto result = sys.open(kPath, kFlags, kMode); + EXPECT_EQ(status::ok, result.status()); + EXPECT_EQ(kFd, result.value()); +} + +TEST_F(SyscallsTest, getsockname) { + constexpr Fd kFd(40); + sockaddr_nl expected = {}; + auto& sys = sSyscalls.get(); + + // Success + EXPECT_CALL(mSyscalls, getsockname(kFd, _, _)) + .WillOnce(Invoke([expected](Fd, sockaddr* addr, socklen_t* addrlen) { + memcpy(addr, &expected, sizeof(expected)); + EXPECT_EQ(*addrlen, static_cast(sizeof(expected))); + return status::ok; + })); + const auto result = sys.getsockname(kFd); + EXPECT_TRUE(isOk(result)); + EXPECT_EQ(expected, result.value()); + + // Failure + const Status kError = statusFromErrno(EINVAL, "test"); + EXPECT_CALL(mSyscalls, getsockname(kFd, _, _)).WillOnce(Return(kError)); + EXPECT_EQ(kError, sys.getsockname(kFd).status()); +} + +TEST_F(SyscallsTest, setsockopt) { + constexpr Fd kFd(40); + constexpr int kLevel = 50; + constexpr int kOptname = 70; + sockaddr_nl expected = {}; + auto& sys = sSyscalls.get(); + + // Success + EXPECT_CALL(mSyscalls, setsockopt(kFd, kLevel, kOptname, &expected, sizeof(expected))) + .WillOnce(Return(status::ok)); + EXPECT_EQ(status::ok, sys.setsockopt(kFd, kLevel, kOptname, expected)); + + // Failure + const Status kError = statusFromErrno(EINVAL, "test"); + EXPECT_CALL(mSyscalls, setsockopt(kFd, kLevel, kOptname, &expected, sizeof(expected))) + .WillOnce(Return(kError)); + EXPECT_EQ(kError, sys.setsockopt(kFd, kLevel, kOptname, expected)); +} + +TEST_F(SyscallsTest, getsockopt) { + constexpr Fd kFd(40); + constexpr int kLevel = 50; + constexpr int kOptname = 70; + sockaddr_nl expected = {}; + socklen_t optLen = 0; + auto& sys = sSyscalls.get(); + + // Success + EXPECT_CALL(mSyscalls, getsockopt(kFd, kLevel, kOptname, &expected, &optLen)) + .WillOnce(Return(status::ok)); + EXPECT_EQ(status::ok, sys.getsockopt(kFd, kLevel, kOptname, &expected, &optLen)); + + // Failure + const Status kError = statusFromErrno(EINVAL, "test"); + EXPECT_CALL(mSyscalls, getsockopt(kFd, kLevel, kOptname, &expected, &optLen)) + .WillOnce(Return(kError)); + EXPECT_EQ(kError, sys.getsockopt(kFd, kLevel, kOptname, &expected, &optLen)); +} + +TEST_F(SyscallsTest, bind) { + constexpr Fd kFd(40); + sockaddr_nl expected = {}; + auto& sys = sSyscalls.get(); + + // Success + EXPECT_CALL(mSyscalls, bind(kFd, asSockaddrPtr(&expected), sizeof(expected))) + .WillOnce(Return(status::ok)); + EXPECT_EQ(status::ok, sys.bind(kFd, expected)); + + // Failure + const Status kError = statusFromErrno(EINVAL, "test"); + EXPECT_CALL(mSyscalls, bind(kFd, asSockaddrPtr(&expected), sizeof(expected))) + .WillOnce(Return(kError)); + EXPECT_EQ(kError, sys.bind(kFd, expected)); +} + +TEST_F(SyscallsTest, connect) { + constexpr Fd kFd(40); + sockaddr_nl expected = {}; + auto& sys = sSyscalls.get(); + + // Success + EXPECT_CALL(mSyscalls, connect(kFd, asSockaddrPtr(&expected), sizeof(expected))) + .WillOnce(Return(status::ok)); + EXPECT_EQ(status::ok, sys.connect(kFd, expected)); + + // Failure + const Status kError = statusFromErrno(EINVAL, "test"); + EXPECT_CALL(mSyscalls, connect(kFd, asSockaddrPtr(&expected), sizeof(expected))) + .WillOnce(Return(kError)); + EXPECT_EQ(kError, sys.connect(kFd, expected)); +} + +TEST_F(SyscallsTest, sendto) { + constexpr Fd kFd(40); + constexpr int kFlags = 0; + std::array payload; + const auto slice = makeSlice(payload); + sockaddr_nl expected = {}; + auto& sys = sSyscalls.get(); + + // Success + EXPECT_CALL(mSyscalls, sendto(kFd, slice, kFlags, asSockaddrPtr(&expected), sizeof(expected))) + .WillOnce(Return(slice.size())); + EXPECT_EQ(status::ok, sys.sendto(kFd, slice, kFlags, expected)); +} + +TEST_F(SyscallsTest, recvfrom) { + constexpr Fd kFd(40); + constexpr int kFlags = 0; + std::array payload; + const auto dst = makeSlice(payload); + const auto used = take(dst, 8); + sockaddr_nl expected = {}; + auto& sys = sSyscalls.get(); + + // Success + EXPECT_CALL(mSyscalls, recvfrom(kFd, dst, kFlags, _, _)) + .WillOnce(Invoke( + [expected, used](Fd, const Slice, int, sockaddr* src, socklen_t* srclen) { + *srclen = sizeof(expected); + memcpy(src, &expected, *srclen); + return used; + })); + auto result = sys.recvfrom(kFd, dst, kFlags); + EXPECT_EQ(status::ok, result.status()); + EXPECT_EQ(used, result.value().first); + EXPECT_EQ(expected, result.value().second); +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/ThreadUtilTest.cpp b/staticlibs/netd/libnetdutils/ThreadUtilTest.cpp new file mode 100644 index 0000000000..8fad8b8e5a --- /dev/null +++ b/staticlibs/netd/libnetdutils/ThreadUtilTest.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2019 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. + */ + +#include + +#include +#include +#include + +namespace android::netdutils { + +namespace { + +android::base::expected getThreadName() { + char name[16] = {}; + if (const int ret = pthread_getname_np(pthread_self(), name, sizeof(name)); ret != 0) { + return android::base::unexpected(ret); + } + return std::string(name); +} + +class NoopRun { + public: + explicit NoopRun(const std::string& name = "") : mName(name) { instanceNum++; } + + // Destructor happens in the thread. + ~NoopRun() { + if (checkName) { + auto expected = getThreadName(); + EXPECT_TRUE(expected.has_value()); + EXPECT_EQ(mExpectedName, expected.value()); + } + instanceNum--; + } + + void run() {} + + std::string threadName() { return mName; } + + // Set the expected thread name which will be used to check if it matches the actual thread + // name which is returned from the system call. The check will happen in the destructor. + void setExpectedName(const std::string& expectedName) { + checkName = true; + mExpectedName = expectedName; + } + + static bool waitForAllReleased(int timeoutMs) { + constexpr int intervalMs = 20; + int limit = timeoutMs / intervalMs; + for (int i = 1; i < limit; i++) { + if (instanceNum == 0) { + return true; + } + usleep(intervalMs * 1000); + } + return false; + } + + // To track how many instances are alive. + static std::atomic instanceNum; + + private: + std::string mName; + std::string mExpectedName; + bool checkName = false; +}; + +std::atomic NoopRun::instanceNum; + +} // namespace + +TEST(ThreadUtilTest, objectReleased) { + NoopRun::instanceNum = 0; + NoopRun* obj = new NoopRun(); + EXPECT_EQ(1, NoopRun::instanceNum); + threadLaunch(obj); + + // Wait for the object released along with the thread exited. + EXPECT_TRUE(NoopRun::waitForAllReleased(1000)); + EXPECT_EQ(0, NoopRun::instanceNum); +} + +TEST(ThreadUtilTest, SetThreadName) { + NoopRun::instanceNum = 0; + + // Test thread name empty. + NoopRun* obj1 = new NoopRun(); + obj1->setExpectedName(""); + + // Test normal case. + NoopRun* obj2 = new NoopRun("TestName"); + obj2->setExpectedName("TestName"); + + // Test thread name too long. + std::string name("TestNameTooooLong"); + NoopRun* obj3 = new NoopRun(name); + obj3->setExpectedName(name.substr(0, 15)); + + // Thread names are examined in their destructors. + EXPECT_EQ(3, NoopRun::instanceNum); + threadLaunch(obj1); + threadLaunch(obj2); + threadLaunch(obj3); + + EXPECT_TRUE(NoopRun::waitForAllReleased(1000)); + EXPECT_EQ(0, NoopRun::instanceNum); +} + +} // namespace android::netdutils diff --git a/staticlibs/netd/libnetdutils/UniqueFd.cpp b/staticlibs/netd/libnetdutils/UniqueFd.cpp new file mode 100644 index 0000000000..1cb30edde2 --- /dev/null +++ b/staticlibs/netd/libnetdutils/UniqueFd.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2017 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. + */ + +#include + +#include "netdutils/UniqueFd.h" +#include "netdutils/Syscalls.h" + +namespace android { +namespace netdutils { + +void UniqueFd::reset(Fd fd) { + auto& sys = sSyscalls.get(); + std::swap(fd, mFd); + if (isWellFormed(fd)) { + expectOk(sys.close(fd)); + } +} + +std::ostream& operator<<(std::ostream& os, const UniqueFd& fd) { + return os << "UniqueFd[" << static_cast(fd) << "]"; +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/UniqueFile.cpp b/staticlibs/netd/libnetdutils/UniqueFile.cpp new file mode 100644 index 0000000000..21e8779805 --- /dev/null +++ b/staticlibs/netd/libnetdutils/UniqueFile.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2017 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. + */ + +#include + +#include "netdutils/Syscalls.h" +#include "netdutils/UniqueFile.h" + +namespace android { +namespace netdutils { + +void UniqueFileDtor::operator()(FILE* file) const { + const auto& sys = sSyscalls.get(); + sys.fclose(file).ignoreError(); +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/include/netdutils/BackoffSequence.h b/staticlibs/netd/libnetdutils/include/netdutils/BackoffSequence.h new file mode 100644 index 0000000000..a52e72d6dd --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/BackoffSequence.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef NETDUTILS_BACKOFFSEQUENCE_H +#define NETDUTILS_BACKOFFSEQUENCE_H + +#include +#include +#include +#include + +namespace android { +namespace netdutils { + +// Encapsulate some RFC 3315 section 14 -style backoff mechanics. +// +// https://tools.ietf.org/html/rfc3315#section-14 +template +class BackoffSequence { + public: + struct Parameters { + time_type initialRetransTime{TIME_UNITY}; + counter_type maxRetransCount{0U}; + time_type maxRetransTime{TIME_ZERO}; + time_type maxRetransDuration{TIME_ZERO}; + time_type endOfSequenceIndicator{TIME_ZERO}; + }; + + BackoffSequence() : BackoffSequence(Parameters{}) {} + BackoffSequence(const BackoffSequence &) = default; + BackoffSequence(BackoffSequence &&) = default; + BackoffSequence& operator=(const BackoffSequence &) = default; + BackoffSequence& operator=(BackoffSequence &&) = default; + + bool hasNextTimeout() const noexcept { + return !maxRetransCountExceed() && !maxRetransDurationExceeded(); + } + + // Returns 0 when the sequence is exhausted. + time_type getNextTimeout() { + if (!hasNextTimeout()) return getEndOfSequenceIndicator(); + + mRetransTime = getNextTimeoutAfter(mRetransTime); + + mRetransCount++; + mTotalRetransDuration += mRetransTime; + return mRetransTime; + } + + time_type getEndOfSequenceIndicator() const noexcept { + return mParams.endOfSequenceIndicator; + } + + class Builder { + public: + Builder() {} + + constexpr Builder& withInitialRetransmissionTime(time_type irt) { + mParams.initialRetransTime = irt; + return *this; + } + constexpr Builder& withMaximumRetransmissionCount(counter_type mrc) { + mParams.maxRetransCount = mrc; + return *this; + } + constexpr Builder& withMaximumRetransmissionTime(time_type mrt) { + mParams.maxRetransTime = mrt; + return *this; + } + constexpr Builder& withMaximumRetransmissionDuration(time_type mrd) { + mParams.maxRetransDuration = mrd; + return *this; + } + constexpr Builder& withEndOfSequenceIndicator(time_type eos) { + mParams.endOfSequenceIndicator = eos; + return *this; + } + + constexpr BackoffSequence build() const { + return BackoffSequence(mParams); + } + + private: + Parameters mParams; + }; + + private: + static constexpr int PER_ITERATION_SCALING_FACTOR = 2; + static constexpr time_type TIME_ZERO = time_type(); + static constexpr time_type TIME_UNITY = time_type(1); + + constexpr BackoffSequence(const struct Parameters ¶ms) + : mParams(params), + mRetransCount(0), + mRetransTime(TIME_ZERO), + mTotalRetransDuration(TIME_ZERO) {} + + constexpr bool maxRetransCountExceed() const { + return (mParams.maxRetransCount > 0) && (mRetransCount >= mParams.maxRetransCount); + } + + constexpr bool maxRetransDurationExceeded() const { + return (mParams.maxRetransDuration > TIME_ZERO) && + (mTotalRetransDuration >= mParams.maxRetransDuration); + } + + time_type getNextTimeoutAfter(time_type lastTimeout) const { + // TODO: Support proper random jitter. Also, consider supporting some + // per-iteration scaling factor other than doubling. + time_type nextTimeout = (lastTimeout > TIME_ZERO) + ? PER_ITERATION_SCALING_FACTOR * lastTimeout + : mParams.initialRetransTime; + + // Check if overflow occurred. + if (nextTimeout < lastTimeout) { + nextTimeout = std::numeric_limits::max(); + } + + // Cap to maximum allowed, if necessary. + if (mParams.maxRetransTime > TIME_ZERO) { + nextTimeout = std::min(nextTimeout, mParams.maxRetransTime); + } + + // Don't overflow the maximum total duration. + if (mParams.maxRetransDuration > TIME_ZERO) { + nextTimeout = std::min(nextTimeout, mParams.maxRetransDuration - lastTimeout); + } + return nextTimeout; + } + + const Parameters mParams; + counter_type mRetransCount; + time_type mRetransTime; + time_type mTotalRetransDuration; +}; + +} // namespace netdutils +} // namespace android + +#endif /* NETDUTILS_BACKOFFSEQUENCE_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/DumpWriter.h b/staticlibs/netd/libnetdutils/include/netdutils/DumpWriter.h new file mode 100644 index 0000000000..a50b5e60a3 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/DumpWriter.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef NETDUTILS_DUMPWRITER_H_ +#define NETDUTILS_DUMPWRITER_H_ + +#include + +namespace android { +namespace netdutils { + +class DumpWriter { + public: + DumpWriter(int fd); + + void incIndent(); + void decIndent(); + + void println(const std::string& line); + template + void println(const char line[n]) { + println(std::string(line)); + } + // Hint to the compiler that it should apply printf validation of + // arguments (beginning at position 3) of the format (specified in + // position 2). Note that position 1 is the implicit "this" argument. + void println(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))); + void blankline() { println(""); } + + private: + uint8_t mIndentLevel; + int mFd; +}; + +class ScopedIndent { + public: + ScopedIndent() = delete; + ScopedIndent(const ScopedIndent&) = delete; + ScopedIndent(ScopedIndent&&) = delete; + explicit ScopedIndent(DumpWriter& dw) : mDw(dw) { mDw.incIndent(); } + ~ScopedIndent() { mDw.decIndent(); } + ScopedIndent& operator=(const ScopedIndent&) = delete; + ScopedIndent& operator=(ScopedIndent&&) = delete; + + // TODO: consider additional {inc,dec}Indent methods and a counter that + // can be used to unwind all pending increments on exit. + + private: + DumpWriter& mDw; +}; + +} // namespace netdutils +} // namespace android + +#endif // NETDUTILS_DUMPWRITER_H_ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Fd.h b/staticlibs/netd/libnetdutils/include/netdutils/Fd.h new file mode 100644 index 0000000000..7db40870f1 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Fd.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_FD_H +#define NETUTILS_FD_H + +#include + +#include "netdutils/Status.h" + +namespace android { +namespace netdutils { + +// Strongly typed wrapper for file descriptors with value semantics. +// This class should typically hold unowned file descriptors. +class Fd { + public: + constexpr Fd() = default; + + constexpr Fd(int fd) : mFd(fd) {} + + int get() const { return mFd; } + + bool operator==(const Fd& other) const { return get() == other.get(); } + bool operator!=(const Fd& other) const { return get() != other.get(); } + + private: + int mFd = -1; +}; + +// Return true if fd appears valid (non-negative) +inline bool isWellFormed(const Fd fd) { + return fd.get() >= 0; +} + +std::ostream& operator<<(std::ostream& os, const Fd& fd); + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_FD_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Handle.h b/staticlibs/netd/libnetdutils/include/netdutils/Handle.h new file mode 100644 index 0000000000..82083d414e --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Handle.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_HANDLE_H +#define NETUTILS_HANDLE_H + +#include + +namespace android { +namespace netdutils { + +// Opaque, strongly typed wrapper for integer-like handles. +// Explicitly avoids implementing arithmetic operations. +// +// This class is intended to avoid common errors when reordering +// arguments to functions, typos and other cases where plain integer +// types would silently cover up the mistake. +// +// usage: +// DEFINE_HANDLE(ProductId, uint64_t); +// DEFINE_HANDLE(ThumbnailHash, uint64_t); +// void foo(ProductId p, ThumbnailHash th) {...} +// +// void test() { +// ProductId p(88); +// ThumbnailHash th1(100), th2(200); +// +// foo(p, th1); <- ok! +// foo(th1, p); <- disallowed! +// th1 += 10; <- disallowed! +// p = th2; <- disallowed! +// assert(th1 != th2); <- ok! +// } +template +class Handle { + public: + constexpr Handle() = default; + constexpr Handle(const T& value) : mValue(value) {} + + const T get() const { return mValue; } + + bool operator==(const Handle& that) const { return get() == that.get(); } + bool operator!=(const Handle& that) const { return get() != that.get(); } + + private: + T mValue; +}; + +#define DEFINE_HANDLE(name, type) \ + struct _##name##Tag {}; \ + using name = ::android::netdutils::Handle; + +template +inline std::ostream& operator<<(std::ostream& os, const Handle& handle) { + return os << handle.get(); +} + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_HANDLE_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/InternetAddresses.h b/staticlibs/netd/libnetdutils/include/netdutils/InternetAddresses.h new file mode 100644 index 0000000000..d5cbe2b466 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/InternetAddresses.h @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2018 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "netdutils/NetworkConstants.h" + +namespace android { +namespace netdutils { + +namespace internal_ { + +// A structure to hold data for dealing with Internet addresses (IPAddress) and +// related types such as IPSockAddr and IPPrefix. +struct compact_ipdata { + uint8_t family{AF_UNSPEC}; + uint8_t cidrlen{0U}; // written and read in host-byte order + in_port_t port{0U}; // written and read in host-byte order + uint32_t scope_id{0U}; + union { + in_addr v4; + in6_addr v6; + } ip{.v6 = IN6ADDR_ANY_INIT}; // written and read in network-byte order + + // Classes that use compact_ipdata and this method should be sure to clear + // (i.e. zero or make uniform) any fields not relevant to the class. + friend bool operator==(const compact_ipdata& a, const compact_ipdata& b) { + if ((a.family != b.family) || (a.cidrlen != b.cidrlen) || (a.port != b.port) || + (a.scope_id != b.scope_id)) { + return false; + } + switch (a.family) { + case AF_UNSPEC: + // After the above checks, two AF_UNSPEC objects can be + // considered equal, for convenience. + return true; + case AF_INET: { + const in_addr v4a = a.ip.v4; + const in_addr v4b = b.ip.v4; + return (v4a.s_addr == v4b.s_addr); + } + case AF_INET6: { + const in6_addr v6a = a.ip.v6; + const in6_addr v6b = b.ip.v6; + return IN6_ARE_ADDR_EQUAL(&v6a, &v6b); + } + } + return false; + } + + // Classes that use compact_ipdata and this method should be sure to clear + // (i.e. zero or make uniform) any fields not relevant to the class. + friend bool operator!=(const compact_ipdata& a, const compact_ipdata& b) { return !(a == b); } + + // Classes that use compact_ipdata and this method should be sure to clear + // (i.e. zero or make uniform) any fields not relevant to the class. + friend bool operator<(const compact_ipdata& a, const compact_ipdata& b) { + if (a.family != b.family) return (a.family < b.family); + switch (a.family) { + case AF_INET: { + const in_addr v4a = a.ip.v4; + const in_addr v4b = b.ip.v4; + if (v4a.s_addr != v4b.s_addr) return (ntohl(v4a.s_addr) < ntohl(v4b.s_addr)); + break; + } + case AF_INET6: { + const in6_addr v6a = a.ip.v6; + const in6_addr v6b = b.ip.v6; + const int cmp = std::memcmp(v6a.s6_addr, v6b.s6_addr, IPV6_ADDR_LEN); + if (cmp != 0) return cmp < 0; + break; + } + } + if (a.cidrlen != b.cidrlen) return (a.cidrlen < b.cidrlen); + if (a.port != b.port) return (a.port < b.port); + return (a.scope_id < b.scope_id); + } +}; + +static_assert(AF_UNSPEC <= std::numeric_limits::max(), "AF_UNSPEC value too large"); +static_assert(AF_INET <= std::numeric_limits::max(), "AF_INET value too large"); +static_assert(AF_INET6 <= std::numeric_limits::max(), "AF_INET6 value too large"); +static_assert(sizeof(compact_ipdata) == 24U, "compact_ipdata unexpectedly large"); + +} // namespace internal_ + +struct AddrinfoDeleter { + void operator()(struct addrinfo* p) const { + if (p != nullptr) { + freeaddrinfo(p); + } + } +}; + +typedef std::unique_ptr ScopedAddrinfo; + +inline bool usesScopedIds(const in6_addr& ipv6) { + return (IN6_IS_ADDR_LINKLOCAL(&ipv6) || IN6_IS_ADDR_MC_LINKLOCAL(&ipv6)); +} + +class IPPrefix; +class IPSockAddr; + +class IPAddress { + public: + static bool forString(const std::string& repr, IPAddress* ip); + static IPAddress forString(const std::string& repr) { + IPAddress ip; + if (!forString(repr, &ip)) return IPAddress(); + return ip; + } + + IPAddress() = default; + IPAddress(const IPAddress&) = default; + IPAddress(IPAddress&&) = default; + + explicit IPAddress(const in_addr& ipv4) + : mData({AF_INET, IPV4_ADDR_BITS, 0U, 0U, {.v4 = ipv4}}) {} + explicit IPAddress(const in6_addr& ipv6) + : mData({AF_INET6, IPV6_ADDR_BITS, 0U, 0U, {.v6 = ipv6}}) {} + IPAddress(const in6_addr& ipv6, uint32_t scope_id) + : mData({AF_INET6, + IPV6_ADDR_BITS, + 0U, + // Sanity check: scoped_ids only for link-local addresses. + usesScopedIds(ipv6) ? scope_id : 0U, + {.v6 = ipv6}}) {} + IPAddress(const IPAddress& ip, uint32_t scope_id) : IPAddress(ip) { + mData.scope_id = (family() == AF_INET6 && usesScopedIds(mData.ip.v6)) ? scope_id : 0U; + } + + IPAddress& operator=(const IPAddress&) = default; + IPAddress& operator=(IPAddress&&) = default; + + constexpr sa_family_t family() const noexcept { return mData.family; } + constexpr uint32_t scope_id() const noexcept { return mData.scope_id; } + + std::string toString() const noexcept; + + friend std::ostream& operator<<(std::ostream& os, const IPAddress& ip) { + os << ip.toString(); + return os; + } + friend bool operator==(const IPAddress& a, const IPAddress& b) { return (a.mData == b.mData); } + friend bool operator!=(const IPAddress& a, const IPAddress& b) { return (a.mData != b.mData); } + friend bool operator<(const IPAddress& a, const IPAddress& b) { return (a.mData < b.mData); } + friend bool operator>(const IPAddress& a, const IPAddress& b) { return (b.mData < a.mData); } + friend bool operator<=(const IPAddress& a, const IPAddress& b) { return (a < b) || (a == b); } + friend bool operator>=(const IPAddress& a, const IPAddress& b) { return (b < a) || (a == b); } + + private: + friend class IPPrefix; + friend class IPSockAddr; + + explicit IPAddress(const internal_::compact_ipdata& ipdata) : mData(ipdata) { + mData.port = 0U; + switch (mData.family) { + case AF_INET: + mData.cidrlen = IPV4_ADDR_BITS; + mData.scope_id = 0U; + break; + case AF_INET6: + mData.cidrlen = IPV6_ADDR_BITS; + if (usesScopedIds(ipdata.ip.v6)) mData.scope_id = ipdata.scope_id; + break; + default: + mData.cidrlen = 0U; + mData.scope_id = 0U; + break; + } + } + + internal_::compact_ipdata mData{}; +}; + +class IPPrefix { + public: + static bool forString(const std::string& repr, IPPrefix* prefix); + static IPPrefix forString(const std::string& repr) { + IPPrefix prefix; + if (!forString(repr, &prefix)) return IPPrefix(); + return prefix; + } + + IPPrefix() = default; + IPPrefix(const IPPrefix&) = default; + IPPrefix(IPPrefix&&) = default; + + explicit IPPrefix(const IPAddress& ip) : mData(ip.mData) {} + + // Truncate the IP address |ip| at length |length|. Lengths greater than + // the address-family-relevant maximum, along with negative values, are + // interpreted as if the address-family-relevant maximum had been given. + IPPrefix(const IPAddress& ip, int length); + + IPPrefix& operator=(const IPPrefix&) = default; + IPPrefix& operator=(IPPrefix&&) = default; + + constexpr sa_family_t family() const noexcept { return mData.family; } + IPAddress ip() const noexcept { return IPAddress(mData); } + in_addr addr4() const noexcept { return mData.ip.v4; } + in6_addr addr6() const noexcept { return mData.ip.v6; } + constexpr int length() const noexcept { return mData.cidrlen; } + + bool isUninitialized() const noexcept; + std::string toString() const noexcept; + + friend std::ostream& operator<<(std::ostream& os, const IPPrefix& prefix) { + os << prefix.toString(); + return os; + } + friend bool operator==(const IPPrefix& a, const IPPrefix& b) { return (a.mData == b.mData); } + friend bool operator!=(const IPPrefix& a, const IPPrefix& b) { return (a.mData != b.mData); } + friend bool operator<(const IPPrefix& a, const IPPrefix& b) { return (a.mData < b.mData); } + friend bool operator>(const IPPrefix& a, const IPPrefix& b) { return (b.mData < a.mData); } + friend bool operator<=(const IPPrefix& a, const IPPrefix& b) { return (a < b) || (a == b); } + friend bool operator>=(const IPPrefix& a, const IPPrefix& b) { return (b < a) || (a == b); } + + private: + internal_::compact_ipdata mData{}; +}; + +// An Internet socket address. +// +// Cannot represent other types of socket addresses (e.g. UNIX socket address, et cetera). +class IPSockAddr { + public: + // TODO: static forString + + static IPSockAddr toIPSockAddr(const std::string& repr, in_port_t port) { + return IPSockAddr(IPAddress::forString(repr), port); + } + static IPSockAddr toIPSockAddr(const sockaddr& sa) { + switch (sa.sa_family) { + case AF_INET: + return IPSockAddr(*reinterpret_cast(&sa)); + case AF_INET6: + return IPSockAddr(*reinterpret_cast(&sa)); + default: + return IPSockAddr(); + } + } + static IPSockAddr toIPSockAddr(const sockaddr_storage& ss) { + return toIPSockAddr(*reinterpret_cast(&ss)); + } + + IPSockAddr() = default; + IPSockAddr(const IPSockAddr&) = default; + IPSockAddr(IPSockAddr&&) = default; + + explicit IPSockAddr(const IPAddress& ip) : mData(ip.mData) {} + IPSockAddr(const IPAddress& ip, in_port_t port) : mData(ip.mData) { mData.port = port; } + explicit IPSockAddr(const sockaddr_in& ipv4sa) + : IPSockAddr(IPAddress(ipv4sa.sin_addr), ntohs(ipv4sa.sin_port)) {} + explicit IPSockAddr(const sockaddr_in6& ipv6sa) + : IPSockAddr(IPAddress(ipv6sa.sin6_addr, ipv6sa.sin6_scope_id), ntohs(ipv6sa.sin6_port)) {} + + IPSockAddr& operator=(const IPSockAddr&) = default; + IPSockAddr& operator=(IPSockAddr&&) = default; + + constexpr sa_family_t family() const noexcept { return mData.family; } + IPAddress ip() const noexcept { return IPAddress(mData); } + constexpr in_port_t port() const noexcept { return mData.port; } + + // Implicit conversion to sockaddr_storage. + operator sockaddr_storage() const noexcept { + sockaddr_storage ss; + ss.ss_family = mData.family; + switch (mData.family) { + case AF_INET: + reinterpret_cast(&ss)->sin_addr = mData.ip.v4; + reinterpret_cast(&ss)->sin_port = htons(mData.port); + break; + case AF_INET6: + reinterpret_cast(&ss)->sin6_addr = mData.ip.v6; + reinterpret_cast(&ss)->sin6_port = htons(mData.port); + reinterpret_cast(&ss)->sin6_scope_id = mData.scope_id; + break; + } + return ss; + } + + std::string toString() const noexcept; + + friend std::ostream& operator<<(std::ostream& os, const IPSockAddr& prefix) { + os << prefix.toString(); + return os; + } + friend bool operator==(const IPSockAddr& a, const IPSockAddr& b) { + return (a.mData == b.mData); + } + friend bool operator!=(const IPSockAddr& a, const IPSockAddr& b) { + return (a.mData != b.mData); + } + friend bool operator<(const IPSockAddr& a, const IPSockAddr& b) { return (a.mData < b.mData); } + friend bool operator>(const IPSockAddr& a, const IPSockAddr& b) { return (b.mData < a.mData); } + friend bool operator<=(const IPSockAddr& a, const IPSockAddr& b) { return (a < b) || (a == b); } + friend bool operator>=(const IPSockAddr& a, const IPSockAddr& b) { return (b < a) || (a == b); } + + private: + internal_::compact_ipdata mData{}; +}; + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Log.h b/staticlibs/netd/libnetdutils/include/netdutils/Log.h new file mode 100644 index 0000000000..77ae649424 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Log.h @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef NETUTILS_LOG_H +#define NETUTILS_LOG_H + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +namespace android { +namespace netdutils { + +class LogEntry { + public: + LogEntry() = default; + LogEntry(const LogEntry&) = default; + LogEntry(LogEntry&&) = default; + ~LogEntry() = default; + LogEntry& operator=(const LogEntry&) = default; + LogEntry& operator=(LogEntry&&) = default; + + std::string toString() const; + + /// + // Helper methods that make it easy to build up a LogEntry message. + // If performance becomes a factor the implementations could be inlined. + /// + LogEntry& message(const std::string& message); + + // For calling with __FUNCTION__. + LogEntry& function(const std::string& function_name); + // For calling with __PRETTY_FUNCTION__. + LogEntry& prettyFunction(const std::string& pretty_function); + + // Convenience methods for each of the common types of function arguments. + LogEntry& arg(const std::string& val); + // Intended for binary buffers, formats as hex + LogEntry& arg(const std::vector& val); + LogEntry& arg(const std::vector& val); + LogEntry& arg(const std::vector& val); + template >> + LogEntry& arg(IntT val) { + mArgs.push_back(std::to_string(val)); + return *this; + } + // Not using a plain overload here to avoid the implicit conversion from + // any pointer to bool, which causes string literals to print as 'true'. + template <> + LogEntry& arg<>(bool val); + + template + LogEntry& args(const Args&... a) { + // Cleverness ahead: we throw away the initializer_list filled with + // zeroes, all we care about is calling arg() for each argument. + (void) std::initializer_list{(arg(a), 0)...}; + return *this; + } + + // Some things can return more than one value, or have multiple output + // parameters, so each of these adds to the mReturns vector. + LogEntry& returns(const std::string& rval); + LogEntry& returns(const Status& status); + LogEntry& returns(bool rval); + template + LogEntry& returns(T val) { + mReturns.push_back(std::to_string(val)); + return *this; + } + + LogEntry& withUid(uid_t uid); + + // Append the duration computed since the creation of this instance. + LogEntry& withAutomaticDuration(); + // Append the string-ified duration computed by some other means. + LogEntry& withDuration(const std::string& duration); + + private: + std::chrono::steady_clock::time_point mStart = std::chrono::steady_clock::now(); + std::string mMsg{}; + std::string mFunc{}; + std::vector mArgs{}; + std::vector mReturns{}; + std::string mUid{}; + std::string mDuration{}; +}; + +class Log { + public: + Log() = delete; + Log(const std::string& tag) : Log(tag, MAX_ENTRIES) {} + Log(const std::string& tag, size_t maxEntries) : mTag(tag), mMaxEntries(maxEntries) {} + Log(const Log&) = delete; + Log(Log&&) = delete; + ~Log(); + Log& operator=(const Log&) = delete; + Log& operator=(Log&&) = delete; + + LogEntry newEntry() const { return LogEntry(); } + + // Record a log entry in internal storage only. + void log(const std::string& entry) { record(Level::LOG, entry); } + template + void log(const char entry[n]) { log(std::string(entry)); } + void log(const LogEntry& entry) { log(entry.toString()); } + void log(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { + using ::android::base::StringAppendV; + std::string result; + va_list ap; + va_start(ap, fmt); + StringAppendV(&result, fmt, ap); + va_end(ap); + log(result); + } + + // Record a log entry in internal storage and to ALOGI as well. + void info(const std::string& entry) { record(Level::INFO, entry); } + template + void info(const char entry[n]) { info(std::string(entry)); } + void info(const LogEntry& entry) { info(entry.toString()); } + void info(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { + using ::android::base::StringAppendV; + std::string result; + va_list ap; + va_start(ap, fmt); + StringAppendV(&result, fmt, ap); + va_end(ap); + info(result); + } + + // Record a log entry in internal storage and to ALOGW as well. + void warn(const std::string& entry) { record(Level::WARN, entry); } + template + void warn(const char entry[n]) { warn(std::string(entry)); } + void warn(const LogEntry& entry) { warn(entry.toString()); } + void warn(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { + using ::android::base::StringAppendV; + std::string result; + va_list ap; + va_start(ap, fmt); + StringAppendV(&result, fmt, ap); + va_end(ap); + warn(result); + } + + // Record a log entry in internal storage and to ALOGE as well. + void error(const std::string& entry) { record(Level::ERROR, entry); } + template + void error(const char entry[n]) { error(std::string(entry)); } + void error(const LogEntry& entry) { error(entry.toString()); } + void error(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { + using ::android::base::StringAppendV; + std::string result; + va_list ap; + va_start(ap, fmt); + StringAppendV(&result, fmt, ap); + va_end(ap); + error(result); + } + + // Iterates over every entry in the log in chronological order. Operates + // on a copy of the log entries, and so perEntryFn may itself call one of + // the logging functions if needed. + void forEachEntry(const std::function& perEntryFn) const; + + private: + static constexpr const size_t MAX_ENTRIES = 750U; + const std::string mTag; + const size_t mMaxEntries; + + // The LOG level adds an entry to mEntries but does not output the message + // to the system log. All other levels append to mEntries and output to the + // the system log. + enum class Level { + LOG, + INFO, + WARN, + ERROR, + }; + + void record(Level lvl, const std::string& entry); + + mutable std::shared_mutex mLock; + std::deque mEntries; // GUARDED_BY(mLock), when supported +}; + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_LOG_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Math.h b/staticlibs/netd/libnetdutils/include/netdutils/Math.h new file mode 100644 index 0000000000..c41fbf5882 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Math.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_MATH_H +#define NETUTILS_MATH_H + +#include +#include + +namespace android { +namespace netdutils { + +template +inline constexpr const T mask(const int shift) { + return (1 << shift) - 1; +} + +// Align x up to the nearest integer multiple of 2^shift +template +inline constexpr const T align(const T& x, const int shift) { + return (x + mask(shift)) & ~mask(shift); +} + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_MATH_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/MemBlock.h b/staticlibs/netd/libnetdutils/include/netdutils/MemBlock.h new file mode 100644 index 0000000000..fd4d612d38 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/MemBlock.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef NETUTILS_MEMBLOCK_H +#define NETUTILS_MEMBLOCK_H + +#include +#include "netdutils/Slice.h" + +namespace android { +namespace netdutils { + +// A class to encapsulate self-deleting byte arrays while preserving access +// to the underlying length (without the length being part of the type, e.g. +// std::array<>). By design, the only interface to the underlying bytes is +// via Slice, to encourage safer memory access usage. +// +// No thread-safety guarantees whatsoever. +class MemBlock { + public: + MemBlock() : MemBlock(0U) {} + explicit MemBlock(size_t len) + : mData((len > 0U) ? new uint8_t[len]{} : nullptr), + mLen(len) {} + // Allocate memory of size src.size() and copy src into this MemBlock. + explicit MemBlock(Slice src) : MemBlock(src.size()) { + copy(get(), src); + } + + // No copy construction or assignment. + MemBlock(const MemBlock&) = delete; + MemBlock& operator=(const MemBlock&) = delete; + + // Move construction and assignment are okay. + MemBlock(MemBlock&&) = default; + MemBlock& operator=(MemBlock&&) = default; + + // Even though this method is const, the memory wrapped by the + // returned Slice is mutable. + Slice get() const noexcept { return Slice(mData.get(), mLen); } + + // Implicit cast to Slice. + // NOLINTNEXTLINE(google-explicit-constructor) + operator const Slice() const noexcept { return get(); } + + private: + std::unique_ptr mData; + size_t mLen; +}; + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_MEMBLOCK_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Misc.h b/staticlibs/netd/libnetdutils/include/netdutils/Misc.h new file mode 100644 index 0000000000..d344f81fc3 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Misc.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_MISC_H +#define NETUTILS_MISC_H + +#include + +namespace android { +namespace netdutils { + +// Lookup key in map, returing a default value if key is not found +template +inline const V& findWithDefault(const std::map& map, const U& key, const V& dflt) { + auto it = map.find(key); + return (it == map.end()) ? dflt : it->second; +} + +// Movable, copiable, scoped lambda (or std::function) runner. Useful +// for running arbitrary cleanup or logging code when exiting a scope. +// +// Compare to defer in golang. +template +class Cleanup { + public: + Cleanup() = delete; + explicit Cleanup(FnT fn) : mFn(fn) {} + ~Cleanup() { if (!mReleased) mFn(); } + + void release() { mReleased = true; } + + private: + bool mReleased{false}; + FnT mFn; +}; + +// Helper to make a new Cleanup. Avoids complex or impossible syntax +// when wrapping lambdas. +// +// Usage: +// auto cleanup = makeCleanup([](){ your_code_here; }); +template +Cleanup makeCleanup(FnT fn) { + return Cleanup(fn); +} + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_MISC_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/MockSyscalls.h b/staticlibs/netd/libnetdutils/include/netdutils/MockSyscalls.h new file mode 100644 index 0000000000..f57b55ca9d --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/MockSyscalls.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_MOCK_SYSCALLS_H +#define NETUTILS_MOCK_SYSCALLS_H + +#include +#include +#include + +#include +#include + +#include "netdutils/Syscalls.h" + +namespace android { +namespace netdutils { + +class MockSyscalls : public Syscalls { + public: + virtual ~MockSyscalls() = default; + // Use Return(ByMove(...)) to deal with movable return types. + MOCK_CONST_METHOD3(open, + StatusOr(const std::string& pathname, int flags, mode_t mode)); + MOCK_CONST_METHOD3(socket, StatusOr(int domain, int type, int protocol)); + MOCK_CONST_METHOD3(getsockname, Status(Fd sock, sockaddr* addr, socklen_t* addrlen)); + MOCK_CONST_METHOD5(getsockopt, Status(Fd sock, int level, int optname, void* optval, + socklen_t *optlen)); + MOCK_CONST_METHOD5(setsockopt, Status(Fd sock, int level, int optname, const void* optval, + socklen_t optlen)); + + MOCK_CONST_METHOD3(bind, Status(Fd sock, const sockaddr* addr, socklen_t addrlen)); + MOCK_CONST_METHOD3(connect, Status(Fd sock, const sockaddr* addr, socklen_t addrlen)); + MOCK_CONST_METHOD3(ioctl, StatusOr(Fd sock, unsigned long request, ifreq* ifr)); + + // Use Return(ByMove(...)) to deal with movable return types. + MOCK_CONST_METHOD2(eventfd, StatusOr(unsigned int initval, int flags)); + MOCK_CONST_METHOD3(ppoll, StatusOr(pollfd* fds, nfds_t nfds, double timeout)); + + MOCK_CONST_METHOD2(writev, StatusOr(Fd fd, const std::vector& iov)); + MOCK_CONST_METHOD2(write, StatusOr(Fd fd, const Slice buf)); + MOCK_CONST_METHOD2(read, StatusOr(Fd fd, const Slice buf)); + MOCK_CONST_METHOD5(sendto, StatusOr(Fd sock, const Slice buf, int flags, + const sockaddr* dst, socklen_t dstlen)); + MOCK_CONST_METHOD5(recvfrom, StatusOr(Fd sock, const Slice dst, int flags, sockaddr* src, + socklen_t* srclen)); + MOCK_CONST_METHOD2(shutdown, Status(Fd fd, int how)); + MOCK_CONST_METHOD1(close, Status(Fd fd)); + + MOCK_CONST_METHOD2(fopen, + StatusOr(const std::string& path, const std::string& mode)); + MOCK_CONST_METHOD3(vfprintf, StatusOr(FILE* file, const char* format, va_list ap)); + MOCK_CONST_METHOD3(vfscanf, StatusOr(FILE* file, const char* format, va_list ap)); + MOCK_CONST_METHOD1(fclose, Status(FILE* file)); + MOCK_CONST_METHOD0(fork, StatusOr()); +}; + +// For the lifetime of this mock, replace the contents of sSyscalls +// with a pointer to this mock. Behavior is undefined if multiple +// ScopedMockSyscalls instances exist concurrently. +class ScopedMockSyscalls : public MockSyscalls { + public: + ScopedMockSyscalls() : mOld(sSyscalls.swap(*this)) { assert((mRefcount++) == 1); } + virtual ~ScopedMockSyscalls() { + sSyscalls.swap(mOld); + assert((mRefcount--) == 0); + } + + private: + std::atomic mRefcount{0}; + Syscalls& mOld; +}; + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_MOCK_SYSCALLS_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Netfilter.h b/staticlibs/netd/libnetdutils/include/netdutils/Netfilter.h new file mode 100644 index 0000000000..22736f192b --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Netfilter.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_NETFILTER_H +#define NETUTILS_NETFILTER_H + +#include + +#include +#include +#include + +std::ostream& operator<<(std::ostream& os, const nfgenmsg& msg); + +#endif /* NETUTILS_NETFILTER_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Netlink.h b/staticlibs/netd/libnetdutils/include/netdutils/Netlink.h new file mode 100644 index 0000000000..ee5183ab47 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Netlink.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_NETLINK_H +#define NETUTILS_NETLINK_H + +#include +#include +#include + +#include "netdutils/Slice.h" + +namespace android { +namespace netdutils { + +// Invoke onMsg once for each netlink message in buf. onMsg will be +// invoked with an aligned and deserialized header along with a Slice +// containing the message payload. +// +// Assume that the first message begins at offset zero within buf. +void forEachNetlinkMessage(const Slice buf, + const std::function& onMsg); + +// Invoke onAttr once for each netlink attribute in buf. onAttr will be +// invoked with an aligned and deserialized header along with a Slice +// containing the attribute payload. +// +// Assume that the first attribute begins at offset zero within buf. +void forEachNetlinkAttribute(const Slice buf, + const std::function& onAttr); + +} // namespace netdutils +} // namespace android + +bool operator==(const sockaddr_nl& lhs, const sockaddr_nl& rhs); +bool operator!=(const sockaddr_nl& lhs, const sockaddr_nl& rhs); + +std::ostream& operator<<(std::ostream& os, const nlmsghdr& hdr); +std::ostream& operator<<(std::ostream& os, const nlattr& attr); +std::ostream& operator<<(std::ostream& os, const sockaddr_nl& addr); + +#endif /* NETUTILS_NETLINK_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/NetworkConstants.h b/staticlibs/netd/libnetdutils/include/netdutils/NetworkConstants.h new file mode 100644 index 0000000000..dead9a17bd --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/NetworkConstants.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 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. + */ + +#pragma once + +namespace android { +namespace netdutils { + +// See also NetworkConstants.java in frameworks/base. +constexpr int IPV4_ADDR_LEN = 4; +constexpr int IPV4_ADDR_BITS = 32; +constexpr int IPV6_ADDR_LEN = 16; +constexpr int IPV6_ADDR_BITS = 128; + +// Referred from SHA256_DIGEST_LENGTH in boringssl +constexpr size_t SHA256_SIZE = 32; + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/include/netdutils/ResponseCode.h b/staticlibs/netd/libnetdutils/include/netdutils/ResponseCode.h new file mode 100644 index 0000000000..c170684cf3 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/ResponseCode.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef NETDUTILS_RESPONSECODE_H +#define NETDUTILS_RESPONSECODE_H + +namespace android { +namespace netdutils { + +class ResponseCode { + // Keep in sync with + // frameworks/base/services/java/com/android/server/NetworkManagementService.java + public: + // 100 series - Requestion action was initiated; expect another reply + // before proceeding with a new command. + // clang-format off + static constexpr int ActionInitiated = 100; + static constexpr int InterfaceListResult = 110; + static constexpr int TetherInterfaceListResult = 111; + static constexpr int TetherDnsFwdTgtListResult = 112; + static constexpr int TtyListResult = 113; + static constexpr int TetheringStatsListResult = 114; + static constexpr int TetherDnsFwdNetIdResult = 115; + + // 200 series - Requested action has been successfully completed + static constexpr int CommandOkay = 200; + static constexpr int TetherStatusResult = 210; + static constexpr int IpFwdStatusResult = 211; + static constexpr int InterfaceGetCfgResult = 213; + // Formerly: int SoftapStatusResult = 214; + static constexpr int UsbRNDISStatusResult = 215; + static constexpr int InterfaceRxCounterResult = 216; + static constexpr int InterfaceTxCounterResult = 217; + static constexpr int InterfaceRxThrottleResult = 218; + static constexpr int InterfaceTxThrottleResult = 219; + static constexpr int QuotaCounterResult = 220; + static constexpr int TetheringStatsResult = 221; + // NOTE: keep synced with bionic/libc/dns/net/gethnamaddr.c + static constexpr int DnsProxyQueryResult = 222; + static constexpr int ClatdStatusResult = 223; + + // 400 series - The command was accepted but the requested action + // did not take place. + static constexpr int OperationFailed = 400; + static constexpr int DnsProxyOperationFailed = 401; + static constexpr int ServiceStartFailed = 402; + static constexpr int ServiceStopFailed = 403; + + // 500 series - The command was not accepted and the requested + // action did not take place. + static constexpr int CommandSyntaxError = 500; + static constexpr int CommandParameterError = 501; + + // 600 series - Unsolicited broadcasts + static constexpr int InterfaceChange = 600; + static constexpr int BandwidthControl = 601; + static constexpr int ServiceDiscoveryFailed = 602; + static constexpr int ServiceDiscoveryServiceAdded = 603; + static constexpr int ServiceDiscoveryServiceRemoved = 604; + static constexpr int ServiceRegistrationFailed = 605; + static constexpr int ServiceRegistrationSucceeded = 606; + static constexpr int ServiceResolveFailed = 607; + static constexpr int ServiceResolveSuccess = 608; + static constexpr int ServiceSetHostnameFailed = 609; + static constexpr int ServiceSetHostnameSuccess = 610; + static constexpr int ServiceGetAddrInfoFailed = 611; + static constexpr int ServiceGetAddrInfoSuccess = 612; + static constexpr int InterfaceClassActivity = 613; + static constexpr int InterfaceAddressChange = 614; + static constexpr int InterfaceDnsInfo = 615; + static constexpr int RouteChange = 616; + static constexpr int StrictCleartext = 617; + // clang-format on +}; + +} // namespace netdutils +} // namespace android + +#endif // NETDUTILS_RESPONSECODE_H diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Slice.h b/staticlibs/netd/libnetdutils/include/netdutils/Slice.h new file mode 100644 index 0000000000..717fbd1fbb --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Slice.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_SLICE_H +#define NETUTILS_SLICE_H + +#include +#include +#include +#include +#include +#include + +namespace android { +namespace netdutils { + +// Immutable wrapper for a linear region of unowned bytes. +// Slice represents memory as a half-closed interval [base, limit). +// +// Note that without manually invoking the Slice() constructor, it is +// impossible to increase the size of a slice. This guarantees that +// applications that properly use the slice API will never access +// memory outside of a slice. +// +// Note that const Slice still wraps mutable memory, however copy +// assignment and move assignment to slice are disabled. +class Slice { + public: + Slice() = default; + + // Create a slice beginning at base and continuing to but not including limit + Slice(void* base, void* limit) : mBase(toUint8(base)), mLimit(toUint8(limit)) {} + + // Create a slice beginning at base and continuing for size bytes + Slice(void* base, size_t size) : Slice(base, toUint8(base) + size) {} + + // Return the address of the first byte in this slice + uint8_t* base() const { return mBase; } + + // Return the address of the first byte following this slice + uint8_t* limit() const { return mLimit; } + + // Return the size of this slice in bytes + size_t size() const { return limit() - base(); } + + // Return true if size() == 0 + bool empty() const { return base() == limit(); } + + private: + static uint8_t* toUint8(void* ptr) { return reinterpret_cast(ptr); } + + uint8_t* mBase = nullptr; + uint8_t* mLimit = nullptr; +}; + +// Return slice representation of ref which must be a POD type +template +inline const Slice makeSlice(const T& ref) { + static_assert(std::is_pod::value, "value must be a POD type"); + static_assert(!std::is_pointer::value, "value must not be a pointer type"); + return {const_cast(&ref), sizeof(ref)}; +} + +// Return slice representation of string data() +inline const Slice makeSlice(const std::string& s) { + using ValueT = std::string::value_type; + return {const_cast(s.data()), s.size() * sizeof(ValueT)}; +} + +// Return slice representation of vector data() +template +inline const Slice makeSlice(const std::vector& v) { + return {const_cast(v.data()), v.size() * sizeof(T)}; +} + +// Return slice representation of array data() +template +inline const Slice makeSlice(const std::array& a) { + return {const_cast(a.data()), a.size() * sizeof(U)}; +} + +// Return prefix and suffix of Slice s ending and starting at position cut +inline std::pair split(const Slice s, size_t cut) { + const size_t tmp = std::min(cut, s.size()); + return {{s.base(), s.base() + tmp}, {s.base() + tmp, s.limit()}}; +} + +// Return prefix of Slice s ending at position cut +inline const Slice take(const Slice s, size_t cut) { + return std::get<0>(split(s, cut)); +} + +// Return suffix of Slice s starting at position cut +inline const Slice drop(const Slice s, size_t cut) { + return std::get<1>(split(s, cut)); +} + +// Copy from src into dst. Bytes copied is the lesser of dst.size() and src.size() +inline size_t copy(const Slice dst, const Slice src) { + const auto min = std::min(dst.size(), src.size()); + memcpy(dst.base(), src.base(), min); + return min; +} + +// Base case for variadic extract below +template +inline size_t extract(const Slice src, Head& head) { + return copy(makeSlice(head), src); +} + +// Copy from src into one or more pointers to POD data. If src.size() +// is less than the sum of all data pointers a suffix of data will be +// left unmodified. Return the number of bytes copied. +template +inline size_t extract(const Slice src, Head& head, Tail&... tail) { + const auto extracted = extract(src, head); + return extracted + extract(drop(src, extracted), tail...); +} + +// Return a string containing a copy of the contents of s +std::string toString(const Slice s); + +// Return a string containing a hexadecimal representation of the contents of s. +// This function inserts a newline into its output every wrap bytes. +std::string toHex(const Slice s, int wrap = INT_MAX); + +inline bool operator==(const Slice& lhs, const Slice& rhs) { + return (lhs.base() == rhs.base()) && (lhs.limit() == rhs.limit()); +} + +inline bool operator!=(const Slice& lhs, const Slice& rhs) { + return !(lhs == rhs); +} + +std::ostream& operator<<(std::ostream& os, const Slice& slice); + +// Return suffix of Slice s starting at the first match of byte c. If no matched +// byte, return an empty Slice. +inline const Slice findFirstMatching(const Slice s, uint8_t c) { + uint8_t* match = (uint8_t*)memchr(s.base(), c, s.size()); + if (!match) return Slice(); + return drop(s, match - s.base()); +} + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_SLICE_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Socket.h b/staticlibs/netd/libnetdutils/include/netdutils/Socket.h new file mode 100644 index 0000000000..e5aaab9c64 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Socket.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETDUTILS_SOCKET_H +#define NETDUTILS_SOCKET_H + +#include +#include +#include + +#include "netdutils/StatusOr.h" + +namespace android { +namespace netdutils { + +inline sockaddr* asSockaddrPtr(void* addr) { + return reinterpret_cast(addr); +} + +inline const sockaddr* asSockaddrPtr(const void* addr) { + return reinterpret_cast(addr); +} + +// Return a string representation of addr or Status if there was a +// failure during conversion. +StatusOr toString(const in6_addr& addr); + +} // namespace netdutils +} // namespace android + +#endif /* NETDUTILS_SOCKET_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/SocketOption.h b/staticlibs/netd/libnetdutils/include/netdutils/SocketOption.h new file mode 100644 index 0000000000..3b0aab75d4 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/SocketOption.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef NETDUTILS_SOCKETOPTION_H +#define NETDUTILS_SOCKETOPTION_H + +#include +#include +#include + +#include "netdutils/Fd.h" +#include "netdutils/Status.h" + +namespace android { +namespace netdutils { + +// Turn on simple "boolean" socket options. +// +// This is simple wrapper for options that are enabled via code of the form: +// +// int on = 1; +// setsockopt(..., &on, sizeof(on)); +Status enableSockopt(Fd sock, int level, int optname); + +// Turn on TCP keepalives, and set keepalive parameters for this socket. +// +// A parameter value of zero does not set that parameter. +// +// Typical system defaults are: +// +// idleTime (in seconds) +// $ cat /proc/sys/net/ipv4/tcp_keepalive_time +// 7200 +// +// numProbes +// $ cat /proc/sys/net/ipv4/tcp_keepalive_probes +// 9 +// +// probeInterval (in seconds) +// $ cat /proc/sys/net/ipv4/tcp_keepalive_intvl +// 75 +Status enableTcpKeepAlives(Fd sock, unsigned idleTime, unsigned numProbes, unsigned probeInterval); + +} // namespace netdutils +} // namespace android + +#endif /* NETDUTILS_SOCKETOPTION_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Status.h b/staticlibs/netd/libnetdutils/include/netdutils/Status.h new file mode 100644 index 0000000000..bc347d5e9e --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Status.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_STATUS_H +#define NETUTILS_STATUS_H + +#include +#include +#include + +#include + +namespace android { +namespace netdutils { + +// Simple status implementation suitable for use on the stack in low +// or moderate performance code. This can definitely be improved but +// for now short string optimization is expected to keep the common +// success case fast. +// +// Status is implicitly movable via the default noexcept move constructor +// and noexcept move-assignment operator. +class [[nodiscard]] Status { + public: + Status() = default; + explicit Status(int code) : mCode(code) {} + + // Constructs an error Status, |code| must be non-zero. + Status(int code, std::string msg) : mCode(code), mMsg(std::move(msg)) { assert(!ok()); } + + Status(android::base::Result result) + : mCode(result.ok() ? 0 : result.error().code()), + mMsg(result.ok() ? "" : result.error().message()) {} + + int code() const { return mCode; } + + bool ok() const { return code() == 0; } + + const std::string& msg() const { return mMsg; } + + // Explicitly ignores the Status without triggering [[nodiscard]] errors. + void ignoreError() const {} + + bool operator==(const Status& other) const { return code() == other.code(); } + bool operator!=(const Status& other) const { return !(*this == other); } + + private: + int mCode = 0; + std::string mMsg; +}; + +namespace status { + +const Status ok{0}; +// EOF is not part of errno space, we'll place it far above the +// highest existing value. +const Status eof{0x10001, "end of file"}; +const Status undefined{std::numeric_limits::max(), "undefined"}; + +} // namespace status + +// Return true if status is "OK". This is sometimes preferable to +// status.ok() when we want to check the state of Status-like objects +// that implicitly cast to Status. +inline bool isOk(const Status& status) { + return status.ok(); +} + +// For use only in tests. Used for both Status and Status-like objects. See also isOk(). +#define EXPECT_OK(status) EXPECT_TRUE(isOk(status)) +#define ASSERT_OK(status) ASSERT_TRUE(isOk(status)) + +// Documents that status is expected to be ok. This function may log +// (or assert when running in debug mode) if status has an unexpected value. +inline void expectOk(const Status& /*status*/) { + // TODO: put something here, for now this function serves solely as documentation. +} + +// Convert POSIX errno to a Status object. +// If Status is extended to have more features, this mapping may +// become more complex. +Status statusFromErrno(int err, const std::string& msg); + +// Helper that checks Status-like object (notably StatusOr) against a +// value in the errno space. +bool equalToErrno(const Status& status, int err); + +// Helper that converts Status-like object (notably StatusOr) to a +// message. +std::string toString(const Status& status); + +std::ostream& operator<<(std::ostream& os, const Status& s); + +// Evaluate 'stmt' to a Status object and if it results in an error, return that +// error. Use 'tmp' as a variable name to avoid shadowing any variables named +// tmp. +#define RETURN_IF_NOT_OK_IMPL(tmp, stmt) \ + do { \ + ::android::netdutils::Status tmp = (stmt); \ + if (!isOk(tmp)) { \ + return tmp; \ + } \ + } while (false) + +// Create a unique variable name to avoid shadowing local variables. +#define RETURN_IF_NOT_OK_CONCAT(line, stmt) RETURN_IF_NOT_OK_IMPL(__CONCAT(_status_, line), stmt) + +// Macro to allow exception-like handling of error return values. +// +// If the evaluation of stmt results in an error, return that error +// from current function. +// +// Example usage: +// Status bar() { ... } +// +// RETURN_IF_NOT_OK(status); +// RETURN_IF_NOT_OK(bar()); +#define RETURN_IF_NOT_OK(stmt) RETURN_IF_NOT_OK_CONCAT(__LINE__, stmt) + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_STATUS_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/StatusOr.h b/staticlibs/netd/libnetdutils/include/netdutils/StatusOr.h new file mode 100644 index 0000000000..c7aa4e4ae0 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/StatusOr.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_STATUSOR_H +#define NETUTILS_STATUSOR_H + +#include +#include "netdutils/Status.h" + +namespace android { +namespace netdutils { + +// Wrapper around a combination of Status and application value type. +// T may be any copyable or movable type. +template +class [[nodiscard]] StatusOr { + public: + // Constructs a new StatusOr with status::undefined status. + // This is marked 'explicit' to try to catch cases like 'return {};', + // where people think StatusOr> will be initialized + // with an empty vector, instead of a status::undefined. + explicit StatusOr() = default; + + // Implicit copy constructor and construction from T. + // NOLINTNEXTLINE(google-explicit-constructor) + StatusOr(Status status) : mStatus(std::move(status)) { assert(!isOk(mStatus)); } + + // Implicit construction from T. It is convenient and sensible to be able + // to do 'return T()' when the return type is StatusOr. + // NOLINTNEXTLINE(google-explicit-constructor) + StatusOr(const T& value) : mStatus(status::ok), mValue(value) {} + // NOLINTNEXTLINE(google-explicit-constructor) + StatusOr(T&& value) : mStatus(status::ok), mValue(std::move(value)) {} + + // Move constructor ok (if T supports move) + StatusOr(StatusOr&&) noexcept = default; + // Move assignment ok (if T supports move) + StatusOr& operator=(StatusOr&&) noexcept = default; + // Copy constructor ok (if T supports copy) + StatusOr(const StatusOr&) = default; + // Copy assignment ok (if T supports copy) + StatusOr& operator=(const StatusOr&) = default; + + // Returns a const reference to wrapped type. + // It is an error to call value() when !isOk(status()) + const T& value() const & { return mValue; } + const T&& value() const && { return mValue; } + + // Returns an rvalue reference to wrapped type + // It is an error to call value() when !isOk(status()) + // + // If T is expensive to copy but supports efficient move, it can be moved + // out of a StatusOr as follows: + // T value = std::move(statusor).value(); + T& value() & { return mValue; } + T&& value() && { return mValue; } + + // Returns the Status object assigned at construction time. + const Status status() const { return mStatus; } + + // Explicitly ignores the Status without triggering [[nodiscard]] errors. + void ignoreError() const {} + + // Implicit cast to Status. + // NOLINTNEXTLINE(google-explicit-constructor) + operator Status() const { return status(); } + + private: + Status mStatus = status::undefined; + T mValue; +}; + +template +inline std::ostream& operator<<(std::ostream& os, const StatusOr& s) { + return os << "StatusOr[status: " << s.status() << "]"; +} + +#define ASSIGN_OR_RETURN_IMPL(tmp, lhs, stmt) \ + auto tmp = (stmt); \ + RETURN_IF_NOT_OK(tmp); \ + lhs = std::move(tmp.value()); + +#define ASSIGN_OR_RETURN_CONCAT(line, lhs, stmt) \ + ASSIGN_OR_RETURN_IMPL(__CONCAT(_status_or_, line), lhs, stmt) + +// Macro to allow exception-like handling of error return values. +// +// If the evaluation of stmt results in an error, return that error +// from the current function. Otherwise, assign the result to lhs. +// +// This macro supports both move and copy assignment operators. lhs +// may be either a new local variable or an existing non-const +// variable accessible in the current scope. +// +// Example usage: +// StatusOr foo() { ... } +// +// ASSIGN_OR_RETURN(auto myVar, foo()); +// ASSIGN_OR_RETURN(myExistingVar, foo()); +// ASSIGN_OR_RETURN(myMemberVar, foo()); +#define ASSIGN_OR_RETURN(lhs, stmt) ASSIGN_OR_RETURN_CONCAT(__LINE__, lhs, stmt) + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_STATUSOR_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Stopwatch.h b/staticlibs/netd/libnetdutils/include/netdutils/Stopwatch.h new file mode 100644 index 0000000000..e7b4326455 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Stopwatch.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef NETDUTILS_STOPWATCH_H +#define NETDUTILS_STOPWATCH_H + +#include + +namespace android { +namespace netdutils { + +class Stopwatch { + private: + using clock = std::chrono::steady_clock; + using time_point = std::chrono::time_point; + + public: + Stopwatch() : mStart(clock::now()) {} + virtual ~Stopwatch() = default; + + int64_t timeTakenUs() const { return getElapsedUs(clock::now()); } + int64_t getTimeAndResetUs() { + const auto& now = clock::now(); + int64_t elapsed = getElapsedUs(now); + mStart = now; + return elapsed; + } + + private: + time_point mStart; + + int64_t getElapsedUs(const time_point& now) const { + return (std::chrono::duration_cast(now - mStart)).count(); + } +}; + +} // namespace netdutils +} // namespace android + +#endif // NETDUTILS_STOPWATCH_H diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Syscalls.h b/staticlibs/netd/libnetdutils/include/netdutils/Syscalls.h new file mode 100644 index 0000000000..36fcd85328 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Syscalls.h @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETDUTILS_SYSCALLS_H +#define NETDUTILS_SYSCALLS_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "netdutils/Fd.h" +#include "netdutils/Slice.h" +#include "netdutils/Socket.h" +#include "netdutils/Status.h" +#include "netdutils/StatusOr.h" +#include "netdutils/UniqueFd.h" +#include "netdutils/UniqueFile.h" + +namespace android { +namespace netdutils { + +class Syscalls { + public: + virtual ~Syscalls() = default; + + virtual StatusOr open(const std::string& pathname, int flags, + mode_t mode = 0) const = 0; + + virtual StatusOr socket(int domain, int type, int protocol) const = 0; + + virtual Status getsockname(Fd sock, sockaddr* addr, socklen_t* addrlen) const = 0; + + virtual Status getsockopt(Fd sock, int level, int optname, void *optval, + socklen_t *optlen) const = 0; + + virtual Status setsockopt(Fd sock, int level, int optname, const void* optval, + socklen_t optlen) const = 0; + + virtual Status bind(Fd sock, const sockaddr* addr, socklen_t addrlen) const = 0; + + virtual Status connect(Fd sock, const sockaddr* addr, socklen_t addrlen) const = 0; + + virtual StatusOr ioctl(Fd sock, unsigned long request, ifreq* ifr) const = 0; + + virtual StatusOr eventfd(unsigned int initval, int flags) const = 0; + + virtual StatusOr ppoll(pollfd* fds, nfds_t nfds, double timeout) const = 0; + + virtual StatusOr writev(Fd fd, const std::vector& iov) const = 0; + + virtual StatusOr write(Fd fd, const Slice buf) const = 0; + + virtual StatusOr read(Fd fd, const Slice buf) const = 0; + + virtual StatusOr sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst, + socklen_t dstlen) const = 0; + + virtual StatusOr recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src, + socklen_t* srclen) const = 0; + + virtual Status shutdown(Fd fd, int how) const = 0; + + virtual Status close(Fd fd) const = 0; + + virtual StatusOr fopen(const std::string& path, const std::string& mode) const = 0; + + virtual StatusOr vfprintf(FILE* file, const char* format, va_list ap) const = 0; + + virtual StatusOr vfscanf(FILE* file, const char* format, va_list ap) const = 0; + + virtual Status fclose(FILE* file) const = 0; + + virtual StatusOr fork() const = 0; + + // va_args helpers + // va_start doesn't work when the preceding argument is a reference + // type so we're forced to use const char*. + StatusOr fprintf(FILE* file, const char* format, ...) const { + va_list ap; + va_start(ap, format); + auto result = vfprintf(file, format, ap); + va_end(ap); + return result; + } + + // va_start doesn't work when the preceding argument is a reference + // type so we're forced to use const char*. + StatusOr fscanf(FILE* file, const char* format, ...) const { + va_list ap; + va_start(ap, format); + auto result = vfscanf(file, format, ap); + va_end(ap); + return result; + } + + // Templated helpers that forward directly to methods declared above + template + StatusOr getsockname(Fd sock) const { + SockaddrT addr = {}; + socklen_t addrlen = sizeof(addr); + RETURN_IF_NOT_OK(getsockname(sock, asSockaddrPtr(&addr), &addrlen)); + return addr; + } + + template + Status getsockopt(Fd sock, int level, int optname, void* optval, socklen_t* optlen) const { + return getsockopt(sock, level, optname, optval, optlen); + } + + template + Status setsockopt(Fd sock, int level, int optname, const SockoptT& opt) const { + return setsockopt(sock, level, optname, &opt, sizeof(opt)); + } + + template + Status bind(Fd sock, const SockaddrT& addr) const { + return bind(sock, asSockaddrPtr(&addr), sizeof(addr)); + } + + template + Status connect(Fd sock, const SockaddrT& addr) const { + return connect(sock, asSockaddrPtr(&addr), sizeof(addr)); + } + + template + StatusOr> ppoll(const std::array& fds, uint16_t events, + double timeout) const { + std::array tmp; + for (size_t i = 0; i < size; ++i) { + tmp[i].fd = fds[i].get(); + tmp[i].events = events; + tmp[i].revents = 0; + } + RETURN_IF_NOT_OK(ppoll(tmp.data(), tmp.size(), timeout).status()); + std::array out; + for (size_t i = 0; i < size; ++i) { + out[i] = tmp[i].revents; + } + return out; + } + + template + StatusOr sendto(Fd sock, const Slice buf, int flags, const SockaddrT& dst) const { + return sendto(sock, buf, flags, asSockaddrPtr(&dst), sizeof(dst)); + } + + // Ignore src sockaddr + StatusOr recvfrom(Fd sock, const Slice dst, int flags) const { + return recvfrom(sock, dst, flags, nullptr, nullptr); + } + + template + StatusOr> recvfrom(Fd sock, const Slice dst, int flags) const { + SockaddrT addr = {}; + socklen_t addrlen = sizeof(addr); + ASSIGN_OR_RETURN(auto used, recvfrom(sock, dst, flags, asSockaddrPtr(&addr), &addrlen)); + return std::make_pair(used, addr); + } +}; + +// Specialized singleton that supports zero initialization and runtime +// override of contained pointer. +class SyscallsHolder { + public: + ~SyscallsHolder(); + + // Return a pointer to an unowned instance of Syscalls. + Syscalls& get(); + + // Testing only: set the value returned by getSyscalls. Return the old value. + // Callers are responsible for restoring the previous value returned + // by getSyscalls to avoid leaks. + Syscalls& swap(Syscalls& syscalls); + + private: + std::atomic mSyscalls{nullptr}; +}; + +// Syscalls instance used throughout netdutils +extern SyscallsHolder sSyscalls; + +} // namespace netdutils +} // namespace android + +#endif /* NETDUTILS_SYSCALLS_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/ThreadUtil.h b/staticlibs/netd/libnetdutils/include/netdutils/ThreadUtil.h new file mode 100644 index 0000000000..62e6f70c90 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/ThreadUtil.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETDUTILS_THREADUTIL_H +#define NETDUTILS_THREADUTIL_H + +#include +#include + +#include + +namespace android { +namespace netdutils { + +struct scoped_pthread_attr { + scoped_pthread_attr() { pthread_attr_init(&attr); } + ~scoped_pthread_attr() { pthread_attr_destroy(&attr); } + + int detach() { return -pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); } + + pthread_attr_t attr; +}; + +inline void setThreadName(std::string name) { + // MAX_TASK_COMM_LEN=16 is not exported by bionic. + const size_t MAX_TASK_COMM_LEN = 16; + + // Crop name to 16 bytes including the NUL byte, as required by pthread_setname_np() + if (name.size() >= MAX_TASK_COMM_LEN) name.resize(MAX_TASK_COMM_LEN - 1); + + if (int ret = pthread_setname_np(pthread_self(), name.c_str()); ret != 0) { + LOG(WARNING) << "Unable to set thread name to " << name << ": " << strerror(ret); + } +} + +template +inline void* runAndDelete(void* obj) { + std::unique_ptr handler(reinterpret_cast(obj)); + setThreadName(handler->threadName().c_str()); + handler->run(); + return nullptr; +} + +template +inline int threadLaunch(T* obj) { + if (obj == nullptr) { + return -EINVAL; + } + + scoped_pthread_attr scoped_attr; + + int rval = scoped_attr.detach(); + if (rval != 0) { + return rval; + } + + pthread_t thread; + rval = pthread_create(&thread, &scoped_attr.attr, &runAndDelete, obj); + if (rval != 0) { + LOG(WARNING) << __func__ << ": pthread_create failed: " << rval; + return -rval; + } + + return rval; +} + +} // namespace netdutils +} // namespace android + +#endif // NETDUTILS_THREADUTIL_H diff --git a/staticlibs/netd/libnetdutils/include/netdutils/UidConstants.h b/staticlibs/netd/libnetdutils/include/netdutils/UidConstants.h new file mode 100644 index 0000000000..42c10908aa --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/UidConstants.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef NETDUTILS_UID_CONSTANTS_H +#define NETDUTILS_UID_CONSTANTS_H + +// These are used by both eBPF kernel programs and netd, we cannot put them in NetdConstant.h since +// we have to minimize the number of headers included by the BPF kernel program. +#define MIN_SYSTEM_UID 0 +#define MAX_SYSTEM_UID 9999 + +#define PER_USER_RANGE 100000 + +#endif // NETDUTILS_UID_CONSTANTS_H diff --git a/staticlibs/netd/libnetdutils/include/netdutils/UniqueFd.h b/staticlibs/netd/libnetdutils/include/netdutils/UniqueFd.h new file mode 100644 index 0000000000..61101f95ac --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/UniqueFd.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_UNIQUEFD_H +#define NETUTILS_UNIQUEFD_H + +#include +#include + +#include "netdutils/Fd.h" + +namespace android { +namespace netdutils { + +// Stricter unique_fd implementation that: +// *) Does not implement release() +// *) Does not implicitly cast to int +// *) Uses a strongly typed wrapper (Fd) for the underlying file descriptor +// +// Users of UniqueFd should endeavor to treat this as a completely +// opaque object. The only code that should interpret the wrapped +// value is in Syscalls.h +class UniqueFd { + public: + UniqueFd() = default; + + UniqueFd(Fd fd) : mFd(fd) {} + + ~UniqueFd() { reset(); } + + // Disallow copy + UniqueFd(const UniqueFd&) = delete; + UniqueFd& operator=(const UniqueFd&) = delete; + + // Allow move + UniqueFd(UniqueFd&& other) { std::swap(mFd, other.mFd); } + UniqueFd& operator=(UniqueFd&& other) { + std::swap(mFd, other.mFd); + return *this; + } + + // Cleanup any currently owned Fd, replacing it with the optional + // parameter fd + void reset(Fd fd = Fd()); + + // Implict cast to Fd + operator const Fd &() const { return mFd; } + + private: + Fd mFd; +}; + +std::ostream& operator<<(std::ostream& os, const UniqueFd& fd); + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_UNIQUEFD_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/UniqueFile.h b/staticlibs/netd/libnetdutils/include/netdutils/UniqueFile.h new file mode 100644 index 0000000000..6dd6d6728e --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/UniqueFile.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETDUTILS_UNIQUEFILE_H +#define NETDUTILS_UNIQUEFILE_H + +#include +#include + +namespace android { +namespace netdutils { + +struct UniqueFileDtor { + void operator()(FILE* file) const; +}; + +using UniqueFile = std::unique_ptr; + +} // namespace netdutils +} // namespace android + +#endif /* NETDUTILS_UNIQUEFILE_H */ From 9053e465088bf7e611db34eee36d8cd3b4092ddd Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 26 Nov 2020 23:34:33 +0800 Subject: [PATCH 279/777] Add ContextUtils Some tests need to create a Context with assigned user and should delegate to orignal Context. Thus, add ContextUtils#mockContextAsUser to factorize the usage. Bug: 170593746 Test: atest FrameworksNetTests Change-Id: I93f64a141709e181276ed4b5195811c36100c1d0 --- .../com/android/testutils/ContextUtils.kt | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/ContextUtils.kt diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ContextUtils.kt b/staticlibs/testutils/devicetests/com/android/testutils/ContextUtils.kt new file mode 100644 index 0000000000..814a75b4c3 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/ContextUtils.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 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. + */ + +@file:JvmName("ContextUtils") + +package com.android.testutils + +import android.content.Context +import android.os.UserHandle +import org.mockito.AdditionalAnswers.delegatesTo +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.mock +import java.util.function.BiConsumer + +// Helper function so that Java doesn't have to pass a method that returns Unit +fun mockContextAsUser(context: Context, functor: BiConsumer? = null) = + mockContextAsUser(context) { c, h -> functor?.accept(c, h) } + +/** + * Return a context with assigned user and delegate to original context. + * + * @param context the mock context to set up createContextAsUser on. After this function + * is called, client code can call createContextAsUser and expect a context that + * will return the correct user and userId. + * + * @param functor additional code to run on the created context-as-user instances, for example to + * set up further mocks on these contexts. + */ +fun mockContextAsUser(context: Context, functor: ((Context, UserHandle) -> Unit)? = null) { + doAnswer { invocation -> + val asUserContext = mock(Context::class.java, delegatesTo(context)) + val user = invocation.arguments[0] as UserHandle + val userId = user.identifier + doReturn(user).`when`(asUserContext).user + doReturn(userId).`when`(asUserContext).userId + functor?.let { it(asUserContext, user) } + asUserContext + }.`when`(context).createContextAsUser(any(UserHandle::class.java), anyInt() /* flags */) +} From d27d6c90626f1bb6b900b9d384a630cdada19fb9 Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Thu, 21 Oct 2021 22:18:59 +0800 Subject: [PATCH 280/777] [NETD-BPF#1] Move libnetdutils to frameworks/libs/net/... libnetdutils is referenced by netd.c and TrafficController.cpp, which are going to be mainlined. Therefore, move libnetdutils to a common place where both mainline module and platform code (Netd) can refer to. Bug: 202086915 Test: build; flash; cd system/netd; atest Ignore-AOSP-First: the netd change(same topic) would not automerge from aosp. No-Typo-Check: Clean code move with no other changes. BYPASS_INCLUSIVE_LANGUAGE_REASON=Clean code move with no other changes. Change-Id: I645bfe35f6543149c9a9f894cd4158d27a481abe --- staticlibs/netd/libnetdutils/Android.bp | 65 +++ .../netd/libnetdutils/BackoffSequenceTest.cpp | 186 ++++++ staticlibs/netd/libnetdutils/DumpWriter.cpp | 72 +++ staticlibs/netd/libnetdutils/Fd.cpp | 27 + staticlibs/netd/libnetdutils/FdTest.cpp | 147 +++++ .../netd/libnetdutils/InternetAddresses.cpp | 164 ++++++ .../libnetdutils/InternetAddressesTest.cpp | 541 ++++++++++++++++++ staticlibs/netd/libnetdutils/Log.cpp | 216 +++++++ staticlibs/netd/libnetdutils/LogTest.cpp | 143 +++++ staticlibs/netd/libnetdutils/MemBlockTest.cpp | 146 +++++ staticlibs/netd/libnetdutils/Netfilter.cpp | 30 + staticlibs/netd/libnetdutils/Netlink.cpp | 78 +++ staticlibs/netd/libnetdutils/Slice.cpp | 61 ++ staticlibs/netd/libnetdutils/SliceTest.cpp | 135 +++++ staticlibs/netd/libnetdutils/Socket.cpp | 35 ++ staticlibs/netd/libnetdutils/SocketOption.cpp | 54 ++ staticlibs/netd/libnetdutils/Status.cpp | 45 ++ staticlibs/netd/libnetdutils/StatusTest.cpp | 105 ++++ staticlibs/netd/libnetdutils/Syscalls.cpp | 265 +++++++++ staticlibs/netd/libnetdutils/SyscallsTest.cpp | 202 +++++++ .../netd/libnetdutils/ThreadUtilTest.cpp | 122 ++++ staticlibs/netd/libnetdutils/UniqueFd.cpp | 38 ++ staticlibs/netd/libnetdutils/UniqueFile.cpp | 31 + .../include/netdutils/BackoffSequence.h | 153 +++++ .../include/netdutils/DumpWriter.h | 68 +++ .../netd/libnetdutils/include/netdutils/Fd.h | 54 ++ .../libnetdutils/include/netdutils/Handle.h | 74 +++ .../include/netdutils/InternetAddresses.h | 325 +++++++++++ .../netd/libnetdutils/include/netdutils/Log.h | 211 +++++++ .../libnetdutils/include/netdutils/Math.h | 40 ++ .../libnetdutils/include/netdutils/MemBlock.h | 67 +++ .../libnetdutils/include/netdutils/Misc.h | 63 ++ .../include/netdutils/MockSyscalls.h | 90 +++ .../include/netdutils/Netfilter.h | 28 + .../libnetdutils/include/netdutils/Netlink.h | 55 ++ .../include/netdutils/NetworkConstants.h | 32 ++ .../include/netdutils/ResponseCode.h | 92 +++ .../libnetdutils/include/netdutils/Slice.h | 161 ++++++ .../libnetdutils/include/netdutils/Socket.h | 44 ++ .../include/netdutils/SocketOption.h | 60 ++ .../libnetdutils/include/netdutils/Status.h | 136 +++++ .../libnetdutils/include/netdutils/StatusOr.h | 119 ++++ .../include/netdutils/Stopwatch.h | 53 ++ .../libnetdutils/include/netdutils/Syscalls.h | 204 +++++++ .../include/netdutils/ThreadUtil.h | 83 +++ .../include/netdutils/UidConstants.h | 27 + .../libnetdutils/include/netdutils/UniqueFd.h | 71 +++ .../include/netdutils/UniqueFile.h | 35 ++ 48 files changed, 5253 insertions(+) create mode 100644 staticlibs/netd/libnetdutils/Android.bp create mode 100644 staticlibs/netd/libnetdutils/BackoffSequenceTest.cpp create mode 100644 staticlibs/netd/libnetdutils/DumpWriter.cpp create mode 100644 staticlibs/netd/libnetdutils/Fd.cpp create mode 100644 staticlibs/netd/libnetdutils/FdTest.cpp create mode 100644 staticlibs/netd/libnetdutils/InternetAddresses.cpp create mode 100644 staticlibs/netd/libnetdutils/InternetAddressesTest.cpp create mode 100644 staticlibs/netd/libnetdutils/Log.cpp create mode 100644 staticlibs/netd/libnetdutils/LogTest.cpp create mode 100644 staticlibs/netd/libnetdutils/MemBlockTest.cpp create mode 100644 staticlibs/netd/libnetdutils/Netfilter.cpp create mode 100644 staticlibs/netd/libnetdutils/Netlink.cpp create mode 100644 staticlibs/netd/libnetdutils/Slice.cpp create mode 100644 staticlibs/netd/libnetdutils/SliceTest.cpp create mode 100644 staticlibs/netd/libnetdutils/Socket.cpp create mode 100644 staticlibs/netd/libnetdutils/SocketOption.cpp create mode 100644 staticlibs/netd/libnetdutils/Status.cpp create mode 100644 staticlibs/netd/libnetdutils/StatusTest.cpp create mode 100644 staticlibs/netd/libnetdutils/Syscalls.cpp create mode 100644 staticlibs/netd/libnetdutils/SyscallsTest.cpp create mode 100644 staticlibs/netd/libnetdutils/ThreadUtilTest.cpp create mode 100644 staticlibs/netd/libnetdutils/UniqueFd.cpp create mode 100644 staticlibs/netd/libnetdutils/UniqueFile.cpp create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/BackoffSequence.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/DumpWriter.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Fd.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Handle.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/InternetAddresses.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Log.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Math.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/MemBlock.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Misc.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/MockSyscalls.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Netfilter.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Netlink.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/NetworkConstants.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/ResponseCode.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Slice.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Socket.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/SocketOption.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Status.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/StatusOr.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Stopwatch.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Syscalls.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/ThreadUtil.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/UidConstants.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/UniqueFd.h create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/UniqueFile.h diff --git a/staticlibs/netd/libnetdutils/Android.bp b/staticlibs/netd/libnetdutils/Android.bp new file mode 100644 index 0000000000..3bb627069a --- /dev/null +++ b/staticlibs/netd/libnetdutils/Android.bp @@ -0,0 +1,65 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_library { + name: "libnetdutils", + srcs: [ + "DumpWriter.cpp", + "Fd.cpp", + "InternetAddresses.cpp", + "Log.cpp", + "Netfilter.cpp", + "Netlink.cpp", + "Slice.cpp", + "Socket.cpp", + "SocketOption.cpp", + "Status.cpp", + "Syscalls.cpp", + "UniqueFd.cpp", + "UniqueFile.cpp", + ], + defaults: ["netd_defaults"], + cflags: ["-Wall", "-Werror"], + shared_libs: [ + "libbase", + "liblog", + ], + export_shared_lib_headers: [ + "libbase", + ], + export_include_dirs: ["include"], + sanitize: { + cfi: true, + }, + + apex_available: [ + "//apex_available:platform", + "com.android.resolv", + ], + min_sdk_version: "29", +} + +cc_test { + name: "netdutils_test", + srcs: [ + "BackoffSequenceTest.cpp", + "FdTest.cpp", + "InternetAddressesTest.cpp", + "LogTest.cpp", + "MemBlockTest.cpp", + "SliceTest.cpp", + "StatusTest.cpp", + "SyscallsTest.cpp", + "ThreadUtilTest.cpp", + ], + defaults: ["netd_defaults"], + test_suites: ["device-tests"], + static_libs: [ + "libgmock", + "libnetdutils", + ], + shared_libs: [ + "libbase", + ], +} diff --git a/staticlibs/netd/libnetdutils/BackoffSequenceTest.cpp b/staticlibs/netd/libnetdutils/BackoffSequenceTest.cpp new file mode 100644 index 0000000000..b6653fe80a --- /dev/null +++ b/staticlibs/netd/libnetdutils/BackoffSequenceTest.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2018 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. + */ + +#include + +#include "netdutils/BackoffSequence.h" + +namespace android { +namespace netdutils { + +TEST(BackoffSequence, defaults) { + BackoffSequence backoff; + + EXPECT_TRUE(backoff.hasNextTimeout()); + EXPECT_EQ(0x00000001U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000002U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000004U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000008U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000010U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000020U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000040U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000080U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000100U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000200U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000400U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000800U, backoff.getNextTimeout()); + EXPECT_EQ(0x00001000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00002000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00004000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00008000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00010000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00020000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00040000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00080000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00100000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00200000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00400000U, backoff.getNextTimeout()); + EXPECT_EQ(0x00800000U, backoff.getNextTimeout()); + EXPECT_EQ(0x01000000U, backoff.getNextTimeout()); + EXPECT_EQ(0x02000000U, backoff.getNextTimeout()); + EXPECT_EQ(0x04000000U, backoff.getNextTimeout()); + EXPECT_EQ(0x08000000U, backoff.getNextTimeout()); + EXPECT_EQ(0x10000000U, backoff.getNextTimeout()); + EXPECT_EQ(0x20000000U, backoff.getNextTimeout()); + EXPECT_EQ(0x40000000U, backoff.getNextTimeout()); + EXPECT_EQ(0x80000000U, backoff.getNextTimeout()); + // Maxes out, and stays there, ad infinitum. + for (int i = 0; i < 10; i++) { + EXPECT_TRUE(backoff.hasNextTimeout()); + EXPECT_EQ(0xffffffffU, backoff.getNextTimeout()); + } +} + +TEST(BackoffSequence, backoffToOncePerHour) { + auto backoff = BackoffSequence::Builder() + .withInitialRetransmissionTime(1) + .withMaximumRetransmissionTime(3600) + .build(); + + EXPECT_TRUE(backoff.hasNextTimeout()); + EXPECT_EQ(0x00000001U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000002U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000004U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000008U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000010U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000020U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000040U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000080U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000100U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000200U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000400U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000800U, backoff.getNextTimeout()); + // Maxes out, and stays there, ad infinitum. + for (int i = 0; i < 10; i++) { + EXPECT_TRUE(backoff.hasNextTimeout()); + EXPECT_EQ(3600U, backoff.getNextTimeout()); + } +} + +TEST(BackoffSequence, simpleMaxRetransCount) { + auto backoff = BackoffSequence::Builder() + .withInitialRetransmissionTime(3) + .withMaximumRetransmissionCount(7) + .build(); + + EXPECT_TRUE(backoff.hasNextTimeout()); + EXPECT_EQ(0x00000003U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000006U, backoff.getNextTimeout()); + EXPECT_EQ(0x0000000cU, backoff.getNextTimeout()); + EXPECT_EQ(0x00000018U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000030U, backoff.getNextTimeout()); + EXPECT_EQ(0x00000060U, backoff.getNextTimeout()); + EXPECT_EQ(0x000000c0U, backoff.getNextTimeout()); + + for (int i = 0; i < 10; i++) { + EXPECT_FALSE(backoff.hasNextTimeout()); + EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout()); + } +} + +TEST(BackoffSequence, simpleMaxDuration) { + auto backoff = BackoffSequence::Builder() + .withInitialRetransmissionTime(3) + .withMaximumRetransmissionDuration(7) + .withEndOfSequenceIndicator(-1) + .build(); + + EXPECT_TRUE(backoff.hasNextTimeout()); + EXPECT_EQ(0x00000003, backoff.getNextTimeout()); + EXPECT_EQ(0x00000004, backoff.getNextTimeout()); + + for (int i = 0; i < 10; i++) { + EXPECT_FALSE(backoff.hasNextTimeout()); + EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout()); + EXPECT_EQ(-1, backoff.getNextTimeout()); + } +} + +TEST(PathologicalBackoffSequence, ZeroInitialRetransTime) { + auto backoff = BackoffSequence::Builder() + .withInitialRetransmissionTime(std::chrono::seconds(0)) + .build(); + + for (int i = 0; i < 10; i++) { + // TODO: Decide whether this needs fixing, and how. + EXPECT_TRUE(backoff.hasNextTimeout()); + EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout()); + } +} + +TEST(PathologicalBackoffSequence, MaxRetransDurationGreaterThanInitialRetransTime) { + auto backoff = BackoffSequence::Builder() + .withInitialRetransmissionTime(std::chrono::milliseconds(5)) + .withMaximumRetransmissionDuration(std::chrono::milliseconds(3)) + .build(); + + EXPECT_EQ(std::chrono::milliseconds(3), backoff.getNextTimeout()); + for (int i = 0; i < 10; i++) { + EXPECT_FALSE(backoff.hasNextTimeout()); + EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout()); + } +} + +TEST(PathologicalBackoffSequence, MaxRetransDurationEqualsInitialRetransTime) { + auto backoff = BackoffSequence::Builder() + .withInitialRetransmissionTime(std::chrono::hours(5)) + .withMaximumRetransmissionDuration(std::chrono::hours(5)) + .build(); + + EXPECT_EQ(std::chrono::hours(5), backoff.getNextTimeout()); + for (int i = 0; i < 10; i++) { + EXPECT_FALSE(backoff.hasNextTimeout()); + EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout()); + } +} + +TEST(PathologicalBackoffSequence, MaxRetransTimeAndDurationGreaterThanInitialRetransTime) { + auto backoff = BackoffSequence::Builder() + .withInitialRetransmissionTime(std::chrono::nanoseconds(7)) + .withMaximumRetransmissionTime(std::chrono::nanoseconds(3)) + .withMaximumRetransmissionDuration(std::chrono::nanoseconds(5)) + .build(); + + EXPECT_EQ(std::chrono::nanoseconds(3), backoff.getNextTimeout()); + EXPECT_EQ(std::chrono::nanoseconds(2), backoff.getNextTimeout()); + for (int i = 0; i < 10; i++) { + EXPECT_FALSE(backoff.hasNextTimeout()); + EXPECT_EQ(backoff.getEndOfSequenceIndicator(), backoff.getNextTimeout()); + } +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/DumpWriter.cpp b/staticlibs/netd/libnetdutils/DumpWriter.cpp new file mode 100644 index 0000000000..092ddbae2d --- /dev/null +++ b/staticlibs/netd/libnetdutils/DumpWriter.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 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. + */ + +#include "netdutils/DumpWriter.h" + +#include +#include + +#include +#include + +using android::base::StringAppendV; + +namespace android { +namespace netdutils { + +namespace { + +const char kIndentString[] = " "; +const size_t kIndentStringLen = strlen(kIndentString); + +} // namespace + +DumpWriter::DumpWriter(int fd) : mIndentLevel(0), mFd(fd) {} + +void DumpWriter::incIndent() { + if (mIndentLevel < std::numeric_limits::max()) { + mIndentLevel++; + } +} + +void DumpWriter::decIndent() { + if (mIndentLevel > std::numeric_limits::min()) { + mIndentLevel--; + } +} + +void DumpWriter::println(const std::string& line) { + if (!line.empty()) { + for (int i = 0; i < mIndentLevel; i++) { + ::write(mFd, kIndentString, kIndentStringLen); + } + ::write(mFd, line.c_str(), line.size()); + } + ::write(mFd, "\n", 1); +} + +// NOLINTNEXTLINE(cert-dcl50-cpp): Grandfathered C-style variadic function. +void DumpWriter::println(const char* fmt, ...) { + std::string line; + va_list ap; + va_start(ap, fmt); + StringAppendV(&line, fmt, ap); + va_end(ap); + println(line); +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/Fd.cpp b/staticlibs/netd/libnetdutils/Fd.cpp new file mode 100644 index 0000000000..2651f906e7 --- /dev/null +++ b/staticlibs/netd/libnetdutils/Fd.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 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. + */ + +#include "netdutils/Fd.h" + +namespace android { +namespace netdutils { + +std::ostream& operator<<(std::ostream& os, const Fd& fd) { + return os << "Fd[" << fd.get() << "]"; +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/FdTest.cpp b/staticlibs/netd/libnetdutils/FdTest.cpp new file mode 100644 index 0000000000..7080f831a1 --- /dev/null +++ b/staticlibs/netd/libnetdutils/FdTest.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2017 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. + */ + +#include + +#include + +#include "netdutils/MockSyscalls.h" +#include "netdutils/Status.h" +#include "netdutils/Syscalls.h" + +using testing::Mock; +using testing::Return; +using testing::StrictMock; + +namespace android { +namespace netdutils { +namespace { + +// Force implicit conversion from UniqueFd -> Fd +inline Fd toFd(const UniqueFd& fd) { + return fd; +} + +} // namespace + +TEST(Fd, smoke) { + // Expect the following lines to compile + Fd fd1(1); + Fd fd2(fd1); + Fd fd3 = fd2; + const Fd fd4(8); + const Fd fd5(fd4); + const Fd fd6 = fd5; + EXPECT_TRUE(isWellFormed(fd3)); + EXPECT_TRUE(isWellFormed(fd6)); + + // Corner case + Fd zero(0); + EXPECT_TRUE(isWellFormed(zero)); + + // Invalid file descriptors + Fd bad(-1); + Fd weird(-9); + EXPECT_FALSE(isWellFormed(bad)); + EXPECT_FALSE(isWellFormed(weird)); + + // Default constructor + EXPECT_EQ(Fd(-1), Fd()); + std::stringstream ss; + ss << fd3 << " " << fd6 << " " << bad << " " << weird; + EXPECT_EQ("Fd[1] Fd[8] Fd[-1] Fd[-9]", ss.str()); +} + +class UniqueFdTest : public testing::Test { + protected: + StrictMock mSyscalls; +}; + +TEST_F(UniqueFdTest, operatorOstream) { + UniqueFd u(97); + EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok)); + std::stringstream ss; + ss << u; + EXPECT_EQ("UniqueFd[Fd[97]]", ss.str()); + u.reset(); +} + +TEST_F(UniqueFdTest, destructor) { + { + UniqueFd u(98); + EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok)); + } + // Expectation above should be upon leaving nested scope + Mock::VerifyAndClearExpectations(&mSyscalls); +} + +TEST_F(UniqueFdTest, reset) { + UniqueFd u(99); + EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok)); + u.reset(); + + // Expectation above should be upon reset + Mock::VerifyAndClearExpectations(&mSyscalls); +} + +TEST_F(UniqueFdTest, moveConstructor) { + constexpr Fd kFd(101); + UniqueFd u1(kFd); + { + UniqueFd u2(std::move(u1)); + // NOLINTNEXTLINE bugprone-use-after-move + EXPECT_FALSE(isWellFormed(u1)); + EXPECT_TRUE(isWellFormed(u2)); + EXPECT_CALL(mSyscalls, close(kFd)).WillOnce(Return(status::ok)); + } + // Expectation above should be upon leaving nested scope + Mock::VerifyAndClearExpectations(&mSyscalls); +} + +TEST_F(UniqueFdTest, moveAssignment) { + constexpr Fd kFd(102); + UniqueFd u1(kFd); + { + UniqueFd u2 = std::move(u1); + // NOLINTNEXTLINE bugprone-use-after-move + EXPECT_FALSE(isWellFormed(u1)); + EXPECT_TRUE(isWellFormed(u2)); + UniqueFd u3; + u3 = std::move(u2); + // NOLINTNEXTLINE bugprone-use-after-move + EXPECT_FALSE(isWellFormed(u2)); + EXPECT_TRUE(isWellFormed(u3)); + EXPECT_CALL(mSyscalls, close(kFd)).WillOnce(Return(status::ok)); + } + // Expectation above should be upon leaving nested scope + Mock::VerifyAndClearExpectations(&mSyscalls); +} + +TEST_F(UniqueFdTest, constConstructor) { + constexpr Fd kFd(103); + const UniqueFd u(kFd); + EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(status::ok)); +} + +TEST_F(UniqueFdTest, closeFailure) { + constexpr Fd kFd(103); + UniqueFd u(kFd); + EXPECT_CALL(mSyscalls, close(toFd(u))).WillOnce(Return(statusFromErrno(EINTR, "test"))); + EXPECT_DEBUG_DEATH(u.reset(), ""); +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/InternetAddresses.cpp b/staticlibs/netd/libnetdutils/InternetAddresses.cpp new file mode 100644 index 0000000000..322f1b1d6c --- /dev/null +++ b/staticlibs/netd/libnetdutils/InternetAddresses.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2018 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. + */ + +#include "netdutils/InternetAddresses.h" + +#include + +#include +#include +#include +#include +#include + +namespace android { + +using base::StringPrintf; + +namespace netdutils { + +std::string IPAddress::toString() const noexcept { + char repr[INET6_ADDRSTRLEN] = "\0"; + + switch (mData.family) { + case AF_UNSPEC: + return ""; + case AF_INET: { + const in_addr v4 = mData.ip.v4; + inet_ntop(AF_INET, &v4, repr, sizeof(repr)); + break; + } + case AF_INET6: { + const in6_addr v6 = mData.ip.v6; + inet_ntop(AF_INET6, &v6, repr, sizeof(repr)); + break; + } + default: + return ""; + } + + if (mData.family == AF_INET6 && mData.scope_id > 0) { + return StringPrintf("%s%%%u", repr, mData.scope_id); + } + + return repr; +} + +bool IPAddress::forString(const std::string& repr, IPAddress* ip) { + const addrinfo hints = { + .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV, + }; + addrinfo* res; + const int ret = getaddrinfo(repr.c_str(), nullptr, &hints, &res); + ScopedAddrinfo res_cleanup(res); + if (ret != 0) { + return false; + } + + bool rval = true; + switch (res[0].ai_family) { + case AF_INET: { + sockaddr_in* sin = (sockaddr_in*) res[0].ai_addr; + if (ip) *ip = IPAddress(sin->sin_addr); + break; + } + case AF_INET6: { + sockaddr_in6* sin6 = (sockaddr_in6*) res[0].ai_addr; + if (ip) *ip = IPAddress(sin6->sin6_addr, sin6->sin6_scope_id); + break; + } + default: + rval = false; + break; + } + + return rval; +} + +IPPrefix::IPPrefix(const IPAddress& ip, int length) : IPPrefix(ip) { + // Silently treat CIDR lengths like "-1" as meaning the full bit length + // appropriate to the address family. + if (length < 0) return; + if (length >= mData.cidrlen) return; + + switch (mData.family) { + case AF_UNSPEC: + break; + case AF_INET: { + const in_addr_t mask = (length > 0) ? (~0U) << (IPV4_ADDR_BITS - length) : 0U; + mData.ip.v4.s_addr &= htonl(mask); + mData.cidrlen = static_cast(length); + break; + } + case AF_INET6: { + // The byte in which this CIDR length falls. + const int which = length / 8; + const int mask = (length % 8 == 0) ? 0 : 0xff << (8 - length % 8); + mData.ip.v6.s6_addr[which] &= mask; + for (int i = which + 1; i < IPV6_ADDR_LEN; i++) { + mData.ip.v6.s6_addr[i] = 0U; + } + mData.cidrlen = static_cast(length); + break; + } + default: + // TODO: Complain bitterly about possible data corruption? + return; + } +} + +bool IPPrefix::isUninitialized() const noexcept { + static const internal_::compact_ipdata empty{}; + return mData == empty; +} + +bool IPPrefix::forString(const std::string& repr, IPPrefix* prefix) { + size_t index = repr.find('/'); + if (index == std::string::npos) return false; + + // Parse the IP address. + IPAddress ip; + if (!IPAddress::forString(repr.substr(0, index), &ip)) return false; + + // Parse the prefix length. Can't use base::ParseUint because it accepts non-base 10 input. + const char* prefixString = repr.c_str() + index + 1; + if (!isdigit(*prefixString)) return false; + char* endptr; + unsigned long prefixlen = strtoul(prefixString, &endptr, 10); + if (*endptr != '\0') return false; + + uint8_t maxlen = (ip.family() == AF_INET) ? 32 : 128; + if (prefixlen > maxlen) return false; + + *prefix = IPPrefix(ip, prefixlen); + return true; +} + +std::string IPPrefix::toString() const noexcept { + return StringPrintf("%s/%d", ip().toString().c_str(), mData.cidrlen); +} + +std::string IPSockAddr::toString() const noexcept { + switch (mData.family) { + case AF_INET6: + return StringPrintf("[%s]:%u", ip().toString().c_str(), mData.port); + default: + return StringPrintf("%s:%u", ip().toString().c_str(), mData.port); + } +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/InternetAddressesTest.cpp b/staticlibs/netd/libnetdutils/InternetAddressesTest.cpp new file mode 100644 index 0000000000..f75fa769ee --- /dev/null +++ b/staticlibs/netd/libnetdutils/InternetAddressesTest.cpp @@ -0,0 +1,541 @@ +/* + * Copyright (C) 2018 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. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "netdutils/InternetAddresses.h" + +namespace android { +namespace netdutils { +namespace { + +enum Relation { EQ, LT }; + +std::ostream& operator<<(std::ostream& os, Relation relation) { + switch (relation) { + case EQ: os << "eq"; break; + case LT: os << "lt"; break; + default: os << "?!"; break; + } + return os; +} + +template +struct OperatorExpectation { + const Relation relation; + const T obj1; + const T obj2; + + std::string toString() const { + std::stringstream output; + output << obj1 << " " << relation << " " << obj2; + return output.str(); + } +}; + +template +void testGamutOfOperators(const OperatorExpectation& expectation) { + switch (expectation.relation) { + case EQ: + EXPECT_TRUE(expectation.obj1 == expectation.obj2); + EXPECT_TRUE(expectation.obj1 <= expectation.obj2); + EXPECT_TRUE(expectation.obj1 >= expectation.obj2); + EXPECT_FALSE(expectation.obj1 != expectation.obj2); + EXPECT_FALSE(expectation.obj1 < expectation.obj2); + EXPECT_FALSE(expectation.obj1 > expectation.obj2); + break; + + case LT: + EXPECT_TRUE(expectation.obj1 < expectation.obj2); + EXPECT_TRUE(expectation.obj1 <= expectation.obj2); + EXPECT_TRUE(expectation.obj1 != expectation.obj2); + EXPECT_FALSE(expectation.obj1 > expectation.obj2); + EXPECT_FALSE(expectation.obj1 >= expectation.obj2); + EXPECT_FALSE(expectation.obj1 == expectation.obj2); + break; + + default: + FAIL() << "Unknown relation given in test expectation"; + } +} + +const in_addr IPV4_ANY{htonl(INADDR_ANY)}; +const in_addr IPV4_LOOPBACK{htonl(INADDR_LOOPBACK)}; +const in_addr IPV4_ONES{~0U}; +const in6_addr IPV6_ANY = IN6ADDR_ANY_INIT; +const in6_addr IPV6_LOOPBACK = IN6ADDR_LOOPBACK_INIT; +const in6_addr FE80{{{0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}; +const in6_addr FE80_1{{{0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,1}}}; +const in6_addr FE80_2{{{0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,2}}}; +const uint8_t ff = std::numeric_limits::max(); +const in6_addr IPV6_ONES{{{ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff}}}; + +TEST(IPAddressTest, GamutOfOperators) { + const std::vector> kExpectations{ + {EQ, IPAddress(), IPAddress()}, + {EQ, IPAddress(IPV4_ONES), IPAddress(IPV4_ONES)}, + {EQ, IPAddress(IPV6_ONES), IPAddress(IPV6_ONES)}, + {EQ, IPAddress(FE80_1), IPAddress(FE80_1)}, + {EQ, IPAddress(FE80_2), IPAddress(FE80_2)}, + {LT, IPAddress(), IPAddress(IPV4_ANY)}, + {LT, IPAddress(), IPAddress(IPV4_ONES)}, + {LT, IPAddress(), IPAddress(IPV6_ANY)}, + {LT, IPAddress(), IPAddress(IPV6_ONES)}, + {LT, IPAddress(IPV4_ANY), IPAddress(IPV4_ONES)}, + {LT, IPAddress(IPV4_ANY), IPAddress(IPV6_ANY)}, + {LT, IPAddress(IPV4_ONES), IPAddress(IPV6_ANY)}, + {LT, IPAddress(IPV4_ONES), IPAddress(IPV6_ONES)}, + {LT, IPAddress(IPV6_ANY), IPAddress(IPV6_LOOPBACK)}, + {LT, IPAddress(IPV6_ANY), IPAddress(IPV6_ONES)}, + {LT, IPAddress(IPV6_LOOPBACK), IPAddress(IPV6_ONES)}, + {LT, IPAddress(FE80_1), IPAddress(FE80_2)}, + {LT, IPAddress(FE80_1), IPAddress(IPV6_ONES)}, + {LT, IPAddress(FE80_2), IPAddress(IPV6_ONES)}, + // Sort by scoped_id within the same address. + {LT, IPAddress(FE80_1), IPAddress(FE80_1, 1)}, + {LT, IPAddress(FE80_1, 1), IPAddress(FE80_1, 2)}, + // Sort by address first, scope_id second. + {LT, IPAddress(FE80_1, 2), IPAddress(FE80_2, 1)}, + }; + + size_t tests_run = 0; + for (const auto& expectation : kExpectations) { + SCOPED_TRACE(expectation.toString()); + EXPECT_NO_FATAL_FAILURE(testGamutOfOperators(expectation)); + tests_run++; + } + EXPECT_EQ(kExpectations.size(), tests_run); +} + +TEST(IPAddressTest, ScopeIds) { + // Scope IDs ignored for IPv4 addresses. + const IPAddress ones(IPV4_ONES); + EXPECT_EQ(0U, ones.scope_id()); + const IPAddress ones22(ones, 22); + EXPECT_EQ(0U, ones22.scope_id()); + EXPECT_EQ(ones, ones22); + const IPAddress ones23(ones, 23); + EXPECT_EQ(0U, ones23.scope_id()); + EXPECT_EQ(ones22, ones23); + + EXPECT_EQ("fe80::1%22", IPAddress(FE80_1, 22).toString()); + EXPECT_EQ("fe80::2%23", IPAddress(FE80_2, 23).toString()); + + // Verify that given an IPAddress with a scope_id an address without a + // scope_id can be constructed (just in case it's useful). + const IPAddress fe80_intf22(FE80_1, 22); + EXPECT_EQ(22U, fe80_intf22.scope_id()); + EXPECT_EQ(fe80_intf22, IPAddress(fe80_intf22)); + EXPECT_EQ(IPAddress(FE80_1), IPAddress(fe80_intf22, 0)); +} + +TEST(IPAddressTest, forString) { + IPAddress ip; + + EXPECT_FALSE(IPAddress::forString("not_an_ip", &ip)); + EXPECT_FALSE(IPAddress::forString("not_an_ip", nullptr)); + EXPECT_EQ(IPAddress(), IPAddress::forString("not_an_ip")); + + EXPECT_EQ(IPAddress(IPV4_ANY), IPAddress::forString("0.0.0.0")); + EXPECT_EQ(IPAddress(IPV4_ONES), IPAddress::forString("255.255.255.255")); + EXPECT_EQ(IPAddress(IPV4_LOOPBACK), IPAddress::forString("127.0.0.1")); + + EXPECT_EQ(IPAddress(IPV6_ANY), IPAddress::forString("::")); + EXPECT_EQ(IPAddress(IPV6_ANY), IPAddress::forString("::0")); + EXPECT_EQ(IPAddress(IPV6_ANY), IPAddress::forString("0::")); + EXPECT_EQ(IPAddress(IPV6_LOOPBACK), IPAddress::forString("::1")); + EXPECT_EQ(IPAddress(IPV6_LOOPBACK), IPAddress::forString("0::1")); + EXPECT_EQ(IPAddress(FE80_1), IPAddress::forString("fe80::1")); + EXPECT_EQ(IPAddress(FE80_1, 22), IPAddress::forString("fe80::1%22")); + // This relies upon having a loopback interface named "lo" with ifindex 1. + EXPECT_EQ(IPAddress(FE80_1, 1), IPAddress::forString("fe80::1%lo")); +} + +TEST(IPPrefixTest, forString) { + IPPrefix prefix; + + EXPECT_FALSE(IPPrefix::forString("", &prefix)); + EXPECT_FALSE(IPPrefix::forString("invalid", &prefix)); + EXPECT_FALSE(IPPrefix::forString("192.0.2.0", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001::db8::", &prefix)); + + EXPECT_FALSE(IPPrefix::forString("2001:db8::/", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8:://32", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8::/32z", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8::/32/", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8::/0x20", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8:: /32", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8::/ 32", &prefix)); + EXPECT_FALSE(IPPrefix::forString(" 2001:db8::/32", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8::/32 ", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8::/+32", &prefix)); + + EXPECT_FALSE(IPPrefix::forString("192.0.2.0/33", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8::/129", &prefix)); + EXPECT_FALSE(IPPrefix::forString("192.0.2.0/-1", &prefix)); + EXPECT_FALSE(IPPrefix::forString("2001:db8::/-1", &prefix)); + + EXPECT_TRUE(IPPrefix::forString("2001:db8::/32", &prefix)); + EXPECT_EQ("2001:db8::/32", prefix.toString()); + EXPECT_EQ(IPPrefix(IPAddress::forString("2001:db8::"), 32), prefix); + + EXPECT_EQ(IPPrefix(), IPPrefix::forString("invalid")); + + EXPECT_EQ("0.0.0.0/0", IPPrefix::forString("0.0.0.0/0").toString()); + EXPECT_EQ("::/0", IPPrefix::forString("::/0").toString()); + EXPECT_EQ("192.0.2.128/25", IPPrefix::forString("192.0.2.131/25").toString()); + EXPECT_EQ("2001:db8:1:2:3:4:5:4/126", + IPPrefix::forString("2001:db8:1:2:3:4:5:6/126").toString()); +} + +TEST(IPPrefixTest, IPv4Truncation) { + const auto prefixStr = [](int length) -> std::string { + return IPPrefix(IPAddress(IPV4_ONES), length).toString(); + }; + + EXPECT_EQ("0.0.0.0/0", prefixStr(0)); + + EXPECT_EQ("128.0.0.0/1", prefixStr(1)); + EXPECT_EQ("192.0.0.0/2", prefixStr(2)); + EXPECT_EQ("224.0.0.0/3", prefixStr(3)); + EXPECT_EQ("240.0.0.0/4", prefixStr(4)); + EXPECT_EQ("248.0.0.0/5", prefixStr(5)); + EXPECT_EQ("252.0.0.0/6", prefixStr(6)); + EXPECT_EQ("254.0.0.0/7", prefixStr(7)); + EXPECT_EQ("255.0.0.0/8", prefixStr(8)); + + EXPECT_EQ("255.128.0.0/9", prefixStr(9)); + EXPECT_EQ("255.192.0.0/10", prefixStr(10)); + EXPECT_EQ("255.224.0.0/11", prefixStr(11)); + EXPECT_EQ("255.240.0.0/12", prefixStr(12)); + EXPECT_EQ("255.248.0.0/13", prefixStr(13)); + EXPECT_EQ("255.252.0.0/14", prefixStr(14)); + EXPECT_EQ("255.254.0.0/15", prefixStr(15)); + EXPECT_EQ("255.255.0.0/16", prefixStr(16)); + + EXPECT_EQ("255.255.128.0/17", prefixStr(17)); + EXPECT_EQ("255.255.192.0/18", prefixStr(18)); + EXPECT_EQ("255.255.224.0/19", prefixStr(19)); + EXPECT_EQ("255.255.240.0/20", prefixStr(20)); + EXPECT_EQ("255.255.248.0/21", prefixStr(21)); + EXPECT_EQ("255.255.252.0/22", prefixStr(22)); + EXPECT_EQ("255.255.254.0/23", prefixStr(23)); + EXPECT_EQ("255.255.255.0/24", prefixStr(24)); + + EXPECT_EQ("255.255.255.128/25", prefixStr(25)); + EXPECT_EQ("255.255.255.192/26", prefixStr(26)); + EXPECT_EQ("255.255.255.224/27", prefixStr(27)); + EXPECT_EQ("255.255.255.240/28", prefixStr(28)); + EXPECT_EQ("255.255.255.248/29", prefixStr(29)); + EXPECT_EQ("255.255.255.252/30", prefixStr(30)); + EXPECT_EQ("255.255.255.254/31", prefixStr(31)); + EXPECT_EQ("255.255.255.255/32", prefixStr(32)); +} + +TEST(IPPrefixTest, IPv6Truncation) { + const auto prefixStr = [](int length) -> std::string { + return IPPrefix(IPAddress(IPV6_ONES), length).toString(); + }; + + EXPECT_EQ("::/0", prefixStr(0)); + + EXPECT_EQ("8000::/1", prefixStr(1)); + EXPECT_EQ("c000::/2", prefixStr(2)); + EXPECT_EQ("e000::/3", prefixStr(3)); + EXPECT_EQ("f000::/4", prefixStr(4)); + EXPECT_EQ("f800::/5", prefixStr(5)); + EXPECT_EQ("fc00::/6", prefixStr(6)); + EXPECT_EQ("fe00::/7", prefixStr(7)); + EXPECT_EQ("ff00::/8", prefixStr(8)); + + EXPECT_EQ("ff80::/9", prefixStr(9)); + EXPECT_EQ("ffc0::/10", prefixStr(10)); + EXPECT_EQ("ffe0::/11", prefixStr(11)); + EXPECT_EQ("fff0::/12", prefixStr(12)); + EXPECT_EQ("fff8::/13", prefixStr(13)); + EXPECT_EQ("fffc::/14", prefixStr(14)); + EXPECT_EQ("fffe::/15", prefixStr(15)); + EXPECT_EQ("ffff::/16", prefixStr(16)); + + EXPECT_EQ("ffff:8000::/17", prefixStr(17)); + EXPECT_EQ("ffff:c000::/18", prefixStr(18)); + EXPECT_EQ("ffff:e000::/19", prefixStr(19)); + EXPECT_EQ("ffff:f000::/20", prefixStr(20)); + EXPECT_EQ("ffff:f800::/21", prefixStr(21)); + EXPECT_EQ("ffff:fc00::/22", prefixStr(22)); + EXPECT_EQ("ffff:fe00::/23", prefixStr(23)); + EXPECT_EQ("ffff:ff00::/24", prefixStr(24)); + + EXPECT_EQ("ffff:ff80::/25", prefixStr(25)); + EXPECT_EQ("ffff:ffc0::/26", prefixStr(26)); + EXPECT_EQ("ffff:ffe0::/27", prefixStr(27)); + EXPECT_EQ("ffff:fff0::/28", prefixStr(28)); + EXPECT_EQ("ffff:fff8::/29", prefixStr(29)); + EXPECT_EQ("ffff:fffc::/30", prefixStr(30)); + EXPECT_EQ("ffff:fffe::/31", prefixStr(31)); + EXPECT_EQ("ffff:ffff::/32", prefixStr(32)); + + EXPECT_EQ("ffff:ffff:8000::/33", prefixStr(33)); + EXPECT_EQ("ffff:ffff:c000::/34", prefixStr(34)); + EXPECT_EQ("ffff:ffff:e000::/35", prefixStr(35)); + EXPECT_EQ("ffff:ffff:f000::/36", prefixStr(36)); + EXPECT_EQ("ffff:ffff:f800::/37", prefixStr(37)); + EXPECT_EQ("ffff:ffff:fc00::/38", prefixStr(38)); + EXPECT_EQ("ffff:ffff:fe00::/39", prefixStr(39)); + EXPECT_EQ("ffff:ffff:ff00::/40", prefixStr(40)); + + EXPECT_EQ("ffff:ffff:ff80::/41", prefixStr(41)); + EXPECT_EQ("ffff:ffff:ffc0::/42", prefixStr(42)); + EXPECT_EQ("ffff:ffff:ffe0::/43", prefixStr(43)); + EXPECT_EQ("ffff:ffff:fff0::/44", prefixStr(44)); + EXPECT_EQ("ffff:ffff:fff8::/45", prefixStr(45)); + EXPECT_EQ("ffff:ffff:fffc::/46", prefixStr(46)); + EXPECT_EQ("ffff:ffff:fffe::/47", prefixStr(47)); + EXPECT_EQ("ffff:ffff:ffff::/48", prefixStr(48)); + + EXPECT_EQ("ffff:ffff:ffff:8000::/49", prefixStr(49)); + EXPECT_EQ("ffff:ffff:ffff:c000::/50", prefixStr(50)); + EXPECT_EQ("ffff:ffff:ffff:e000::/51", prefixStr(51)); + EXPECT_EQ("ffff:ffff:ffff:f000::/52", prefixStr(52)); + EXPECT_EQ("ffff:ffff:ffff:f800::/53", prefixStr(53)); + EXPECT_EQ("ffff:ffff:ffff:fc00::/54", prefixStr(54)); + EXPECT_EQ("ffff:ffff:ffff:fe00::/55", prefixStr(55)); + EXPECT_EQ("ffff:ffff:ffff:ff00::/56", prefixStr(56)); + + EXPECT_EQ("ffff:ffff:ffff:ff80::/57", prefixStr(57)); + EXPECT_EQ("ffff:ffff:ffff:ffc0::/58", prefixStr(58)); + EXPECT_EQ("ffff:ffff:ffff:ffe0::/59", prefixStr(59)); + EXPECT_EQ("ffff:ffff:ffff:fff0::/60", prefixStr(60)); + EXPECT_EQ("ffff:ffff:ffff:fff8::/61", prefixStr(61)); + EXPECT_EQ("ffff:ffff:ffff:fffc::/62", prefixStr(62)); + EXPECT_EQ("ffff:ffff:ffff:fffe::/63", prefixStr(63)); + EXPECT_EQ("ffff:ffff:ffff:ffff::/64", prefixStr(64)); + + EXPECT_EQ("ffff:ffff:ffff:ffff:8000::/65", prefixStr(65)); + EXPECT_EQ("ffff:ffff:ffff:ffff:c000::/66", prefixStr(66)); + EXPECT_EQ("ffff:ffff:ffff:ffff:e000::/67", prefixStr(67)); + EXPECT_EQ("ffff:ffff:ffff:ffff:f000::/68", prefixStr(68)); + EXPECT_EQ("ffff:ffff:ffff:ffff:f800::/69", prefixStr(69)); + EXPECT_EQ("ffff:ffff:ffff:ffff:fc00::/70", prefixStr(70)); + EXPECT_EQ("ffff:ffff:ffff:ffff:fe00::/71", prefixStr(71)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ff00::/72", prefixStr(72)); + + EXPECT_EQ("ffff:ffff:ffff:ffff:ff80::/73", prefixStr(73)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffc0::/74", prefixStr(74)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffe0::/75", prefixStr(75)); + EXPECT_EQ("ffff:ffff:ffff:ffff:fff0::/76", prefixStr(76)); + EXPECT_EQ("ffff:ffff:ffff:ffff:fff8::/77", prefixStr(77)); + EXPECT_EQ("ffff:ffff:ffff:ffff:fffc::/78", prefixStr(78)); + EXPECT_EQ("ffff:ffff:ffff:ffff:fffe::/79", prefixStr(79)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff::/80", prefixStr(80)); + + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:8000::/81", prefixStr(81)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:c000::/82", prefixStr(82)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:e000::/83", prefixStr(83)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:f000::/84", prefixStr(84)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:f800::/85", prefixStr(85)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fc00::/86", prefixStr(86)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fe00::/87", prefixStr(87)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ff00::/88", prefixStr(88)); + + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ff80::/89", prefixStr(89)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffc0::/90", prefixStr(90)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffe0::/91", prefixStr(91)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fff0::/92", prefixStr(92)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fff8::/93", prefixStr(93)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fffc::/94", prefixStr(94)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:fffe::/95", prefixStr(95)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff::/96", prefixStr(96)); + + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:8000:0/97", prefixStr(97)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:c000:0/98", prefixStr(98)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:e000:0/99", prefixStr(99)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:f000:0/100", prefixStr(100)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:f800:0/101", prefixStr(101)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fc00:0/102", prefixStr(102)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fe00:0/103", prefixStr(103)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ff00:0/104", prefixStr(104)); + + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ff80:0/105", prefixStr(105)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffc0:0/106", prefixStr(106)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffe0:0/107", prefixStr(107)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fff0:0/108", prefixStr(108)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fff8:0/109", prefixStr(109)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fffc:0/110", prefixStr(110)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:fffe:0/111", prefixStr(111)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0/112", prefixStr(112)); + + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:8000/113", prefixStr(113)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:c000/114", prefixStr(114)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:e000/115", prefixStr(115)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:f000/116", prefixStr(116)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:f800/117", prefixStr(117)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fc00/118", prefixStr(118)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fe00/119", prefixStr(119)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00/120", prefixStr(120)); + + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff80/121", prefixStr(121)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffc0/122", prefixStr(122)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffe0/123", prefixStr(123)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0/124", prefixStr(124)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff8/125", prefixStr(125)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc/126", prefixStr(126)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe/127", prefixStr(127)); + EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128", prefixStr(128)); +} + +TEST(IPPrefixTest, TruncationOther) { + const struct { + const char* ip; + const int cidrLen; + const char* ipTruncated; + } testExpectations[] = { + {"192.0.2.0", 24, "192.0.2.0"}, + {"192.0.2.0", 23, "192.0.2.0"}, + {"192.0.2.0", 22, "192.0.0.0"}, + {"192.0.2.0", 1, "128.0.0.0"}, + {"2001:db8:cafe:d00d::", 56, "2001:db8:cafe:d000::"}, + {"2001:db8:cafe:d00d::", 48, "2001:db8:cafe::"}, + {"2001:db8:cafe:d00d::", 47, "2001:db8:cafe::"}, + {"2001:db8:cafe:d00d::", 46, "2001:db8:cafc::"}, + }; + + for (const auto& expectation : testExpectations) { + IPAddress ip; + EXPECT_TRUE(IPAddress::forString(expectation.ip, &ip)) + << "Failed to parse IP address " << expectation.ip; + + IPAddress ipTruncated; + EXPECT_TRUE(IPAddress::forString(expectation.ipTruncated, &ipTruncated)) + << "Failed to parse IP address " << expectation.ipTruncated; + + IPPrefix prefix(ip, expectation.cidrLen); + + EXPECT_EQ(expectation.cidrLen, prefix.length()) + << "Unexpected cidrLen " << expectation.cidrLen; + EXPECT_EQ(ipTruncated, prefix.ip()) + << "Unexpected IP truncation: " << prefix.ip() << ", expected: " << ipTruncated; + } +} + +TEST(IPPrefixTest, GamutOfOperators) { + const std::vector> kExpectations{ + {EQ, IPPrefix(), IPPrefix()}, + {EQ, IPPrefix(IPAddress(IPV4_ANY), 0), IPPrefix(IPAddress(IPV4_ANY), 0)}, + {EQ, IPPrefix(IPAddress(IPV4_ANY), IPV4_ADDR_BITS), IPPrefix(IPAddress(IPV4_ANY))}, + {EQ, IPPrefix(IPAddress(IPV6_ANY), 0), IPPrefix(IPAddress(IPV6_ANY), 0)}, + {EQ, IPPrefix(IPAddress(IPV6_ANY), IPV6_ADDR_BITS), IPPrefix(IPAddress(IPV6_ANY))}, + // Needlessly fully-specified IPv6 link-local address. + {EQ, IPPrefix(IPAddress(FE80_1)), IPPrefix(IPAddress(FE80_1, 0), IPV6_ADDR_BITS)}, + // Different IPv6 link-local addresses within the same /64, no scoped_id: same /64. + {EQ, IPPrefix(IPAddress(FE80_1), 64), IPPrefix(IPAddress(FE80_2), 64)}, + // Different IPv6 link-local address within the same /64, same scoped_id: same /64. + {EQ, IPPrefix(IPAddress(FE80_1, 17), 64), IPPrefix(IPAddress(FE80_2, 17), 64)}, + // Unspecified < IPv4. + {LT, IPPrefix(), IPPrefix(IPAddress(IPV4_ANY), 0)}, + // Same IPv4 base address sorts by prefix length. + {LT, IPPrefix(IPAddress(IPV4_ANY), 0), IPPrefix(IPAddress(IPV4_ANY), 1)}, + {LT, IPPrefix(IPAddress(IPV4_ANY), 1), IPPrefix(IPAddress(IPV4_ANY), IPV4_ADDR_BITS)}, + // Truncation means each base IPv4 address is different. + {LT, IPPrefix(IPAddress(IPV4_ONES), 0), IPPrefix(IPAddress(IPV4_ONES), 1)}, + {LT, IPPrefix(IPAddress(IPV4_ONES), 1), IPPrefix(IPAddress(IPV4_ONES), IPV4_ADDR_BITS)}, + // Sort by base IPv4 addresses first. + {LT, IPPrefix(IPAddress(IPV4_ANY), 0), IPPrefix(IPAddress::forString("0.0.0.1"))}, + {LT, IPPrefix(IPAddress(IPV4_ANY), 1), IPPrefix(IPAddress::forString("0.0.0.1"))}, + {LT, IPPrefix(IPAddress(IPV4_ANY), 24), IPPrefix(IPAddress::forString("0.0.0.1"))}, + // IPv4 < IPv6. + {LT, IPPrefix(IPAddress(IPV4_ANY), 0), IPPrefix(IPAddress(IPV6_ANY), 0)}, + {LT, IPPrefix(IPAddress(IPV4_ONES)), IPPrefix(IPAddress(IPV6_ANY))}, + // Unspecified < IPv6. + {LT, IPPrefix(), IPPrefix(IPAddress(IPV6_ANY), 0)}, + // Same IPv6 base address sorts by prefix length. + {LT, IPPrefix(IPAddress(IPV6_ANY), 0), IPPrefix(IPAddress(IPV6_ANY), 1)}, + {LT, IPPrefix(IPAddress(IPV6_ANY), 1), IPPrefix(IPAddress(IPV6_ANY), IPV6_ADDR_BITS)}, + // Truncation means each base IPv6 address is different. + {LT, IPPrefix(IPAddress(IPV6_ONES), 0), IPPrefix(IPAddress(IPV6_ONES), 1)}, + {LT, IPPrefix(IPAddress(IPV6_ONES), 1), IPPrefix(IPAddress(IPV6_ONES), IPV6_ADDR_BITS)}, + // Different IPv6 link-local address in same /64, different scoped_id: different /64. + {LT, IPPrefix(IPAddress(FE80_1, 17), 64), IPPrefix(IPAddress(FE80_2, 22), 64)}, + {LT, IPPrefix(IPAddress(FE80_1, 17), 64), IPPrefix(IPAddress(FE80_1, 18), 64)}, + {LT, IPPrefix(IPAddress(FE80_1, 18), 64), IPPrefix(IPAddress(FE80_1, 19), 64)}, + }; + + size_t tests_run = 0; + for (const auto& expectation : kExpectations) { + SCOPED_TRACE(expectation.toString()); + EXPECT_NO_FATAL_FAILURE(testGamutOfOperators(expectation)); + tests_run++; + } + EXPECT_EQ(kExpectations.size(), tests_run); +} + +TEST(IPSockAddrTest, GamutOfOperators) { + const std::vector> kExpectations{ + {EQ, IPSockAddr(), IPSockAddr()}, + {EQ, IPSockAddr(IPAddress(IPV4_ANY)), IPSockAddr(IPAddress(IPV4_ANY), 0)}, + {EQ, IPSockAddr(IPAddress(IPV6_ANY)), IPSockAddr(IPAddress(IPV6_ANY), 0)}, + {EQ, IPSockAddr(IPAddress(FE80_1), 80), IPSockAddr(IPAddress(FE80_1), 80)}, + {EQ, IPSockAddr(IPAddress(FE80_1, 17)), IPSockAddr(IPAddress(FE80_1, 17), 0)}, + {LT, IPSockAddr(IPAddress(IPV4_ANY), 0), IPSockAddr(IPAddress(IPV4_ANY), 1)}, + {LT, IPSockAddr(IPAddress(IPV4_ANY), 53), IPSockAddr(IPAddress(IPV4_ANY), 123)}, + {LT, IPSockAddr(IPAddress(IPV4_ONES), 123), IPSockAddr(IPAddress(IPV6_ANY), 53)}, + {LT, IPSockAddr(IPAddress(IPV6_ANY), 0), IPSockAddr(IPAddress(IPV6_ANY), 1)}, + {LT, IPSockAddr(IPAddress(IPV6_ANY), 53), IPSockAddr(IPAddress(IPV6_ANY), 123)}, + {LT, IPSockAddr(IPAddress(FE80_1), 80), IPSockAddr(IPAddress(FE80_1, 17), 80)}, + {LT, IPSockAddr(IPAddress(FE80_1, 17), 80), IPSockAddr(IPAddress(FE80_1, 22), 80)}, + }; + + size_t tests_run = 0; + for (const auto& expectation : kExpectations) { + SCOPED_TRACE(expectation.toString()); + EXPECT_NO_FATAL_FAILURE(testGamutOfOperators(expectation)); + tests_run++; + } + EXPECT_EQ(kExpectations.size(), tests_run); +} + +TEST(IPSockAddrTest, toString) { + EXPECT_EQ(":0", IPSockAddr().toString()); + EXPECT_EQ("0.0.0.0:0", IPSockAddr(IPAddress(IPV4_ANY)).toString()); + EXPECT_EQ("255.255.255.255:67", IPSockAddr(IPAddress(IPV4_ONES), 67).toString()); + EXPECT_EQ("[::]:0", IPSockAddr(IPAddress(IPV6_ANY)).toString()); + EXPECT_EQ("[::1]:53", IPSockAddr(IPAddress(IPV6_LOOPBACK), 53).toString()); + EXPECT_EQ("[fe80::1]:0", IPSockAddr(IPAddress(FE80_1)).toString()); + EXPECT_EQ("[fe80::2%17]:123", IPSockAddr(IPAddress(FE80_2, 17), 123).toString()); +} + +TEST(CompatIPDataTest, ConversionsClearUnneededValues) { + const uint32_t idx = 17; + const IPSockAddr linkLocalNtpSockaddr(IPAddress(FE80_2, idx), 123); + EXPECT_EQ(IPAddress(FE80_2, idx), linkLocalNtpSockaddr.ip()); + // IPSockAddr(IPSockaddr.ip()) see the port cleared. + EXPECT_EQ(0, IPSockAddr(linkLocalNtpSockaddr.ip()).port()); + const IPPrefix linkLocalPrefix(linkLocalNtpSockaddr.ip(), 64); + EXPECT_EQ(IPAddress(FE80, idx), linkLocalPrefix.ip()); + // IPPrefix(IPPrefix.ip()) see the CIDR length cleared. + EXPECT_EQ(IPV6_ADDR_BITS, IPPrefix(linkLocalPrefix.ip()).length()); +} + +} // namespace +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/Log.cpp b/staticlibs/netd/libnetdutils/Log.cpp new file mode 100644 index 0000000000..d2ce98f094 --- /dev/null +++ b/staticlibs/netd/libnetdutils/Log.cpp @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2018 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. + */ + +#include "netdutils/Log.h" +#include "netdutils/Slice.h" + +#include +#include +#include +#include +#include + +#include +#include + +using ::android::base::Join; +using ::android::base::StringPrintf; + +namespace android { +namespace netdutils { + +namespace { + +std::string makeTimestampedEntry(const std::string& entry) { + using ::std::chrono::duration_cast; + using ::std::chrono::milliseconds; + using ::std::chrono::system_clock; + + std::stringstream tsEntry; + const auto now = system_clock::now(); + const auto time_sec = system_clock::to_time_t(now); + tsEntry << std::put_time(std::localtime(&time_sec), "%m-%d %H:%M:%S.") << std::setw(3) + << std::setfill('0') + << duration_cast(now - system_clock::from_time_t(time_sec)).count() << " " + << entry; + + return tsEntry.str(); +} + +} // namespace + +std::string LogEntry::toString() const { + std::vector text; + + if (!mMsg.empty()) text.push_back(mMsg); + if (!mFunc.empty()) { + text.push_back(StringPrintf("%s(%s)", mFunc.c_str(), Join(mArgs, ", ").c_str())); + } + if (!mReturns.empty()) { + text.push_back("->"); + text.push_back(StringPrintf("(%s)", Join(mReturns, ", ").c_str())); + } + if (!mUid.empty()) text.push_back(mUid); + if (!mDuration.empty()) text.push_back(StringPrintf("(%s)", mDuration.c_str())); + + return Join(text, " "); +} + +LogEntry& LogEntry::message(const std::string& message) { + mMsg = message; + return *this; +} + +LogEntry& LogEntry::function(const std::string& function_name) { + mFunc = function_name; + return *this; +} + +LogEntry& LogEntry::prettyFunction(const std::string& pretty_function) { + // __PRETTY_FUNCTION__ generally seems to be of the form: + // + // qualifed::returnType qualified::function(args...) + // + // where the qualified forms include "(anonymous namespace)" in the + // "::"-delimited list and keywords like "virtual" (where applicable). + // + // Here we try to convert strings like: + // + // virtual binder::Status android::net::NetdNativeService::isAlive(bool *) + // netdutils::LogEntry android::netd::(anonymous namespace)::AAA::BBB::function() + // + // into just "NetdNativeService::isAlive" or "BBB::function". Note that + // without imposing convention, how to easily identify any namespace/class + // name boundary is not obvious. + const size_t endFuncName = pretty_function.rfind('('); + const size_t precedingSpace = pretty_function.rfind(' ', endFuncName); + size_t substrStart = (precedingSpace != std::string::npos) ? precedingSpace + 1 : 0; + + const size_t beginFuncName = pretty_function.rfind("::", endFuncName); + if (beginFuncName != std::string::npos && substrStart < beginFuncName) { + const size_t previousNameBoundary = pretty_function.rfind("::", beginFuncName - 1); + if (previousNameBoundary < beginFuncName && substrStart < previousNameBoundary) { + substrStart = previousNameBoundary + 2; + } else { + substrStart = beginFuncName + 2; + } + } + + mFunc = pretty_function.substr(substrStart, endFuncName - substrStart); + return *this; +} + +LogEntry& LogEntry::arg(const std::string& val) { + mArgs.push_back(val.empty() ? "\"\"" : val); + return *this; +} + +template <> +LogEntry& LogEntry::arg<>(bool val) { + mArgs.push_back(val ? "true" : "false"); + return *this; +} + +LogEntry& LogEntry::arg(const std::vector& val) { + mArgs.push_back(StringPrintf("[%s]", Join(val, ", ").c_str())); + return *this; +} + +LogEntry& LogEntry::arg(const std::vector& val) { + mArgs.push_back('{' + toHex(makeSlice(val)) + '}'); + return *this; +} + +LogEntry& LogEntry::arg(const std::vector& val) { + mArgs.push_back(StringPrintf("[%s]", Join(val, ", ").c_str())); + return *this; +} + +LogEntry& LogEntry::returns(const std::string& rval) { + mReturns.push_back(rval); + return *this; +} + +LogEntry& LogEntry::returns(bool rval) { + mReturns.push_back(rval ? "true" : "false"); + return *this; +} + +LogEntry& LogEntry::returns(const Status& status) { + mReturns.push_back(status.msg()); + return *this; +} + +LogEntry& LogEntry::withUid(uid_t uid) { + mUid = StringPrintf("(uid=%d)", uid); + return *this; +} + +LogEntry& LogEntry::withAutomaticDuration() { + using ms = std::chrono::duration>; + + const std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); + std::stringstream duration; + duration << std::setprecision(1) << std::chrono::duration_cast(end - mStart).count() + << "ms"; + mDuration = duration.str(); + return *this; +} + +LogEntry& LogEntry::withDuration(const std::string& duration) { + mDuration = duration; + return *this; +} + +Log::~Log() { + // TODO: dump the last N entries to the android log for possible posterity. + info(LogEntry().function(__FUNCTION__)); +} + +void Log::forEachEntry(const std::function& perEntryFn) const { + // We make a (potentially expensive) copy of the log buffer (including + // all strings), in case the |perEntryFn| takes its sweet time. + std::deque entries; + { + std::shared_lock guard(mLock); + entries.assign(mEntries.cbegin(), mEntries.cend()); + } + + for (const std::string& entry : entries) perEntryFn(entry); +} + +void Log::record(Log::Level lvl, const std::string& entry) { + switch (lvl) { + case Level::LOG: + break; + case Level::INFO: + ALOG(LOG_INFO, mTag.c_str(), "%s", entry.c_str()); + break; + case Level::WARN: + ALOG(LOG_WARN, mTag.c_str(), "%s", entry.c_str()); + break; + case Level::ERROR: + ALOG(LOG_ERROR, mTag.c_str(), "%s", entry.c_str()); + break; + } + + std::lock_guard guard(mLock); + mEntries.push_back(makeTimestampedEntry(entry)); + while (mEntries.size() > mMaxEntries) mEntries.pop_front(); +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/LogTest.cpp b/staticlibs/netd/libnetdutils/LogTest.cpp new file mode 100644 index 0000000000..127056091b --- /dev/null +++ b/staticlibs/netd/libnetdutils/LogTest.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2018 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. + */ + +#include + +#include "netdutils/Log.h" + +android::netdutils::LogEntry globalFunctionName() { + return android::netdutils::LogEntry().function(__FUNCTION__); +} + +android::netdutils::LogEntry globalPrettyFunctionName() { + return android::netdutils::LogEntry().prettyFunction(__PRETTY_FUNCTION__); +} + +namespace android { +namespace netdutils { + +namespace { + +LogEntry functionName() { + return LogEntry().function(__FUNCTION__); +} + +LogEntry prettyFunctionName() { + return LogEntry().prettyFunction(__PRETTY_FUNCTION__); +} + +} // namespace + +class AAA { + public: + AAA() = default; + + LogEntry functionName() { + return LogEntry().function(__FUNCTION__); + } + + LogEntry prettyFunctionName() { + return LogEntry().prettyFunction(__PRETTY_FUNCTION__); + } + + class BBB { + public: + BBB() = default; + + LogEntry functionName() { + return LogEntry().function(__FUNCTION__); + } + + LogEntry prettyFunctionName() { + return LogEntry().prettyFunction(__PRETTY_FUNCTION__); + } + }; +}; + +TEST(LogEntryTest, Empty) { + LogEntry empty; + EXPECT_EQ("", empty.toString()); +} + +TEST(LogEntryTest, GlobalFunction) { + EXPECT_EQ("globalFunctionName()", ::globalFunctionName().toString()); +} + +TEST(LogEntryTest, GlobalPrettyFunction) { + EXPECT_EQ("globalPrettyFunctionName()", ::globalPrettyFunctionName().toString()); +} + +TEST(LogEntryTest, UnnamedNamespaceFunction) { + const LogEntry entry = functionName(); + EXPECT_EQ("functionName()", entry.toString()); +} + +TEST(LogEntryTest, UnnamedNamespacePrettyFunction) { + const LogEntry entry = prettyFunctionName(); + EXPECT_EQ("prettyFunctionName()", entry.toString()); +} + +TEST(LogEntryTest, ClassFunction) { + const LogEntry entry = AAA().functionName(); + EXPECT_EQ("functionName()", entry.toString()); +} + +TEST(LogEntryTest, ClassPrettyFunction) { + const LogEntry entry = AAA().prettyFunctionName(); + EXPECT_EQ("AAA::prettyFunctionName()", entry.toString()); +} + +TEST(LogEntryTest, InnerClassFunction) { + const LogEntry entry = AAA::BBB().functionName(); + EXPECT_EQ("functionName()", entry.toString()); +} + +TEST(LogEntryTest, InnerClassPrettyFunction) { + const LogEntry entry = AAA::BBB().prettyFunctionName(); + EXPECT_EQ("BBB::prettyFunctionName()", entry.toString()); +} + +TEST(LogEntryTest, PrintChainedArguments) { + const LogEntry entry = LogEntry() + .function("testFunc") + .arg("hello") + .arg(42) + .arg(true); + EXPECT_EQ("testFunc(hello, 42, true)", entry.toString()); +} + +TEST(LogEntryTest, PrintIntegralTypes) { + const LogEntry entry = LogEntry() + .function("testFunc") + .arg('A') + .arg(100U) + .arg(-1000LL); + EXPECT_EQ("testFunc(65, 100, -1000)", entry.toString()); +} + +TEST(LogEntryTest, PrintHex) { + const std::vector buf{0xDE, 0xAD, 0xBE, 0xEF}; + const LogEntry entry = LogEntry().function("testFunc").arg(buf); + EXPECT_EQ("testFunc({deadbeef})", entry.toString()); +} + +TEST(LogEntryTest, PrintArgumentPack) { + const LogEntry entry = LogEntry().function("testFunc").args("hello", 42, false); + EXPECT_EQ("testFunc(hello, 42, false)", entry.toString()); +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/MemBlockTest.cpp b/staticlibs/netd/libnetdutils/MemBlockTest.cpp new file mode 100644 index 0000000000..6455a7e01b --- /dev/null +++ b/staticlibs/netd/libnetdutils/MemBlockTest.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2018 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. + */ + +#include +#include +#include + +#include + +#include "netdutils/MemBlock.h" +#include "netdutils/Slice.h" + +namespace android { +namespace netdutils { + +namespace { + +constexpr unsigned DNS_PACKET_SIZE = 512; +constexpr int ARBITRARY_VALUE = 0x55; + +MemBlock makeArbitraryMemBlock(size_t len) { + MemBlock result(len); + // Do some fictional work before returning. + for (Slice slice = result.get(); !slice.empty(); slice = drop(slice, 1)) { + slice.base()[0] = ARBITRARY_VALUE; + } + return result; +} + +void checkAllZeros(Slice slice) { + for (; !slice.empty(); slice = drop(slice, 1)) { + EXPECT_EQ(0U, slice.base()[0]); + } +} + +void checkArbitraryMemBlock(const MemBlock& block, size_t expectedSize) { + Slice slice = block.get(); + EXPECT_EQ(expectedSize, slice.size()); + EXPECT_NE(nullptr, slice.base()); + for (; !slice.empty(); slice = drop(slice, 1)) { + EXPECT_EQ(ARBITRARY_VALUE, slice.base()[0]); + } +} + +void checkHelloMello(Slice dest, Slice src) { + EXPECT_EQ('h', dest.base()[0]); + EXPECT_EQ('e', dest.base()[1]); + EXPECT_EQ('l', dest.base()[2]); + EXPECT_EQ('l', dest.base()[3]); + EXPECT_EQ('o', dest.base()[4]); + + src.base()[0] = 'm'; + EXPECT_EQ('h', dest.base()[0]); +} + +} // namespace + +TEST(MemBlockTest, Empty) { + MemBlock empty; + EXPECT_TRUE(empty.get().empty()); + EXPECT_EQ(nullptr, empty.get().base()); +} + +TEST(MemBlockTest, ExplicitZero) { + MemBlock zero(0); + EXPECT_TRUE(zero.get().empty()); + EXPECT_EQ(nullptr, zero.get().base()); +} + +TEST(MemBlockTest, BasicAllocation) { + MemBlock dnsPacket(DNS_PACKET_SIZE); + Slice slice = dnsPacket.get(); + EXPECT_EQ(DNS_PACKET_SIZE, slice.size()); + // Verify the space is '\0'-initialized. + ASSERT_NO_FATAL_FAILURE(checkAllZeros(slice)); + EXPECT_NE(nullptr, slice.base()); +} + +TEST(MemBlockTest, MoveConstruction) { + MemBlock block(makeArbitraryMemBlock(DNS_PACKET_SIZE)); + ASSERT_NO_FATAL_FAILURE(checkArbitraryMemBlock(block, DNS_PACKET_SIZE)); +} + +TEST(MemBlockTest, MoveAssignmentOrConstruction) { + MemBlock block = makeArbitraryMemBlock(DNS_PACKET_SIZE); + ASSERT_NO_FATAL_FAILURE(checkArbitraryMemBlock(block, DNS_PACKET_SIZE)); +} + +TEST(MemBlockTest, StdMoveAssignment) { + constexpr unsigned SIZE = 10; + + MemBlock block; + EXPECT_TRUE(block.get().empty()); + EXPECT_EQ(nullptr, block.get().base()); + + { + MemBlock block2 = makeArbitraryMemBlock(SIZE); + EXPECT_EQ(SIZE, block2.get().size()); + // More fictional work. + for (unsigned i = 0; i < SIZE; i++) { + block2.get().base()[i] = i; + } + block = std::move(block2); + } + + EXPECT_EQ(SIZE, block.get().size()); + for (unsigned i = 0; i < SIZE; i++) { + EXPECT_EQ(i, block.get().base()[i]); + } +} + +TEST(MemBlockTest, ConstructionFromSlice) { + uint8_t data[] = {'h', 'e', 'l', 'l', 'o'}; + Slice dataSlice(Slice(data, sizeof(data) / sizeof(data[0]))); + + MemBlock dataCopy(dataSlice); + ASSERT_NO_FATAL_FAILURE(checkHelloMello(dataCopy.get(), dataSlice)); +} + +TEST(MemBlockTest, ImplicitCastToSlice) { + uint8_t data[] = {'h', 'e', 'l', 'l', 'o'}; + Slice dataSlice(Slice(data, sizeof(data) / sizeof(data[0]))); + + MemBlock dataCopy(dataSlice.size()); + // NOTE: no explicit MemBlock::get(). + // Verify the space is '\0'-initialized. + ASSERT_NO_FATAL_FAILURE(checkAllZeros(dataCopy)); + copy(dataCopy, dataSlice); + ASSERT_NO_FATAL_FAILURE(checkHelloMello(dataCopy, dataSlice)); +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/Netfilter.cpp b/staticlibs/netd/libnetdutils/Netfilter.cpp new file mode 100644 index 0000000000..bb43de0ab6 --- /dev/null +++ b/staticlibs/netd/libnetdutils/Netfilter.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2017 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. + */ + +#include +#include +#include +#include +#include + +#include "netdutils/Netfilter.h" + +std::ostream& operator<<(std::ostream& os, const nfgenmsg& msg) { + return os << std::hex << "nfgenmsg[" + << "family: 0x" << static_cast(msg.nfgen_family) << ", version: 0x" + << static_cast(msg.version) << ", res_id: 0x" << ntohs(msg.res_id) << "]" + << std::dec; +} diff --git a/staticlibs/netd/libnetdutils/Netlink.cpp b/staticlibs/netd/libnetdutils/Netlink.cpp new file mode 100644 index 0000000000..824c0f224d --- /dev/null +++ b/staticlibs/netd/libnetdutils/Netlink.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2017 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. + */ + +#include +#include + +#include "netdutils/Math.h" +#include "netdutils/Netlink.h" + +namespace android { +namespace netdutils { + +void forEachNetlinkMessage(const Slice buf, + const std::function& onMsg) { + Slice tail = buf; + while (tail.size() >= sizeof(nlmsghdr)) { + nlmsghdr hdr = {}; + extract(tail, hdr); + const auto len = std::max(hdr.nlmsg_len, sizeof(hdr)); + onMsg(hdr, drop(take(tail, len), sizeof(hdr))); + tail = drop(tail, align(len, 2)); + } +} + +void forEachNetlinkAttribute(const Slice buf, + const std::function& onAttr) { + Slice tail = buf; + while (tail.size() >= sizeof(nlattr)) { + nlattr hdr = {}; + extract(tail, hdr); + const auto len = std::max(hdr.nla_len, sizeof(hdr)); + onAttr(hdr, drop(take(tail, len), sizeof(hdr))); + tail = drop(tail, align(len, 2)); + } +} + +} // namespace netdutils +} // namespace android + +bool operator==(const sockaddr_nl& lhs, const sockaddr_nl& rhs) { + return (lhs.nl_family == rhs.nl_family) && (lhs.nl_pid == rhs.nl_pid) && + (lhs.nl_groups == rhs.nl_groups); +} + +bool operator!=(const sockaddr_nl& lhs, const sockaddr_nl& rhs) { + return !(lhs == rhs); +} + +std::ostream& operator<<(std::ostream& os, const nlmsghdr& hdr) { + return os << std::hex << "nlmsghdr[" + << "len: 0x" << hdr.nlmsg_len << ", type: 0x" << hdr.nlmsg_type << ", flags: 0x" + << hdr.nlmsg_flags << ", seq: 0x" << hdr.nlmsg_seq << ", pid: 0x" << hdr.nlmsg_pid + << "]" << std::dec; +} + +std::ostream& operator<<(std::ostream& os, const nlattr& attr) { + return os << std::hex << "nlattr[" + << "len: 0x" << attr.nla_len << ", type: 0x" << attr.nla_type << "]" << std::dec; +} + +std::ostream& operator<<(std::ostream& os, const sockaddr_nl& addr) { + return os << std::hex << "sockaddr_nl[" + << "family: " << addr.nl_family << ", pid: " << addr.nl_pid + << ", groups: " << addr.nl_groups << "]" << std::dec; +} diff --git a/staticlibs/netd/libnetdutils/Slice.cpp b/staticlibs/netd/libnetdutils/Slice.cpp new file mode 100644 index 0000000000..7a07d477e7 --- /dev/null +++ b/staticlibs/netd/libnetdutils/Slice.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2017 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. + */ + +#include + +#include "netdutils/Slice.h" + +namespace android { +namespace netdutils { +namespace { + +// Convert one byte to a two character hexadecimal string +const std::string toHex(uint8_t byte) { + const std::array kLookup = { + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}}; + return {kLookup[byte >> 4], kLookup[byte & 0xf]}; +} + +} // namespace + +std::string toString(const Slice s) { + return std::string(reinterpret_cast(s.base()), s.size()); +} + +std::string toHex(const Slice s, int wrap) { + Slice tail = s; + int count = 0; + std::stringstream ss; + while (!tail.empty()) { + uint8_t byte = 0; + extract(tail, byte); + ss << toHex(byte); + if ((++count % wrap) == 0) { + ss << "\n"; + } + tail = drop(tail, 1); + } + return ss.str(); +} + +std::ostream& operator<<(std::ostream& os, const Slice& slice) { + return os << std::hex << "Slice[base: " << reinterpret_cast(slice.base()) + << ", limit: " << reinterpret_cast(slice.limit()) << ", size: 0x" + << slice.size() << "]" << std::dec; +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/SliceTest.cpp b/staticlibs/netd/libnetdutils/SliceTest.cpp new file mode 100644 index 0000000000..a4969331bd --- /dev/null +++ b/staticlibs/netd/libnetdutils/SliceTest.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2017 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. + */ + +#include +#include + +#include + +#include "netdutils/Slice.h" +#include "netdutils/Status.h" +#include "netdutils/StatusOr.h" + +namespace android { +namespace netdutils { + +class SliceTest : public testing::Test { + protected: + std::array mRaw = {}; +}; + +TEST_F(SliceTest, smoke) { + Slice s1 = makeSlice(mRaw); + Slice s2 = makeSlice(mRaw); + auto p = split(s1, 14); + s2 = p.first; // avoid warn-unused error + std::stringstream ss; + ss << Slice(); + EXPECT_EQ("Slice[base: 0x0, limit: 0x0, size: 0x0]", ss.str()); + constexpr size_t kBytes = 14; + EXPECT_EQ(s1.base(), take(s1, kBytes).base()); + EXPECT_EQ(kBytes, take(s1, kBytes).size()); + EXPECT_EQ(s1.base() + kBytes, drop(s1, kBytes).base()); + EXPECT_EQ(s1.size() - kBytes, drop(s1, kBytes).size()); + double a = 0; + double b = 0; + int c = 0; + EXPECT_EQ(sizeof(a), extract(s1, a)); + EXPECT_EQ(sizeof(a) + sizeof(b), extract(s1, a, b)); + EXPECT_EQ(sizeof(a) + sizeof(b) + sizeof(c), extract(s1, a, b, c)); +} + +TEST_F(SliceTest, constructor) { + // Expect the following lines to compile + Slice s1 = makeSlice(mRaw); + Slice s2(s1); + Slice s3 = s2; + const Slice s4(s3); + const Slice s5 = s4; + s3 = s5; + Slice s6(mRaw.data(), mRaw.size()); + Slice s7(mRaw.data(), mRaw.data() + mRaw.size()); + struct { + int a; + double b; + float c; + } anon; + makeSlice(anon); + EXPECT_EQ(reinterpret_cast(mRaw.data()), s1.base()); + EXPECT_EQ(reinterpret_cast(mRaw.data()) + mRaw.size(), s1.limit()); + EXPECT_EQ(mRaw.size(), s1.size()); + EXPECT_FALSE(mRaw.empty()); + EXPECT_TRUE(Slice().empty()); + EXPECT_TRUE(Slice(nullptr, static_cast(0)).empty()); + EXPECT_TRUE(Slice(nullptr, nullptr).empty()); +} + +TEST_F(SliceTest, extract) { + struct A { + int a, b; + bool operator==(const A& other) const { return a == other.a && b == other.b; } + }; + struct B { + char str[12]; + bool b; + int i; + bool operator==(const B& other) const { + return b == other.b && i == other.i && 0 == strncmp(str, other.str, 12); + } + }; + + A origA1 = {1, 2}; + A origA2 = {3, 4}; + B origB = {"hello world", true, 1234}; + + // Populate buffer for extracting. + Slice buffer = makeSlice(mRaw); + copy(buffer, makeSlice(origA1)); + copy(drop(buffer, sizeof(origA1)), makeSlice(origB)); + copy(drop(buffer, sizeof(origA1) + sizeof(origB)), makeSlice(origA2)); + + { + // Non-variadic extract + A a1{}; + size_t len = extract(buffer, a1); + EXPECT_EQ(sizeof(A), len); + EXPECT_EQ(origA1, a1); + } + + { + // Variadic extract, 2 destinations + A a1{}; + B b{}; + size_t len = extract(buffer, a1, b); + EXPECT_EQ(sizeof(A) + sizeof(B), len); + EXPECT_EQ(origA1, a1); + EXPECT_EQ(origB, b); + } + + { + // Variadic extract, 3 destinations + A a1{}, a2{}; + B b{}; + size_t len = extract(buffer, a1, b, a2); + EXPECT_EQ(2 * sizeof(A) + sizeof(B), len); + EXPECT_EQ(origA1, a1); + EXPECT_EQ(origB, b); + EXPECT_EQ(origA2, a2); + } +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/Socket.cpp b/staticlibs/netd/libnetdutils/Socket.cpp new file mode 100644 index 0000000000..e962b6e5d3 --- /dev/null +++ b/staticlibs/netd/libnetdutils/Socket.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2017 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. + */ + +#include + +#include "netdutils/Slice.h" +#include "netdutils/Socket.h" + +namespace android { +namespace netdutils { + +StatusOr toString(const in6_addr& addr) { + std::array out = {}; + auto* rv = inet_ntop(AF_INET6, &addr, out.data(), out.size()); + if (rv == nullptr) { + return statusFromErrno(errno, "inet_ntop() failed"); + } + return std::string(out.data()); +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/SocketOption.cpp b/staticlibs/netd/libnetdutils/SocketOption.cpp new file mode 100644 index 0000000000..023df6e8b9 --- /dev/null +++ b/staticlibs/netd/libnetdutils/SocketOption.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018 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. + */ + +#include "netdutils/SocketOption.h" + +#include +#include +#include +#include + +#include "netdutils/Syscalls.h" + +namespace android { +namespace netdutils { + +Status enableSockopt(Fd sock, int level, int optname) { + auto& sys = sSyscalls.get(); + const int on = 1; + return sys.setsockopt(sock, level, optname, &on, sizeof(on)); +} + +Status enableTcpKeepAlives(Fd sock, unsigned idleTime, unsigned numProbes, unsigned probeInterval) { + RETURN_IF_NOT_OK(enableSockopt(sock, SOL_SOCKET, SO_KEEPALIVE)); + + auto& sys = sSyscalls.get(); + if (idleTime != 0) { + RETURN_IF_NOT_OK(sys.setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &idleTime, sizeof(idleTime))); + } + if (numProbes != 0) { + RETURN_IF_NOT_OK(sys.setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &numProbes, sizeof(numProbes))); + } + if (probeInterval != 0) { + RETURN_IF_NOT_OK(sys.setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &probeInterval, + sizeof(probeInterval))); + } + + return status::ok; +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/Status.cpp b/staticlibs/netd/libnetdutils/Status.cpp new file mode 100644 index 0000000000..acd8f11a36 --- /dev/null +++ b/staticlibs/netd/libnetdutils/Status.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2017 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. + */ + +#include "netdutils/Status.h" + +#include + +#include "android-base/stringprintf.h" + +namespace android { +namespace netdutils { + +Status statusFromErrno(int err, const std::string& msg) { + return Status(err, base::StringPrintf("[%s] : %s", strerror(err), msg.c_str())); +} + +bool equalToErrno(const Status& status, int err) { + return status.code() == err; +} + +std::string toString(const Status& status) { + std::stringstream ss; + ss << status; + return ss.str(); +} + +std::ostream& operator<<(std::ostream& os, const Status& s) { + return os << "Status[code: " << s.code() << ", msg: \"" << s.msg() << "\"]"; +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/StatusTest.cpp b/staticlibs/netd/libnetdutils/StatusTest.cpp new file mode 100644 index 0000000000..4cfc3bbbc3 --- /dev/null +++ b/staticlibs/netd/libnetdutils/StatusTest.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2017 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. + */ + +#include "netdutils/Status.h" +#include "netdutils/StatusOr.h" + +#include + +#include + +namespace android { +namespace netdutils { +namespace { + +TEST(StatusTest, valueSemantics) { + // Default constructor + EXPECT_EQ(status::ok, Status()); + + // Copy constructor + Status status1(1); + Status status2(status1); // NOLINT(performance-unnecessary-copy-initialization) + EXPECT_EQ(1, status2.code()); + + // Copy assignment + Status status3; + status3 = status2; + EXPECT_EQ(1, status3.code()); + + // Same with const objects + const Status status4(4); + const Status status5(status4); // NOLINT(performance-unnecessary-copy-initialization) + Status status6; + status6 = status5; + EXPECT_EQ(4, status6.code()); +} + +TEST(StatusTest, errorMessages) { + Status s(42, "for tea too"); + EXPECT_EQ(42, s.code()); + EXPECT_FALSE(s.ok()); + EXPECT_EQ(s.msg(), "for tea too"); +} + +TEST(StatusOrTest, moveSemantics) { + // Status objects should be cheaply movable. + EXPECT_TRUE(std::is_nothrow_move_constructible::value); + EXPECT_TRUE(std::is_nothrow_move_assignable::value); + + // Should move from a temporary Status (twice) + Status s(Status(Status(42, "move me"))); + EXPECT_EQ(42, s.code()); + EXPECT_EQ(s.msg(), "move me"); + + Status s2(666, "EDAEMON"); + EXPECT_NE(s, s2); + s = s2; // Invokes the move-assignment operator. + EXPECT_EQ(666, s.code()); + EXPECT_EQ(s.msg(), "EDAEMON"); + EXPECT_EQ(s, s2); + + // A moved-from Status can be re-used. + s2 = s; + + // Now both objects are valid. + EXPECT_EQ(666, s.code()); + EXPECT_EQ(s.msg(), "EDAEMON"); + EXPECT_EQ(s, s2); +} + +TEST(StatusTest, ignoredStatus) { + statusFromErrno(ENOTTY, "Not a typewriter, what did you expect?").ignoreError(); +} + +TEST(StatusOrTest, ostream) { + { + StatusOr so(11); + std::stringstream ss; + ss << so; + // TODO: Fix StatusOr to optionally output "value:". + EXPECT_EQ("StatusOr[status: Status[code: 0, msg: \"\"]]", ss.str()); + } + { + StatusOr err(status::undefined); + std::stringstream ss; + ss << err; + EXPECT_EQ("StatusOr[status: Status[code: 2147483647, msg: \"undefined\"]]", ss.str()); + } +} + +} // namespace +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/Syscalls.cpp b/staticlibs/netd/libnetdutils/Syscalls.cpp new file mode 100644 index 0000000000..9f653f70c7 --- /dev/null +++ b/staticlibs/netd/libnetdutils/Syscalls.cpp @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2017 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. + */ + +#include "netdutils/Syscalls.h" + +#include +#include +#include + +namespace android { +namespace netdutils { +namespace { + +// Retry syscall fn as long as it returns -1 with errno == EINTR +template +typename std::result_of::type syscallRetry(FnT fn, Params&&... params) { + auto rv = fn(std::forward(params)...); + while ((rv == -1) && (errno == EINTR)) { + rv = fn(std::forward(params)...); + } + return rv; +} + +} // namespace + +// Production implementation of Syscalls that forwards to libc syscalls. +class RealSyscalls final : public Syscalls { + public: + ~RealSyscalls() override = default; + + StatusOr open(const std::string& pathname, int flags, mode_t mode) const override { + UniqueFd fd(::open(pathname.c_str(), flags, mode)); + if (!isWellFormed(fd)) { + return statusFromErrno(errno, "open(\"" + pathname + "\"...) failed"); + } + return fd; + } + + StatusOr socket(int domain, int type, int protocol) const override { + UniqueFd sock(::socket(domain, type, protocol)); + if (!isWellFormed(sock)) { + return statusFromErrno(errno, "socket() failed"); + } + return sock; + } + + Status getsockname(Fd sock, sockaddr* addr, socklen_t* addrlen) const override { + auto rv = ::getsockname(sock.get(), addr, addrlen); + if (rv == -1) { + return statusFromErrno(errno, "getsockname() failed"); + } + return status::ok; + } + + Status getsockopt(Fd sock, int level, int optname, void* optval, + socklen_t* optlen) const override { + auto rv = ::getsockopt(sock.get(), level, optname, optval, optlen); + if (rv == -1) { + return statusFromErrno(errno, "getsockopt() failed"); + } + return status::ok; + } + + Status setsockopt(Fd sock, int level, int optname, const void* optval, + socklen_t optlen) const override { + auto rv = ::setsockopt(sock.get(), level, optname, optval, optlen); + if (rv == -1) { + return statusFromErrno(errno, "setsockopt() failed"); + } + return status::ok; + } + + Status bind(Fd sock, const sockaddr* addr, socklen_t addrlen) const override { + auto rv = ::bind(sock.get(), addr, addrlen); + if (rv == -1) { + return statusFromErrno(errno, "bind() failed"); + } + return status::ok; + } + + Status connect(Fd sock, const sockaddr* addr, socklen_t addrlen) const override { + auto rv = syscallRetry(::connect, sock.get(), addr, addrlen); + if (rv == -1) { + return statusFromErrno(errno, "connect() failed"); + } + return status::ok; + } + + StatusOr ioctl(Fd sock, unsigned long request, ifreq* ifr) const override { + auto rv = ::ioctl(sock.get(), request, ifr); + if (rv == -1) { + return statusFromErrno(errno, "ioctl() failed"); + } + return *ifr; + } + + StatusOr eventfd(unsigned int initval, int flags) const override { + UniqueFd fd(::eventfd(initval, flags)); + if (!isWellFormed(fd)) { + return statusFromErrno(errno, "eventfd() failed"); + } + return fd; + } + + StatusOr ppoll(pollfd* fds, nfds_t nfds, double timeout) const override { + timespec ts = {}; + ts.tv_sec = timeout; + ts.tv_nsec = (timeout - ts.tv_sec) * 1e9; + auto rv = syscallRetry(::ppoll, fds, nfds, &ts, nullptr); + if (rv == -1) { + return statusFromErrno(errno, "ppoll() failed"); + } + return rv; + } + + StatusOr writev(Fd fd, const std::vector& iov) const override { + auto rv = syscallRetry(::writev, fd.get(), iov.data(), iov.size()); + if (rv == -1) { + return statusFromErrno(errno, "writev() failed"); + } + return rv; + } + + StatusOr write(Fd fd, const Slice buf) const override { + auto rv = syscallRetry(::write, fd.get(), buf.base(), buf.size()); + if (rv == -1) { + return statusFromErrno(errno, "write() failed"); + } + return static_cast(rv); + } + + StatusOr read(Fd fd, const Slice buf) const override { + auto rv = syscallRetry(::read, fd.get(), buf.base(), buf.size()); + if (rv == -1) { + return statusFromErrno(errno, "read() failed"); + } + return Slice(buf.base(), rv); + } + + StatusOr sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst, + socklen_t dstlen) const override { + auto rv = syscallRetry(::sendto, sock.get(), buf.base(), buf.size(), flags, dst, dstlen); + if (rv == -1) { + return statusFromErrno(errno, "sendto() failed"); + } + return static_cast(rv); + } + + StatusOr recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src, + socklen_t* srclen) const override { + auto rv = syscallRetry(::recvfrom, sock.get(), dst.base(), dst.size(), flags, src, srclen); + if (rv == -1) { + return statusFromErrno(errno, "recvfrom() failed"); + } + if (rv == 0) { + return status::eof; + } + return take(dst, rv); + } + + Status shutdown(Fd fd, int how) const override { + auto rv = ::shutdown(fd.get(), how); + if (rv == -1) { + return statusFromErrno(errno, "shutdown() failed"); + } + return status::ok; + } + + Status close(Fd fd) const override { + auto rv = ::close(fd.get()); + if (rv == -1) { + return statusFromErrno(errno, "close() failed"); + } + return status::ok; + } + + StatusOr fopen(const std::string& path, const std::string& mode) const override { + UniqueFile file(::fopen(path.c_str(), mode.c_str())); + if (file == nullptr) { + return statusFromErrno(errno, "fopen(\"" + path + "\", \"" + mode + "\") failed"); + } + return file; + } + + StatusOr fork() const override { + pid_t rv = ::fork(); + if (rv == -1) { + return statusFromErrno(errno, "fork() failed"); + } + return rv; + } + + StatusOr vfprintf(FILE* file, const char* format, va_list ap) const override { + auto rv = ::vfprintf(file, format, ap); + if (rv == -1) { + return statusFromErrno(errno, "vfprintf() failed"); + } + return rv; + } + + StatusOr vfscanf(FILE* file, const char* format, va_list ap) const override { + auto rv = ::vfscanf(file, format, ap); + if (rv == -1) { + return statusFromErrno(errno, "vfscanf() failed"); + } + return rv; + } + + Status fclose(FILE* file) const override { + auto rv = ::fclose(file); + if (rv == -1) { + return statusFromErrno(errno, "fclose() failed"); + } + return status::ok; + } +}; + +SyscallsHolder::~SyscallsHolder() { + delete &get(); +} + +Syscalls& SyscallsHolder::get() { + while (true) { + // memory_order_relaxed gives the compiler and hardware more + // freedom. If we get a stale value (this should only happen + // early in the execution of a program) the exchange code below + // will loop until we get the most current value. + auto* syscalls = mSyscalls.load(std::memory_order_relaxed); + // Common case returns existing syscalls + if (syscalls) { + return *syscalls; + } + + // This code will execute on first get() + std::unique_ptr tmp(new RealSyscalls()); + Syscalls* expected = nullptr; + bool success = mSyscalls.compare_exchange_strong(expected, tmp.get()); + if (success) { + // Ownership was transferred to mSyscalls already, must release() + return *tmp.release(); + } + } +} + +Syscalls& SyscallsHolder::swap(Syscalls& syscalls) { + return *mSyscalls.exchange(&syscalls); +} + +SyscallsHolder sSyscalls; + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/SyscallsTest.cpp b/staticlibs/netd/libnetdutils/SyscallsTest.cpp new file mode 100644 index 0000000000..78ffab5e25 --- /dev/null +++ b/staticlibs/netd/libnetdutils/SyscallsTest.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2017 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. + */ + +#include +#include +#include + +#include + +#include "netdutils/Handle.h" +#include "netdutils/Math.h" +#include "netdutils/MockSyscalls.h" +#include "netdutils/Netfilter.h" +#include "netdutils/Netlink.h" +#include "netdutils/Slice.h" +#include "netdutils/Status.h" +#include "netdutils/StatusOr.h" +#include "netdutils/Syscalls.h" + +using testing::_; +using testing::ByMove; +using testing::Invoke; +using testing::Return; +using testing::StrictMock; + +namespace android { +namespace netdutils { + +class SyscallsTest : public testing::Test { + protected: + StrictMock mSyscalls; +}; + +TEST(syscalls, scopedMock) { + auto& old = sSyscalls.get(); + { + StrictMock s; + EXPECT_EQ(&s, &sSyscalls.get()); + } + EXPECT_EQ(&old, &sSyscalls.get()); +} + +TEST_F(SyscallsTest, open) { + const char kPath[] = "/test/path/please/ignore"; + constexpr Fd kFd(40); + constexpr int kFlags = 883; + constexpr mode_t kMode = 37373; + const auto& sys = sSyscalls.get(); + EXPECT_CALL(mSyscalls, open(kPath, kFlags, kMode)).WillOnce(Return(ByMove(UniqueFd(kFd)))); + EXPECT_CALL(mSyscalls, close(kFd)).WillOnce(Return(status::ok)); + auto result = sys.open(kPath, kFlags, kMode); + EXPECT_EQ(status::ok, result.status()); + EXPECT_EQ(kFd, result.value()); +} + +TEST_F(SyscallsTest, getsockname) { + constexpr Fd kFd(40); + sockaddr_nl expected = {}; + auto& sys = sSyscalls.get(); + + // Success + EXPECT_CALL(mSyscalls, getsockname(kFd, _, _)) + .WillOnce(Invoke([expected](Fd, sockaddr* addr, socklen_t* addrlen) { + memcpy(addr, &expected, sizeof(expected)); + EXPECT_EQ(*addrlen, static_cast(sizeof(expected))); + return status::ok; + })); + const auto result = sys.getsockname(kFd); + EXPECT_TRUE(isOk(result)); + EXPECT_EQ(expected, result.value()); + + // Failure + const Status kError = statusFromErrno(EINVAL, "test"); + EXPECT_CALL(mSyscalls, getsockname(kFd, _, _)).WillOnce(Return(kError)); + EXPECT_EQ(kError, sys.getsockname(kFd).status()); +} + +TEST_F(SyscallsTest, setsockopt) { + constexpr Fd kFd(40); + constexpr int kLevel = 50; + constexpr int kOptname = 70; + sockaddr_nl expected = {}; + auto& sys = sSyscalls.get(); + + // Success + EXPECT_CALL(mSyscalls, setsockopt(kFd, kLevel, kOptname, &expected, sizeof(expected))) + .WillOnce(Return(status::ok)); + EXPECT_EQ(status::ok, sys.setsockopt(kFd, kLevel, kOptname, expected)); + + // Failure + const Status kError = statusFromErrno(EINVAL, "test"); + EXPECT_CALL(mSyscalls, setsockopt(kFd, kLevel, kOptname, &expected, sizeof(expected))) + .WillOnce(Return(kError)); + EXPECT_EQ(kError, sys.setsockopt(kFd, kLevel, kOptname, expected)); +} + +TEST_F(SyscallsTest, getsockopt) { + constexpr Fd kFd(40); + constexpr int kLevel = 50; + constexpr int kOptname = 70; + sockaddr_nl expected = {}; + socklen_t optLen = 0; + auto& sys = sSyscalls.get(); + + // Success + EXPECT_CALL(mSyscalls, getsockopt(kFd, kLevel, kOptname, &expected, &optLen)) + .WillOnce(Return(status::ok)); + EXPECT_EQ(status::ok, sys.getsockopt(kFd, kLevel, kOptname, &expected, &optLen)); + + // Failure + const Status kError = statusFromErrno(EINVAL, "test"); + EXPECT_CALL(mSyscalls, getsockopt(kFd, kLevel, kOptname, &expected, &optLen)) + .WillOnce(Return(kError)); + EXPECT_EQ(kError, sys.getsockopt(kFd, kLevel, kOptname, &expected, &optLen)); +} + +TEST_F(SyscallsTest, bind) { + constexpr Fd kFd(40); + sockaddr_nl expected = {}; + auto& sys = sSyscalls.get(); + + // Success + EXPECT_CALL(mSyscalls, bind(kFd, asSockaddrPtr(&expected), sizeof(expected))) + .WillOnce(Return(status::ok)); + EXPECT_EQ(status::ok, sys.bind(kFd, expected)); + + // Failure + const Status kError = statusFromErrno(EINVAL, "test"); + EXPECT_CALL(mSyscalls, bind(kFd, asSockaddrPtr(&expected), sizeof(expected))) + .WillOnce(Return(kError)); + EXPECT_EQ(kError, sys.bind(kFd, expected)); +} + +TEST_F(SyscallsTest, connect) { + constexpr Fd kFd(40); + sockaddr_nl expected = {}; + auto& sys = sSyscalls.get(); + + // Success + EXPECT_CALL(mSyscalls, connect(kFd, asSockaddrPtr(&expected), sizeof(expected))) + .WillOnce(Return(status::ok)); + EXPECT_EQ(status::ok, sys.connect(kFd, expected)); + + // Failure + const Status kError = statusFromErrno(EINVAL, "test"); + EXPECT_CALL(mSyscalls, connect(kFd, asSockaddrPtr(&expected), sizeof(expected))) + .WillOnce(Return(kError)); + EXPECT_EQ(kError, sys.connect(kFd, expected)); +} + +TEST_F(SyscallsTest, sendto) { + constexpr Fd kFd(40); + constexpr int kFlags = 0; + std::array payload; + const auto slice = makeSlice(payload); + sockaddr_nl expected = {}; + auto& sys = sSyscalls.get(); + + // Success + EXPECT_CALL(mSyscalls, sendto(kFd, slice, kFlags, asSockaddrPtr(&expected), sizeof(expected))) + .WillOnce(Return(slice.size())); + EXPECT_EQ(status::ok, sys.sendto(kFd, slice, kFlags, expected)); +} + +TEST_F(SyscallsTest, recvfrom) { + constexpr Fd kFd(40); + constexpr int kFlags = 0; + std::array payload; + const auto dst = makeSlice(payload); + const auto used = take(dst, 8); + sockaddr_nl expected = {}; + auto& sys = sSyscalls.get(); + + // Success + EXPECT_CALL(mSyscalls, recvfrom(kFd, dst, kFlags, _, _)) + .WillOnce(Invoke( + [expected, used](Fd, const Slice, int, sockaddr* src, socklen_t* srclen) { + *srclen = sizeof(expected); + memcpy(src, &expected, *srclen); + return used; + })); + auto result = sys.recvfrom(kFd, dst, kFlags); + EXPECT_EQ(status::ok, result.status()); + EXPECT_EQ(used, result.value().first); + EXPECT_EQ(expected, result.value().second); +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/ThreadUtilTest.cpp b/staticlibs/netd/libnetdutils/ThreadUtilTest.cpp new file mode 100644 index 0000000000..8fad8b8e5a --- /dev/null +++ b/staticlibs/netd/libnetdutils/ThreadUtilTest.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2019 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. + */ + +#include + +#include +#include +#include + +namespace android::netdutils { + +namespace { + +android::base::expected getThreadName() { + char name[16] = {}; + if (const int ret = pthread_getname_np(pthread_self(), name, sizeof(name)); ret != 0) { + return android::base::unexpected(ret); + } + return std::string(name); +} + +class NoopRun { + public: + explicit NoopRun(const std::string& name = "") : mName(name) { instanceNum++; } + + // Destructor happens in the thread. + ~NoopRun() { + if (checkName) { + auto expected = getThreadName(); + EXPECT_TRUE(expected.has_value()); + EXPECT_EQ(mExpectedName, expected.value()); + } + instanceNum--; + } + + void run() {} + + std::string threadName() { return mName; } + + // Set the expected thread name which will be used to check if it matches the actual thread + // name which is returned from the system call. The check will happen in the destructor. + void setExpectedName(const std::string& expectedName) { + checkName = true; + mExpectedName = expectedName; + } + + static bool waitForAllReleased(int timeoutMs) { + constexpr int intervalMs = 20; + int limit = timeoutMs / intervalMs; + for (int i = 1; i < limit; i++) { + if (instanceNum == 0) { + return true; + } + usleep(intervalMs * 1000); + } + return false; + } + + // To track how many instances are alive. + static std::atomic instanceNum; + + private: + std::string mName; + std::string mExpectedName; + bool checkName = false; +}; + +std::atomic NoopRun::instanceNum; + +} // namespace + +TEST(ThreadUtilTest, objectReleased) { + NoopRun::instanceNum = 0; + NoopRun* obj = new NoopRun(); + EXPECT_EQ(1, NoopRun::instanceNum); + threadLaunch(obj); + + // Wait for the object released along with the thread exited. + EXPECT_TRUE(NoopRun::waitForAllReleased(1000)); + EXPECT_EQ(0, NoopRun::instanceNum); +} + +TEST(ThreadUtilTest, SetThreadName) { + NoopRun::instanceNum = 0; + + // Test thread name empty. + NoopRun* obj1 = new NoopRun(); + obj1->setExpectedName(""); + + // Test normal case. + NoopRun* obj2 = new NoopRun("TestName"); + obj2->setExpectedName("TestName"); + + // Test thread name too long. + std::string name("TestNameTooooLong"); + NoopRun* obj3 = new NoopRun(name); + obj3->setExpectedName(name.substr(0, 15)); + + // Thread names are examined in their destructors. + EXPECT_EQ(3, NoopRun::instanceNum); + threadLaunch(obj1); + threadLaunch(obj2); + threadLaunch(obj3); + + EXPECT_TRUE(NoopRun::waitForAllReleased(1000)); + EXPECT_EQ(0, NoopRun::instanceNum); +} + +} // namespace android::netdutils diff --git a/staticlibs/netd/libnetdutils/UniqueFd.cpp b/staticlibs/netd/libnetdutils/UniqueFd.cpp new file mode 100644 index 0000000000..1cb30edde2 --- /dev/null +++ b/staticlibs/netd/libnetdutils/UniqueFd.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2017 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. + */ + +#include + +#include "netdutils/UniqueFd.h" +#include "netdutils/Syscalls.h" + +namespace android { +namespace netdutils { + +void UniqueFd::reset(Fd fd) { + auto& sys = sSyscalls.get(); + std::swap(fd, mFd); + if (isWellFormed(fd)) { + expectOk(sys.close(fd)); + } +} + +std::ostream& operator<<(std::ostream& os, const UniqueFd& fd) { + return os << "UniqueFd[" << static_cast(fd) << "]"; +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/UniqueFile.cpp b/staticlibs/netd/libnetdutils/UniqueFile.cpp new file mode 100644 index 0000000000..21e8779805 --- /dev/null +++ b/staticlibs/netd/libnetdutils/UniqueFile.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2017 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. + */ + +#include + +#include "netdutils/Syscalls.h" +#include "netdutils/UniqueFile.h" + +namespace android { +namespace netdutils { + +void UniqueFileDtor::operator()(FILE* file) const { + const auto& sys = sSyscalls.get(); + sys.fclose(file).ignoreError(); +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/include/netdutils/BackoffSequence.h b/staticlibs/netd/libnetdutils/include/netdutils/BackoffSequence.h new file mode 100644 index 0000000000..a52e72d6dd --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/BackoffSequence.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef NETDUTILS_BACKOFFSEQUENCE_H +#define NETDUTILS_BACKOFFSEQUENCE_H + +#include +#include +#include +#include + +namespace android { +namespace netdutils { + +// Encapsulate some RFC 3315 section 14 -style backoff mechanics. +// +// https://tools.ietf.org/html/rfc3315#section-14 +template +class BackoffSequence { + public: + struct Parameters { + time_type initialRetransTime{TIME_UNITY}; + counter_type maxRetransCount{0U}; + time_type maxRetransTime{TIME_ZERO}; + time_type maxRetransDuration{TIME_ZERO}; + time_type endOfSequenceIndicator{TIME_ZERO}; + }; + + BackoffSequence() : BackoffSequence(Parameters{}) {} + BackoffSequence(const BackoffSequence &) = default; + BackoffSequence(BackoffSequence &&) = default; + BackoffSequence& operator=(const BackoffSequence &) = default; + BackoffSequence& operator=(BackoffSequence &&) = default; + + bool hasNextTimeout() const noexcept { + return !maxRetransCountExceed() && !maxRetransDurationExceeded(); + } + + // Returns 0 when the sequence is exhausted. + time_type getNextTimeout() { + if (!hasNextTimeout()) return getEndOfSequenceIndicator(); + + mRetransTime = getNextTimeoutAfter(mRetransTime); + + mRetransCount++; + mTotalRetransDuration += mRetransTime; + return mRetransTime; + } + + time_type getEndOfSequenceIndicator() const noexcept { + return mParams.endOfSequenceIndicator; + } + + class Builder { + public: + Builder() {} + + constexpr Builder& withInitialRetransmissionTime(time_type irt) { + mParams.initialRetransTime = irt; + return *this; + } + constexpr Builder& withMaximumRetransmissionCount(counter_type mrc) { + mParams.maxRetransCount = mrc; + return *this; + } + constexpr Builder& withMaximumRetransmissionTime(time_type mrt) { + mParams.maxRetransTime = mrt; + return *this; + } + constexpr Builder& withMaximumRetransmissionDuration(time_type mrd) { + mParams.maxRetransDuration = mrd; + return *this; + } + constexpr Builder& withEndOfSequenceIndicator(time_type eos) { + mParams.endOfSequenceIndicator = eos; + return *this; + } + + constexpr BackoffSequence build() const { + return BackoffSequence(mParams); + } + + private: + Parameters mParams; + }; + + private: + static constexpr int PER_ITERATION_SCALING_FACTOR = 2; + static constexpr time_type TIME_ZERO = time_type(); + static constexpr time_type TIME_UNITY = time_type(1); + + constexpr BackoffSequence(const struct Parameters ¶ms) + : mParams(params), + mRetransCount(0), + mRetransTime(TIME_ZERO), + mTotalRetransDuration(TIME_ZERO) {} + + constexpr bool maxRetransCountExceed() const { + return (mParams.maxRetransCount > 0) && (mRetransCount >= mParams.maxRetransCount); + } + + constexpr bool maxRetransDurationExceeded() const { + return (mParams.maxRetransDuration > TIME_ZERO) && + (mTotalRetransDuration >= mParams.maxRetransDuration); + } + + time_type getNextTimeoutAfter(time_type lastTimeout) const { + // TODO: Support proper random jitter. Also, consider supporting some + // per-iteration scaling factor other than doubling. + time_type nextTimeout = (lastTimeout > TIME_ZERO) + ? PER_ITERATION_SCALING_FACTOR * lastTimeout + : mParams.initialRetransTime; + + // Check if overflow occurred. + if (nextTimeout < lastTimeout) { + nextTimeout = std::numeric_limits::max(); + } + + // Cap to maximum allowed, if necessary. + if (mParams.maxRetransTime > TIME_ZERO) { + nextTimeout = std::min(nextTimeout, mParams.maxRetransTime); + } + + // Don't overflow the maximum total duration. + if (mParams.maxRetransDuration > TIME_ZERO) { + nextTimeout = std::min(nextTimeout, mParams.maxRetransDuration - lastTimeout); + } + return nextTimeout; + } + + const Parameters mParams; + counter_type mRetransCount; + time_type mRetransTime; + time_type mTotalRetransDuration; +}; + +} // namespace netdutils +} // namespace android + +#endif /* NETDUTILS_BACKOFFSEQUENCE_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/DumpWriter.h b/staticlibs/netd/libnetdutils/include/netdutils/DumpWriter.h new file mode 100644 index 0000000000..a50b5e60a3 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/DumpWriter.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef NETDUTILS_DUMPWRITER_H_ +#define NETDUTILS_DUMPWRITER_H_ + +#include + +namespace android { +namespace netdutils { + +class DumpWriter { + public: + DumpWriter(int fd); + + void incIndent(); + void decIndent(); + + void println(const std::string& line); + template + void println(const char line[n]) { + println(std::string(line)); + } + // Hint to the compiler that it should apply printf validation of + // arguments (beginning at position 3) of the format (specified in + // position 2). Note that position 1 is the implicit "this" argument. + void println(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))); + void blankline() { println(""); } + + private: + uint8_t mIndentLevel; + int mFd; +}; + +class ScopedIndent { + public: + ScopedIndent() = delete; + ScopedIndent(const ScopedIndent&) = delete; + ScopedIndent(ScopedIndent&&) = delete; + explicit ScopedIndent(DumpWriter& dw) : mDw(dw) { mDw.incIndent(); } + ~ScopedIndent() { mDw.decIndent(); } + ScopedIndent& operator=(const ScopedIndent&) = delete; + ScopedIndent& operator=(ScopedIndent&&) = delete; + + // TODO: consider additional {inc,dec}Indent methods and a counter that + // can be used to unwind all pending increments on exit. + + private: + DumpWriter& mDw; +}; + +} // namespace netdutils +} // namespace android + +#endif // NETDUTILS_DUMPWRITER_H_ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Fd.h b/staticlibs/netd/libnetdutils/include/netdutils/Fd.h new file mode 100644 index 0000000000..7db40870f1 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Fd.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_FD_H +#define NETUTILS_FD_H + +#include + +#include "netdutils/Status.h" + +namespace android { +namespace netdutils { + +// Strongly typed wrapper for file descriptors with value semantics. +// This class should typically hold unowned file descriptors. +class Fd { + public: + constexpr Fd() = default; + + constexpr Fd(int fd) : mFd(fd) {} + + int get() const { return mFd; } + + bool operator==(const Fd& other) const { return get() == other.get(); } + bool operator!=(const Fd& other) const { return get() != other.get(); } + + private: + int mFd = -1; +}; + +// Return true if fd appears valid (non-negative) +inline bool isWellFormed(const Fd fd) { + return fd.get() >= 0; +} + +std::ostream& operator<<(std::ostream& os, const Fd& fd); + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_FD_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Handle.h b/staticlibs/netd/libnetdutils/include/netdutils/Handle.h new file mode 100644 index 0000000000..82083d414e --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Handle.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_HANDLE_H +#define NETUTILS_HANDLE_H + +#include + +namespace android { +namespace netdutils { + +// Opaque, strongly typed wrapper for integer-like handles. +// Explicitly avoids implementing arithmetic operations. +// +// This class is intended to avoid common errors when reordering +// arguments to functions, typos and other cases where plain integer +// types would silently cover up the mistake. +// +// usage: +// DEFINE_HANDLE(ProductId, uint64_t); +// DEFINE_HANDLE(ThumbnailHash, uint64_t); +// void foo(ProductId p, ThumbnailHash th) {...} +// +// void test() { +// ProductId p(88); +// ThumbnailHash th1(100), th2(200); +// +// foo(p, th1); <- ok! +// foo(th1, p); <- disallowed! +// th1 += 10; <- disallowed! +// p = th2; <- disallowed! +// assert(th1 != th2); <- ok! +// } +template +class Handle { + public: + constexpr Handle() = default; + constexpr Handle(const T& value) : mValue(value) {} + + const T get() const { return mValue; } + + bool operator==(const Handle& that) const { return get() == that.get(); } + bool operator!=(const Handle& that) const { return get() != that.get(); } + + private: + T mValue; +}; + +#define DEFINE_HANDLE(name, type) \ + struct _##name##Tag {}; \ + using name = ::android::netdutils::Handle; + +template +inline std::ostream& operator<<(std::ostream& os, const Handle& handle) { + return os << handle.get(); +} + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_HANDLE_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/InternetAddresses.h b/staticlibs/netd/libnetdutils/include/netdutils/InternetAddresses.h new file mode 100644 index 0000000000..d5cbe2b466 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/InternetAddresses.h @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2018 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "netdutils/NetworkConstants.h" + +namespace android { +namespace netdutils { + +namespace internal_ { + +// A structure to hold data for dealing with Internet addresses (IPAddress) and +// related types such as IPSockAddr and IPPrefix. +struct compact_ipdata { + uint8_t family{AF_UNSPEC}; + uint8_t cidrlen{0U}; // written and read in host-byte order + in_port_t port{0U}; // written and read in host-byte order + uint32_t scope_id{0U}; + union { + in_addr v4; + in6_addr v6; + } ip{.v6 = IN6ADDR_ANY_INIT}; // written and read in network-byte order + + // Classes that use compact_ipdata and this method should be sure to clear + // (i.e. zero or make uniform) any fields not relevant to the class. + friend bool operator==(const compact_ipdata& a, const compact_ipdata& b) { + if ((a.family != b.family) || (a.cidrlen != b.cidrlen) || (a.port != b.port) || + (a.scope_id != b.scope_id)) { + return false; + } + switch (a.family) { + case AF_UNSPEC: + // After the above checks, two AF_UNSPEC objects can be + // considered equal, for convenience. + return true; + case AF_INET: { + const in_addr v4a = a.ip.v4; + const in_addr v4b = b.ip.v4; + return (v4a.s_addr == v4b.s_addr); + } + case AF_INET6: { + const in6_addr v6a = a.ip.v6; + const in6_addr v6b = b.ip.v6; + return IN6_ARE_ADDR_EQUAL(&v6a, &v6b); + } + } + return false; + } + + // Classes that use compact_ipdata and this method should be sure to clear + // (i.e. zero or make uniform) any fields not relevant to the class. + friend bool operator!=(const compact_ipdata& a, const compact_ipdata& b) { return !(a == b); } + + // Classes that use compact_ipdata and this method should be sure to clear + // (i.e. zero or make uniform) any fields not relevant to the class. + friend bool operator<(const compact_ipdata& a, const compact_ipdata& b) { + if (a.family != b.family) return (a.family < b.family); + switch (a.family) { + case AF_INET: { + const in_addr v4a = a.ip.v4; + const in_addr v4b = b.ip.v4; + if (v4a.s_addr != v4b.s_addr) return (ntohl(v4a.s_addr) < ntohl(v4b.s_addr)); + break; + } + case AF_INET6: { + const in6_addr v6a = a.ip.v6; + const in6_addr v6b = b.ip.v6; + const int cmp = std::memcmp(v6a.s6_addr, v6b.s6_addr, IPV6_ADDR_LEN); + if (cmp != 0) return cmp < 0; + break; + } + } + if (a.cidrlen != b.cidrlen) return (a.cidrlen < b.cidrlen); + if (a.port != b.port) return (a.port < b.port); + return (a.scope_id < b.scope_id); + } +}; + +static_assert(AF_UNSPEC <= std::numeric_limits::max(), "AF_UNSPEC value too large"); +static_assert(AF_INET <= std::numeric_limits::max(), "AF_INET value too large"); +static_assert(AF_INET6 <= std::numeric_limits::max(), "AF_INET6 value too large"); +static_assert(sizeof(compact_ipdata) == 24U, "compact_ipdata unexpectedly large"); + +} // namespace internal_ + +struct AddrinfoDeleter { + void operator()(struct addrinfo* p) const { + if (p != nullptr) { + freeaddrinfo(p); + } + } +}; + +typedef std::unique_ptr ScopedAddrinfo; + +inline bool usesScopedIds(const in6_addr& ipv6) { + return (IN6_IS_ADDR_LINKLOCAL(&ipv6) || IN6_IS_ADDR_MC_LINKLOCAL(&ipv6)); +} + +class IPPrefix; +class IPSockAddr; + +class IPAddress { + public: + static bool forString(const std::string& repr, IPAddress* ip); + static IPAddress forString(const std::string& repr) { + IPAddress ip; + if (!forString(repr, &ip)) return IPAddress(); + return ip; + } + + IPAddress() = default; + IPAddress(const IPAddress&) = default; + IPAddress(IPAddress&&) = default; + + explicit IPAddress(const in_addr& ipv4) + : mData({AF_INET, IPV4_ADDR_BITS, 0U, 0U, {.v4 = ipv4}}) {} + explicit IPAddress(const in6_addr& ipv6) + : mData({AF_INET6, IPV6_ADDR_BITS, 0U, 0U, {.v6 = ipv6}}) {} + IPAddress(const in6_addr& ipv6, uint32_t scope_id) + : mData({AF_INET6, + IPV6_ADDR_BITS, + 0U, + // Sanity check: scoped_ids only for link-local addresses. + usesScopedIds(ipv6) ? scope_id : 0U, + {.v6 = ipv6}}) {} + IPAddress(const IPAddress& ip, uint32_t scope_id) : IPAddress(ip) { + mData.scope_id = (family() == AF_INET6 && usesScopedIds(mData.ip.v6)) ? scope_id : 0U; + } + + IPAddress& operator=(const IPAddress&) = default; + IPAddress& operator=(IPAddress&&) = default; + + constexpr sa_family_t family() const noexcept { return mData.family; } + constexpr uint32_t scope_id() const noexcept { return mData.scope_id; } + + std::string toString() const noexcept; + + friend std::ostream& operator<<(std::ostream& os, const IPAddress& ip) { + os << ip.toString(); + return os; + } + friend bool operator==(const IPAddress& a, const IPAddress& b) { return (a.mData == b.mData); } + friend bool operator!=(const IPAddress& a, const IPAddress& b) { return (a.mData != b.mData); } + friend bool operator<(const IPAddress& a, const IPAddress& b) { return (a.mData < b.mData); } + friend bool operator>(const IPAddress& a, const IPAddress& b) { return (b.mData < a.mData); } + friend bool operator<=(const IPAddress& a, const IPAddress& b) { return (a < b) || (a == b); } + friend bool operator>=(const IPAddress& a, const IPAddress& b) { return (b < a) || (a == b); } + + private: + friend class IPPrefix; + friend class IPSockAddr; + + explicit IPAddress(const internal_::compact_ipdata& ipdata) : mData(ipdata) { + mData.port = 0U; + switch (mData.family) { + case AF_INET: + mData.cidrlen = IPV4_ADDR_BITS; + mData.scope_id = 0U; + break; + case AF_INET6: + mData.cidrlen = IPV6_ADDR_BITS; + if (usesScopedIds(ipdata.ip.v6)) mData.scope_id = ipdata.scope_id; + break; + default: + mData.cidrlen = 0U; + mData.scope_id = 0U; + break; + } + } + + internal_::compact_ipdata mData{}; +}; + +class IPPrefix { + public: + static bool forString(const std::string& repr, IPPrefix* prefix); + static IPPrefix forString(const std::string& repr) { + IPPrefix prefix; + if (!forString(repr, &prefix)) return IPPrefix(); + return prefix; + } + + IPPrefix() = default; + IPPrefix(const IPPrefix&) = default; + IPPrefix(IPPrefix&&) = default; + + explicit IPPrefix(const IPAddress& ip) : mData(ip.mData) {} + + // Truncate the IP address |ip| at length |length|. Lengths greater than + // the address-family-relevant maximum, along with negative values, are + // interpreted as if the address-family-relevant maximum had been given. + IPPrefix(const IPAddress& ip, int length); + + IPPrefix& operator=(const IPPrefix&) = default; + IPPrefix& operator=(IPPrefix&&) = default; + + constexpr sa_family_t family() const noexcept { return mData.family; } + IPAddress ip() const noexcept { return IPAddress(mData); } + in_addr addr4() const noexcept { return mData.ip.v4; } + in6_addr addr6() const noexcept { return mData.ip.v6; } + constexpr int length() const noexcept { return mData.cidrlen; } + + bool isUninitialized() const noexcept; + std::string toString() const noexcept; + + friend std::ostream& operator<<(std::ostream& os, const IPPrefix& prefix) { + os << prefix.toString(); + return os; + } + friend bool operator==(const IPPrefix& a, const IPPrefix& b) { return (a.mData == b.mData); } + friend bool operator!=(const IPPrefix& a, const IPPrefix& b) { return (a.mData != b.mData); } + friend bool operator<(const IPPrefix& a, const IPPrefix& b) { return (a.mData < b.mData); } + friend bool operator>(const IPPrefix& a, const IPPrefix& b) { return (b.mData < a.mData); } + friend bool operator<=(const IPPrefix& a, const IPPrefix& b) { return (a < b) || (a == b); } + friend bool operator>=(const IPPrefix& a, const IPPrefix& b) { return (b < a) || (a == b); } + + private: + internal_::compact_ipdata mData{}; +}; + +// An Internet socket address. +// +// Cannot represent other types of socket addresses (e.g. UNIX socket address, et cetera). +class IPSockAddr { + public: + // TODO: static forString + + static IPSockAddr toIPSockAddr(const std::string& repr, in_port_t port) { + return IPSockAddr(IPAddress::forString(repr), port); + } + static IPSockAddr toIPSockAddr(const sockaddr& sa) { + switch (sa.sa_family) { + case AF_INET: + return IPSockAddr(*reinterpret_cast(&sa)); + case AF_INET6: + return IPSockAddr(*reinterpret_cast(&sa)); + default: + return IPSockAddr(); + } + } + static IPSockAddr toIPSockAddr(const sockaddr_storage& ss) { + return toIPSockAddr(*reinterpret_cast(&ss)); + } + + IPSockAddr() = default; + IPSockAddr(const IPSockAddr&) = default; + IPSockAddr(IPSockAddr&&) = default; + + explicit IPSockAddr(const IPAddress& ip) : mData(ip.mData) {} + IPSockAddr(const IPAddress& ip, in_port_t port) : mData(ip.mData) { mData.port = port; } + explicit IPSockAddr(const sockaddr_in& ipv4sa) + : IPSockAddr(IPAddress(ipv4sa.sin_addr), ntohs(ipv4sa.sin_port)) {} + explicit IPSockAddr(const sockaddr_in6& ipv6sa) + : IPSockAddr(IPAddress(ipv6sa.sin6_addr, ipv6sa.sin6_scope_id), ntohs(ipv6sa.sin6_port)) {} + + IPSockAddr& operator=(const IPSockAddr&) = default; + IPSockAddr& operator=(IPSockAddr&&) = default; + + constexpr sa_family_t family() const noexcept { return mData.family; } + IPAddress ip() const noexcept { return IPAddress(mData); } + constexpr in_port_t port() const noexcept { return mData.port; } + + // Implicit conversion to sockaddr_storage. + operator sockaddr_storage() const noexcept { + sockaddr_storage ss; + ss.ss_family = mData.family; + switch (mData.family) { + case AF_INET: + reinterpret_cast(&ss)->sin_addr = mData.ip.v4; + reinterpret_cast(&ss)->sin_port = htons(mData.port); + break; + case AF_INET6: + reinterpret_cast(&ss)->sin6_addr = mData.ip.v6; + reinterpret_cast(&ss)->sin6_port = htons(mData.port); + reinterpret_cast(&ss)->sin6_scope_id = mData.scope_id; + break; + } + return ss; + } + + std::string toString() const noexcept; + + friend std::ostream& operator<<(std::ostream& os, const IPSockAddr& prefix) { + os << prefix.toString(); + return os; + } + friend bool operator==(const IPSockAddr& a, const IPSockAddr& b) { + return (a.mData == b.mData); + } + friend bool operator!=(const IPSockAddr& a, const IPSockAddr& b) { + return (a.mData != b.mData); + } + friend bool operator<(const IPSockAddr& a, const IPSockAddr& b) { return (a.mData < b.mData); } + friend bool operator>(const IPSockAddr& a, const IPSockAddr& b) { return (b.mData < a.mData); } + friend bool operator<=(const IPSockAddr& a, const IPSockAddr& b) { return (a < b) || (a == b); } + friend bool operator>=(const IPSockAddr& a, const IPSockAddr& b) { return (b < a) || (a == b); } + + private: + internal_::compact_ipdata mData{}; +}; + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Log.h b/staticlibs/netd/libnetdutils/include/netdutils/Log.h new file mode 100644 index 0000000000..77ae649424 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Log.h @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef NETUTILS_LOG_H +#define NETUTILS_LOG_H + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +namespace android { +namespace netdutils { + +class LogEntry { + public: + LogEntry() = default; + LogEntry(const LogEntry&) = default; + LogEntry(LogEntry&&) = default; + ~LogEntry() = default; + LogEntry& operator=(const LogEntry&) = default; + LogEntry& operator=(LogEntry&&) = default; + + std::string toString() const; + + /// + // Helper methods that make it easy to build up a LogEntry message. + // If performance becomes a factor the implementations could be inlined. + /// + LogEntry& message(const std::string& message); + + // For calling with __FUNCTION__. + LogEntry& function(const std::string& function_name); + // For calling with __PRETTY_FUNCTION__. + LogEntry& prettyFunction(const std::string& pretty_function); + + // Convenience methods for each of the common types of function arguments. + LogEntry& arg(const std::string& val); + // Intended for binary buffers, formats as hex + LogEntry& arg(const std::vector& val); + LogEntry& arg(const std::vector& val); + LogEntry& arg(const std::vector& val); + template >> + LogEntry& arg(IntT val) { + mArgs.push_back(std::to_string(val)); + return *this; + } + // Not using a plain overload here to avoid the implicit conversion from + // any pointer to bool, which causes string literals to print as 'true'. + template <> + LogEntry& arg<>(bool val); + + template + LogEntry& args(const Args&... a) { + // Cleverness ahead: we throw away the initializer_list filled with + // zeroes, all we care about is calling arg() for each argument. + (void) std::initializer_list{(arg(a), 0)...}; + return *this; + } + + // Some things can return more than one value, or have multiple output + // parameters, so each of these adds to the mReturns vector. + LogEntry& returns(const std::string& rval); + LogEntry& returns(const Status& status); + LogEntry& returns(bool rval); + template + LogEntry& returns(T val) { + mReturns.push_back(std::to_string(val)); + return *this; + } + + LogEntry& withUid(uid_t uid); + + // Append the duration computed since the creation of this instance. + LogEntry& withAutomaticDuration(); + // Append the string-ified duration computed by some other means. + LogEntry& withDuration(const std::string& duration); + + private: + std::chrono::steady_clock::time_point mStart = std::chrono::steady_clock::now(); + std::string mMsg{}; + std::string mFunc{}; + std::vector mArgs{}; + std::vector mReturns{}; + std::string mUid{}; + std::string mDuration{}; +}; + +class Log { + public: + Log() = delete; + Log(const std::string& tag) : Log(tag, MAX_ENTRIES) {} + Log(const std::string& tag, size_t maxEntries) : mTag(tag), mMaxEntries(maxEntries) {} + Log(const Log&) = delete; + Log(Log&&) = delete; + ~Log(); + Log& operator=(const Log&) = delete; + Log& operator=(Log&&) = delete; + + LogEntry newEntry() const { return LogEntry(); } + + // Record a log entry in internal storage only. + void log(const std::string& entry) { record(Level::LOG, entry); } + template + void log(const char entry[n]) { log(std::string(entry)); } + void log(const LogEntry& entry) { log(entry.toString()); } + void log(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { + using ::android::base::StringAppendV; + std::string result; + va_list ap; + va_start(ap, fmt); + StringAppendV(&result, fmt, ap); + va_end(ap); + log(result); + } + + // Record a log entry in internal storage and to ALOGI as well. + void info(const std::string& entry) { record(Level::INFO, entry); } + template + void info(const char entry[n]) { info(std::string(entry)); } + void info(const LogEntry& entry) { info(entry.toString()); } + void info(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { + using ::android::base::StringAppendV; + std::string result; + va_list ap; + va_start(ap, fmt); + StringAppendV(&result, fmt, ap); + va_end(ap); + info(result); + } + + // Record a log entry in internal storage and to ALOGW as well. + void warn(const std::string& entry) { record(Level::WARN, entry); } + template + void warn(const char entry[n]) { warn(std::string(entry)); } + void warn(const LogEntry& entry) { warn(entry.toString()); } + void warn(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { + using ::android::base::StringAppendV; + std::string result; + va_list ap; + va_start(ap, fmt); + StringAppendV(&result, fmt, ap); + va_end(ap); + warn(result); + } + + // Record a log entry in internal storage and to ALOGE as well. + void error(const std::string& entry) { record(Level::ERROR, entry); } + template + void error(const char entry[n]) { error(std::string(entry)); } + void error(const LogEntry& entry) { error(entry.toString()); } + void error(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) { + using ::android::base::StringAppendV; + std::string result; + va_list ap; + va_start(ap, fmt); + StringAppendV(&result, fmt, ap); + va_end(ap); + error(result); + } + + // Iterates over every entry in the log in chronological order. Operates + // on a copy of the log entries, and so perEntryFn may itself call one of + // the logging functions if needed. + void forEachEntry(const std::function& perEntryFn) const; + + private: + static constexpr const size_t MAX_ENTRIES = 750U; + const std::string mTag; + const size_t mMaxEntries; + + // The LOG level adds an entry to mEntries but does not output the message + // to the system log. All other levels append to mEntries and output to the + // the system log. + enum class Level { + LOG, + INFO, + WARN, + ERROR, + }; + + void record(Level lvl, const std::string& entry); + + mutable std::shared_mutex mLock; + std::deque mEntries; // GUARDED_BY(mLock), when supported +}; + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_LOG_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Math.h b/staticlibs/netd/libnetdutils/include/netdutils/Math.h new file mode 100644 index 0000000000..c41fbf5882 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Math.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_MATH_H +#define NETUTILS_MATH_H + +#include +#include + +namespace android { +namespace netdutils { + +template +inline constexpr const T mask(const int shift) { + return (1 << shift) - 1; +} + +// Align x up to the nearest integer multiple of 2^shift +template +inline constexpr const T align(const T& x, const int shift) { + return (x + mask(shift)) & ~mask(shift); +} + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_MATH_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/MemBlock.h b/staticlibs/netd/libnetdutils/include/netdutils/MemBlock.h new file mode 100644 index 0000000000..fd4d612d38 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/MemBlock.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef NETUTILS_MEMBLOCK_H +#define NETUTILS_MEMBLOCK_H + +#include +#include "netdutils/Slice.h" + +namespace android { +namespace netdutils { + +// A class to encapsulate self-deleting byte arrays while preserving access +// to the underlying length (without the length being part of the type, e.g. +// std::array<>). By design, the only interface to the underlying bytes is +// via Slice, to encourage safer memory access usage. +// +// No thread-safety guarantees whatsoever. +class MemBlock { + public: + MemBlock() : MemBlock(0U) {} + explicit MemBlock(size_t len) + : mData((len > 0U) ? new uint8_t[len]{} : nullptr), + mLen(len) {} + // Allocate memory of size src.size() and copy src into this MemBlock. + explicit MemBlock(Slice src) : MemBlock(src.size()) { + copy(get(), src); + } + + // No copy construction or assignment. + MemBlock(const MemBlock&) = delete; + MemBlock& operator=(const MemBlock&) = delete; + + // Move construction and assignment are okay. + MemBlock(MemBlock&&) = default; + MemBlock& operator=(MemBlock&&) = default; + + // Even though this method is const, the memory wrapped by the + // returned Slice is mutable. + Slice get() const noexcept { return Slice(mData.get(), mLen); } + + // Implicit cast to Slice. + // NOLINTNEXTLINE(google-explicit-constructor) + operator const Slice() const noexcept { return get(); } + + private: + std::unique_ptr mData; + size_t mLen; +}; + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_MEMBLOCK_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Misc.h b/staticlibs/netd/libnetdutils/include/netdutils/Misc.h new file mode 100644 index 0000000000..d344f81fc3 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Misc.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_MISC_H +#define NETUTILS_MISC_H + +#include + +namespace android { +namespace netdutils { + +// Lookup key in map, returing a default value if key is not found +template +inline const V& findWithDefault(const std::map& map, const U& key, const V& dflt) { + auto it = map.find(key); + return (it == map.end()) ? dflt : it->second; +} + +// Movable, copiable, scoped lambda (or std::function) runner. Useful +// for running arbitrary cleanup or logging code when exiting a scope. +// +// Compare to defer in golang. +template +class Cleanup { + public: + Cleanup() = delete; + explicit Cleanup(FnT fn) : mFn(fn) {} + ~Cleanup() { if (!mReleased) mFn(); } + + void release() { mReleased = true; } + + private: + bool mReleased{false}; + FnT mFn; +}; + +// Helper to make a new Cleanup. Avoids complex or impossible syntax +// when wrapping lambdas. +// +// Usage: +// auto cleanup = makeCleanup([](){ your_code_here; }); +template +Cleanup makeCleanup(FnT fn) { + return Cleanup(fn); +} + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_MISC_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/MockSyscalls.h b/staticlibs/netd/libnetdutils/include/netdutils/MockSyscalls.h new file mode 100644 index 0000000000..f57b55ca9d --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/MockSyscalls.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_MOCK_SYSCALLS_H +#define NETUTILS_MOCK_SYSCALLS_H + +#include +#include +#include + +#include +#include + +#include "netdutils/Syscalls.h" + +namespace android { +namespace netdutils { + +class MockSyscalls : public Syscalls { + public: + virtual ~MockSyscalls() = default; + // Use Return(ByMove(...)) to deal with movable return types. + MOCK_CONST_METHOD3(open, + StatusOr(const std::string& pathname, int flags, mode_t mode)); + MOCK_CONST_METHOD3(socket, StatusOr(int domain, int type, int protocol)); + MOCK_CONST_METHOD3(getsockname, Status(Fd sock, sockaddr* addr, socklen_t* addrlen)); + MOCK_CONST_METHOD5(getsockopt, Status(Fd sock, int level, int optname, void* optval, + socklen_t *optlen)); + MOCK_CONST_METHOD5(setsockopt, Status(Fd sock, int level, int optname, const void* optval, + socklen_t optlen)); + + MOCK_CONST_METHOD3(bind, Status(Fd sock, const sockaddr* addr, socklen_t addrlen)); + MOCK_CONST_METHOD3(connect, Status(Fd sock, const sockaddr* addr, socklen_t addrlen)); + MOCK_CONST_METHOD3(ioctl, StatusOr(Fd sock, unsigned long request, ifreq* ifr)); + + // Use Return(ByMove(...)) to deal with movable return types. + MOCK_CONST_METHOD2(eventfd, StatusOr(unsigned int initval, int flags)); + MOCK_CONST_METHOD3(ppoll, StatusOr(pollfd* fds, nfds_t nfds, double timeout)); + + MOCK_CONST_METHOD2(writev, StatusOr(Fd fd, const std::vector& iov)); + MOCK_CONST_METHOD2(write, StatusOr(Fd fd, const Slice buf)); + MOCK_CONST_METHOD2(read, StatusOr(Fd fd, const Slice buf)); + MOCK_CONST_METHOD5(sendto, StatusOr(Fd sock, const Slice buf, int flags, + const sockaddr* dst, socklen_t dstlen)); + MOCK_CONST_METHOD5(recvfrom, StatusOr(Fd sock, const Slice dst, int flags, sockaddr* src, + socklen_t* srclen)); + MOCK_CONST_METHOD2(shutdown, Status(Fd fd, int how)); + MOCK_CONST_METHOD1(close, Status(Fd fd)); + + MOCK_CONST_METHOD2(fopen, + StatusOr(const std::string& path, const std::string& mode)); + MOCK_CONST_METHOD3(vfprintf, StatusOr(FILE* file, const char* format, va_list ap)); + MOCK_CONST_METHOD3(vfscanf, StatusOr(FILE* file, const char* format, va_list ap)); + MOCK_CONST_METHOD1(fclose, Status(FILE* file)); + MOCK_CONST_METHOD0(fork, StatusOr()); +}; + +// For the lifetime of this mock, replace the contents of sSyscalls +// with a pointer to this mock. Behavior is undefined if multiple +// ScopedMockSyscalls instances exist concurrently. +class ScopedMockSyscalls : public MockSyscalls { + public: + ScopedMockSyscalls() : mOld(sSyscalls.swap(*this)) { assert((mRefcount++) == 1); } + virtual ~ScopedMockSyscalls() { + sSyscalls.swap(mOld); + assert((mRefcount--) == 0); + } + + private: + std::atomic mRefcount{0}; + Syscalls& mOld; +}; + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_MOCK_SYSCALLS_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Netfilter.h b/staticlibs/netd/libnetdutils/include/netdutils/Netfilter.h new file mode 100644 index 0000000000..22736f192b --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Netfilter.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_NETFILTER_H +#define NETUTILS_NETFILTER_H + +#include + +#include +#include +#include + +std::ostream& operator<<(std::ostream& os, const nfgenmsg& msg); + +#endif /* NETUTILS_NETFILTER_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Netlink.h b/staticlibs/netd/libnetdutils/include/netdutils/Netlink.h new file mode 100644 index 0000000000..ee5183ab47 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Netlink.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_NETLINK_H +#define NETUTILS_NETLINK_H + +#include +#include +#include + +#include "netdutils/Slice.h" + +namespace android { +namespace netdutils { + +// Invoke onMsg once for each netlink message in buf. onMsg will be +// invoked with an aligned and deserialized header along with a Slice +// containing the message payload. +// +// Assume that the first message begins at offset zero within buf. +void forEachNetlinkMessage(const Slice buf, + const std::function& onMsg); + +// Invoke onAttr once for each netlink attribute in buf. onAttr will be +// invoked with an aligned and deserialized header along with a Slice +// containing the attribute payload. +// +// Assume that the first attribute begins at offset zero within buf. +void forEachNetlinkAttribute(const Slice buf, + const std::function& onAttr); + +} // namespace netdutils +} // namespace android + +bool operator==(const sockaddr_nl& lhs, const sockaddr_nl& rhs); +bool operator!=(const sockaddr_nl& lhs, const sockaddr_nl& rhs); + +std::ostream& operator<<(std::ostream& os, const nlmsghdr& hdr); +std::ostream& operator<<(std::ostream& os, const nlattr& attr); +std::ostream& operator<<(std::ostream& os, const sockaddr_nl& addr); + +#endif /* NETUTILS_NETLINK_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/NetworkConstants.h b/staticlibs/netd/libnetdutils/include/netdutils/NetworkConstants.h new file mode 100644 index 0000000000..dead9a17bd --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/NetworkConstants.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 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. + */ + +#pragma once + +namespace android { +namespace netdutils { + +// See also NetworkConstants.java in frameworks/base. +constexpr int IPV4_ADDR_LEN = 4; +constexpr int IPV4_ADDR_BITS = 32; +constexpr int IPV6_ADDR_LEN = 16; +constexpr int IPV6_ADDR_BITS = 128; + +// Referred from SHA256_DIGEST_LENGTH in boringssl +constexpr size_t SHA256_SIZE = 32; + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/include/netdutils/ResponseCode.h b/staticlibs/netd/libnetdutils/include/netdutils/ResponseCode.h new file mode 100644 index 0000000000..c170684cf3 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/ResponseCode.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef NETDUTILS_RESPONSECODE_H +#define NETDUTILS_RESPONSECODE_H + +namespace android { +namespace netdutils { + +class ResponseCode { + // Keep in sync with + // frameworks/base/services/java/com/android/server/NetworkManagementService.java + public: + // 100 series - Requestion action was initiated; expect another reply + // before proceeding with a new command. + // clang-format off + static constexpr int ActionInitiated = 100; + static constexpr int InterfaceListResult = 110; + static constexpr int TetherInterfaceListResult = 111; + static constexpr int TetherDnsFwdTgtListResult = 112; + static constexpr int TtyListResult = 113; + static constexpr int TetheringStatsListResult = 114; + static constexpr int TetherDnsFwdNetIdResult = 115; + + // 200 series - Requested action has been successfully completed + static constexpr int CommandOkay = 200; + static constexpr int TetherStatusResult = 210; + static constexpr int IpFwdStatusResult = 211; + static constexpr int InterfaceGetCfgResult = 213; + // Formerly: int SoftapStatusResult = 214; + static constexpr int UsbRNDISStatusResult = 215; + static constexpr int InterfaceRxCounterResult = 216; + static constexpr int InterfaceTxCounterResult = 217; + static constexpr int InterfaceRxThrottleResult = 218; + static constexpr int InterfaceTxThrottleResult = 219; + static constexpr int QuotaCounterResult = 220; + static constexpr int TetheringStatsResult = 221; + // NOTE: keep synced with bionic/libc/dns/net/gethnamaddr.c + static constexpr int DnsProxyQueryResult = 222; + static constexpr int ClatdStatusResult = 223; + + // 400 series - The command was accepted but the requested action + // did not take place. + static constexpr int OperationFailed = 400; + static constexpr int DnsProxyOperationFailed = 401; + static constexpr int ServiceStartFailed = 402; + static constexpr int ServiceStopFailed = 403; + + // 500 series - The command was not accepted and the requested + // action did not take place. + static constexpr int CommandSyntaxError = 500; + static constexpr int CommandParameterError = 501; + + // 600 series - Unsolicited broadcasts + static constexpr int InterfaceChange = 600; + static constexpr int BandwidthControl = 601; + static constexpr int ServiceDiscoveryFailed = 602; + static constexpr int ServiceDiscoveryServiceAdded = 603; + static constexpr int ServiceDiscoveryServiceRemoved = 604; + static constexpr int ServiceRegistrationFailed = 605; + static constexpr int ServiceRegistrationSucceeded = 606; + static constexpr int ServiceResolveFailed = 607; + static constexpr int ServiceResolveSuccess = 608; + static constexpr int ServiceSetHostnameFailed = 609; + static constexpr int ServiceSetHostnameSuccess = 610; + static constexpr int ServiceGetAddrInfoFailed = 611; + static constexpr int ServiceGetAddrInfoSuccess = 612; + static constexpr int InterfaceClassActivity = 613; + static constexpr int InterfaceAddressChange = 614; + static constexpr int InterfaceDnsInfo = 615; + static constexpr int RouteChange = 616; + static constexpr int StrictCleartext = 617; + // clang-format on +}; + +} // namespace netdutils +} // namespace android + +#endif // NETDUTILS_RESPONSECODE_H diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Slice.h b/staticlibs/netd/libnetdutils/include/netdutils/Slice.h new file mode 100644 index 0000000000..717fbd1fbb --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Slice.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_SLICE_H +#define NETUTILS_SLICE_H + +#include +#include +#include +#include +#include +#include + +namespace android { +namespace netdutils { + +// Immutable wrapper for a linear region of unowned bytes. +// Slice represents memory as a half-closed interval [base, limit). +// +// Note that without manually invoking the Slice() constructor, it is +// impossible to increase the size of a slice. This guarantees that +// applications that properly use the slice API will never access +// memory outside of a slice. +// +// Note that const Slice still wraps mutable memory, however copy +// assignment and move assignment to slice are disabled. +class Slice { + public: + Slice() = default; + + // Create a slice beginning at base and continuing to but not including limit + Slice(void* base, void* limit) : mBase(toUint8(base)), mLimit(toUint8(limit)) {} + + // Create a slice beginning at base and continuing for size bytes + Slice(void* base, size_t size) : Slice(base, toUint8(base) + size) {} + + // Return the address of the first byte in this slice + uint8_t* base() const { return mBase; } + + // Return the address of the first byte following this slice + uint8_t* limit() const { return mLimit; } + + // Return the size of this slice in bytes + size_t size() const { return limit() - base(); } + + // Return true if size() == 0 + bool empty() const { return base() == limit(); } + + private: + static uint8_t* toUint8(void* ptr) { return reinterpret_cast(ptr); } + + uint8_t* mBase = nullptr; + uint8_t* mLimit = nullptr; +}; + +// Return slice representation of ref which must be a POD type +template +inline const Slice makeSlice(const T& ref) { + static_assert(std::is_pod::value, "value must be a POD type"); + static_assert(!std::is_pointer::value, "value must not be a pointer type"); + return {const_cast(&ref), sizeof(ref)}; +} + +// Return slice representation of string data() +inline const Slice makeSlice(const std::string& s) { + using ValueT = std::string::value_type; + return {const_cast(s.data()), s.size() * sizeof(ValueT)}; +} + +// Return slice representation of vector data() +template +inline const Slice makeSlice(const std::vector& v) { + return {const_cast(v.data()), v.size() * sizeof(T)}; +} + +// Return slice representation of array data() +template +inline const Slice makeSlice(const std::array& a) { + return {const_cast(a.data()), a.size() * sizeof(U)}; +} + +// Return prefix and suffix of Slice s ending and starting at position cut +inline std::pair split(const Slice s, size_t cut) { + const size_t tmp = std::min(cut, s.size()); + return {{s.base(), s.base() + tmp}, {s.base() + tmp, s.limit()}}; +} + +// Return prefix of Slice s ending at position cut +inline const Slice take(const Slice s, size_t cut) { + return std::get<0>(split(s, cut)); +} + +// Return suffix of Slice s starting at position cut +inline const Slice drop(const Slice s, size_t cut) { + return std::get<1>(split(s, cut)); +} + +// Copy from src into dst. Bytes copied is the lesser of dst.size() and src.size() +inline size_t copy(const Slice dst, const Slice src) { + const auto min = std::min(dst.size(), src.size()); + memcpy(dst.base(), src.base(), min); + return min; +} + +// Base case for variadic extract below +template +inline size_t extract(const Slice src, Head& head) { + return copy(makeSlice(head), src); +} + +// Copy from src into one or more pointers to POD data. If src.size() +// is less than the sum of all data pointers a suffix of data will be +// left unmodified. Return the number of bytes copied. +template +inline size_t extract(const Slice src, Head& head, Tail&... tail) { + const auto extracted = extract(src, head); + return extracted + extract(drop(src, extracted), tail...); +} + +// Return a string containing a copy of the contents of s +std::string toString(const Slice s); + +// Return a string containing a hexadecimal representation of the contents of s. +// This function inserts a newline into its output every wrap bytes. +std::string toHex(const Slice s, int wrap = INT_MAX); + +inline bool operator==(const Slice& lhs, const Slice& rhs) { + return (lhs.base() == rhs.base()) && (lhs.limit() == rhs.limit()); +} + +inline bool operator!=(const Slice& lhs, const Slice& rhs) { + return !(lhs == rhs); +} + +std::ostream& operator<<(std::ostream& os, const Slice& slice); + +// Return suffix of Slice s starting at the first match of byte c. If no matched +// byte, return an empty Slice. +inline const Slice findFirstMatching(const Slice s, uint8_t c) { + uint8_t* match = (uint8_t*)memchr(s.base(), c, s.size()); + if (!match) return Slice(); + return drop(s, match - s.base()); +} + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_SLICE_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Socket.h b/staticlibs/netd/libnetdutils/include/netdutils/Socket.h new file mode 100644 index 0000000000..e5aaab9c64 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Socket.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETDUTILS_SOCKET_H +#define NETDUTILS_SOCKET_H + +#include +#include +#include + +#include "netdutils/StatusOr.h" + +namespace android { +namespace netdutils { + +inline sockaddr* asSockaddrPtr(void* addr) { + return reinterpret_cast(addr); +} + +inline const sockaddr* asSockaddrPtr(const void* addr) { + return reinterpret_cast(addr); +} + +// Return a string representation of addr or Status if there was a +// failure during conversion. +StatusOr toString(const in6_addr& addr); + +} // namespace netdutils +} // namespace android + +#endif /* NETDUTILS_SOCKET_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/SocketOption.h b/staticlibs/netd/libnetdutils/include/netdutils/SocketOption.h new file mode 100644 index 0000000000..3b0aab75d4 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/SocketOption.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef NETDUTILS_SOCKETOPTION_H +#define NETDUTILS_SOCKETOPTION_H + +#include +#include +#include + +#include "netdutils/Fd.h" +#include "netdutils/Status.h" + +namespace android { +namespace netdutils { + +// Turn on simple "boolean" socket options. +// +// This is simple wrapper for options that are enabled via code of the form: +// +// int on = 1; +// setsockopt(..., &on, sizeof(on)); +Status enableSockopt(Fd sock, int level, int optname); + +// Turn on TCP keepalives, and set keepalive parameters for this socket. +// +// A parameter value of zero does not set that parameter. +// +// Typical system defaults are: +// +// idleTime (in seconds) +// $ cat /proc/sys/net/ipv4/tcp_keepalive_time +// 7200 +// +// numProbes +// $ cat /proc/sys/net/ipv4/tcp_keepalive_probes +// 9 +// +// probeInterval (in seconds) +// $ cat /proc/sys/net/ipv4/tcp_keepalive_intvl +// 75 +Status enableTcpKeepAlives(Fd sock, unsigned idleTime, unsigned numProbes, unsigned probeInterval); + +} // namespace netdutils +} // namespace android + +#endif /* NETDUTILS_SOCKETOPTION_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Status.h b/staticlibs/netd/libnetdutils/include/netdutils/Status.h new file mode 100644 index 0000000000..bc347d5e9e --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Status.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_STATUS_H +#define NETUTILS_STATUS_H + +#include +#include +#include + +#include + +namespace android { +namespace netdutils { + +// Simple status implementation suitable for use on the stack in low +// or moderate performance code. This can definitely be improved but +// for now short string optimization is expected to keep the common +// success case fast. +// +// Status is implicitly movable via the default noexcept move constructor +// and noexcept move-assignment operator. +class [[nodiscard]] Status { + public: + Status() = default; + explicit Status(int code) : mCode(code) {} + + // Constructs an error Status, |code| must be non-zero. + Status(int code, std::string msg) : mCode(code), mMsg(std::move(msg)) { assert(!ok()); } + + Status(android::base::Result result) + : mCode(result.ok() ? 0 : result.error().code()), + mMsg(result.ok() ? "" : result.error().message()) {} + + int code() const { return mCode; } + + bool ok() const { return code() == 0; } + + const std::string& msg() const { return mMsg; } + + // Explicitly ignores the Status without triggering [[nodiscard]] errors. + void ignoreError() const {} + + bool operator==(const Status& other) const { return code() == other.code(); } + bool operator!=(const Status& other) const { return !(*this == other); } + + private: + int mCode = 0; + std::string mMsg; +}; + +namespace status { + +const Status ok{0}; +// EOF is not part of errno space, we'll place it far above the +// highest existing value. +const Status eof{0x10001, "end of file"}; +const Status undefined{std::numeric_limits::max(), "undefined"}; + +} // namespace status + +// Return true if status is "OK". This is sometimes preferable to +// status.ok() when we want to check the state of Status-like objects +// that implicitly cast to Status. +inline bool isOk(const Status& status) { + return status.ok(); +} + +// For use only in tests. Used for both Status and Status-like objects. See also isOk(). +#define EXPECT_OK(status) EXPECT_TRUE(isOk(status)) +#define ASSERT_OK(status) ASSERT_TRUE(isOk(status)) + +// Documents that status is expected to be ok. This function may log +// (or assert when running in debug mode) if status has an unexpected value. +inline void expectOk(const Status& /*status*/) { + // TODO: put something here, for now this function serves solely as documentation. +} + +// Convert POSIX errno to a Status object. +// If Status is extended to have more features, this mapping may +// become more complex. +Status statusFromErrno(int err, const std::string& msg); + +// Helper that checks Status-like object (notably StatusOr) against a +// value in the errno space. +bool equalToErrno(const Status& status, int err); + +// Helper that converts Status-like object (notably StatusOr) to a +// message. +std::string toString(const Status& status); + +std::ostream& operator<<(std::ostream& os, const Status& s); + +// Evaluate 'stmt' to a Status object and if it results in an error, return that +// error. Use 'tmp' as a variable name to avoid shadowing any variables named +// tmp. +#define RETURN_IF_NOT_OK_IMPL(tmp, stmt) \ + do { \ + ::android::netdutils::Status tmp = (stmt); \ + if (!isOk(tmp)) { \ + return tmp; \ + } \ + } while (false) + +// Create a unique variable name to avoid shadowing local variables. +#define RETURN_IF_NOT_OK_CONCAT(line, stmt) RETURN_IF_NOT_OK_IMPL(__CONCAT(_status_, line), stmt) + +// Macro to allow exception-like handling of error return values. +// +// If the evaluation of stmt results in an error, return that error +// from current function. +// +// Example usage: +// Status bar() { ... } +// +// RETURN_IF_NOT_OK(status); +// RETURN_IF_NOT_OK(bar()); +#define RETURN_IF_NOT_OK(stmt) RETURN_IF_NOT_OK_CONCAT(__LINE__, stmt) + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_STATUS_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/StatusOr.h b/staticlibs/netd/libnetdutils/include/netdutils/StatusOr.h new file mode 100644 index 0000000000..c7aa4e4ae0 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/StatusOr.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_STATUSOR_H +#define NETUTILS_STATUSOR_H + +#include +#include "netdutils/Status.h" + +namespace android { +namespace netdutils { + +// Wrapper around a combination of Status and application value type. +// T may be any copyable or movable type. +template +class [[nodiscard]] StatusOr { + public: + // Constructs a new StatusOr with status::undefined status. + // This is marked 'explicit' to try to catch cases like 'return {};', + // where people think StatusOr> will be initialized + // with an empty vector, instead of a status::undefined. + explicit StatusOr() = default; + + // Implicit copy constructor and construction from T. + // NOLINTNEXTLINE(google-explicit-constructor) + StatusOr(Status status) : mStatus(std::move(status)) { assert(!isOk(mStatus)); } + + // Implicit construction from T. It is convenient and sensible to be able + // to do 'return T()' when the return type is StatusOr. + // NOLINTNEXTLINE(google-explicit-constructor) + StatusOr(const T& value) : mStatus(status::ok), mValue(value) {} + // NOLINTNEXTLINE(google-explicit-constructor) + StatusOr(T&& value) : mStatus(status::ok), mValue(std::move(value)) {} + + // Move constructor ok (if T supports move) + StatusOr(StatusOr&&) noexcept = default; + // Move assignment ok (if T supports move) + StatusOr& operator=(StatusOr&&) noexcept = default; + // Copy constructor ok (if T supports copy) + StatusOr(const StatusOr&) = default; + // Copy assignment ok (if T supports copy) + StatusOr& operator=(const StatusOr&) = default; + + // Returns a const reference to wrapped type. + // It is an error to call value() when !isOk(status()) + const T& value() const & { return mValue; } + const T&& value() const && { return mValue; } + + // Returns an rvalue reference to wrapped type + // It is an error to call value() when !isOk(status()) + // + // If T is expensive to copy but supports efficient move, it can be moved + // out of a StatusOr as follows: + // T value = std::move(statusor).value(); + T& value() & { return mValue; } + T&& value() && { return mValue; } + + // Returns the Status object assigned at construction time. + const Status status() const { return mStatus; } + + // Explicitly ignores the Status without triggering [[nodiscard]] errors. + void ignoreError() const {} + + // Implicit cast to Status. + // NOLINTNEXTLINE(google-explicit-constructor) + operator Status() const { return status(); } + + private: + Status mStatus = status::undefined; + T mValue; +}; + +template +inline std::ostream& operator<<(std::ostream& os, const StatusOr& s) { + return os << "StatusOr[status: " << s.status() << "]"; +} + +#define ASSIGN_OR_RETURN_IMPL(tmp, lhs, stmt) \ + auto tmp = (stmt); \ + RETURN_IF_NOT_OK(tmp); \ + lhs = std::move(tmp.value()); + +#define ASSIGN_OR_RETURN_CONCAT(line, lhs, stmt) \ + ASSIGN_OR_RETURN_IMPL(__CONCAT(_status_or_, line), lhs, stmt) + +// Macro to allow exception-like handling of error return values. +// +// If the evaluation of stmt results in an error, return that error +// from the current function. Otherwise, assign the result to lhs. +// +// This macro supports both move and copy assignment operators. lhs +// may be either a new local variable or an existing non-const +// variable accessible in the current scope. +// +// Example usage: +// StatusOr foo() { ... } +// +// ASSIGN_OR_RETURN(auto myVar, foo()); +// ASSIGN_OR_RETURN(myExistingVar, foo()); +// ASSIGN_OR_RETURN(myMemberVar, foo()); +#define ASSIGN_OR_RETURN(lhs, stmt) ASSIGN_OR_RETURN_CONCAT(__LINE__, lhs, stmt) + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_STATUSOR_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Stopwatch.h b/staticlibs/netd/libnetdutils/include/netdutils/Stopwatch.h new file mode 100644 index 0000000000..e7b4326455 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Stopwatch.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef NETDUTILS_STOPWATCH_H +#define NETDUTILS_STOPWATCH_H + +#include + +namespace android { +namespace netdutils { + +class Stopwatch { + private: + using clock = std::chrono::steady_clock; + using time_point = std::chrono::time_point; + + public: + Stopwatch() : mStart(clock::now()) {} + virtual ~Stopwatch() = default; + + int64_t timeTakenUs() const { return getElapsedUs(clock::now()); } + int64_t getTimeAndResetUs() { + const auto& now = clock::now(); + int64_t elapsed = getElapsedUs(now); + mStart = now; + return elapsed; + } + + private: + time_point mStart; + + int64_t getElapsedUs(const time_point& now) const { + return (std::chrono::duration_cast(now - mStart)).count(); + } +}; + +} // namespace netdutils +} // namespace android + +#endif // NETDUTILS_STOPWATCH_H diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Syscalls.h b/staticlibs/netd/libnetdutils/include/netdutils/Syscalls.h new file mode 100644 index 0000000000..36fcd85328 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Syscalls.h @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETDUTILS_SYSCALLS_H +#define NETDUTILS_SYSCALLS_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "netdutils/Fd.h" +#include "netdutils/Slice.h" +#include "netdutils/Socket.h" +#include "netdutils/Status.h" +#include "netdutils/StatusOr.h" +#include "netdutils/UniqueFd.h" +#include "netdutils/UniqueFile.h" + +namespace android { +namespace netdutils { + +class Syscalls { + public: + virtual ~Syscalls() = default; + + virtual StatusOr open(const std::string& pathname, int flags, + mode_t mode = 0) const = 0; + + virtual StatusOr socket(int domain, int type, int protocol) const = 0; + + virtual Status getsockname(Fd sock, sockaddr* addr, socklen_t* addrlen) const = 0; + + virtual Status getsockopt(Fd sock, int level, int optname, void *optval, + socklen_t *optlen) const = 0; + + virtual Status setsockopt(Fd sock, int level, int optname, const void* optval, + socklen_t optlen) const = 0; + + virtual Status bind(Fd sock, const sockaddr* addr, socklen_t addrlen) const = 0; + + virtual Status connect(Fd sock, const sockaddr* addr, socklen_t addrlen) const = 0; + + virtual StatusOr ioctl(Fd sock, unsigned long request, ifreq* ifr) const = 0; + + virtual StatusOr eventfd(unsigned int initval, int flags) const = 0; + + virtual StatusOr ppoll(pollfd* fds, nfds_t nfds, double timeout) const = 0; + + virtual StatusOr writev(Fd fd, const std::vector& iov) const = 0; + + virtual StatusOr write(Fd fd, const Slice buf) const = 0; + + virtual StatusOr read(Fd fd, const Slice buf) const = 0; + + virtual StatusOr sendto(Fd sock, const Slice buf, int flags, const sockaddr* dst, + socklen_t dstlen) const = 0; + + virtual StatusOr recvfrom(Fd sock, const Slice dst, int flags, sockaddr* src, + socklen_t* srclen) const = 0; + + virtual Status shutdown(Fd fd, int how) const = 0; + + virtual Status close(Fd fd) const = 0; + + virtual StatusOr fopen(const std::string& path, const std::string& mode) const = 0; + + virtual StatusOr vfprintf(FILE* file, const char* format, va_list ap) const = 0; + + virtual StatusOr vfscanf(FILE* file, const char* format, va_list ap) const = 0; + + virtual Status fclose(FILE* file) const = 0; + + virtual StatusOr fork() const = 0; + + // va_args helpers + // va_start doesn't work when the preceding argument is a reference + // type so we're forced to use const char*. + StatusOr fprintf(FILE* file, const char* format, ...) const { + va_list ap; + va_start(ap, format); + auto result = vfprintf(file, format, ap); + va_end(ap); + return result; + } + + // va_start doesn't work when the preceding argument is a reference + // type so we're forced to use const char*. + StatusOr fscanf(FILE* file, const char* format, ...) const { + va_list ap; + va_start(ap, format); + auto result = vfscanf(file, format, ap); + va_end(ap); + return result; + } + + // Templated helpers that forward directly to methods declared above + template + StatusOr getsockname(Fd sock) const { + SockaddrT addr = {}; + socklen_t addrlen = sizeof(addr); + RETURN_IF_NOT_OK(getsockname(sock, asSockaddrPtr(&addr), &addrlen)); + return addr; + } + + template + Status getsockopt(Fd sock, int level, int optname, void* optval, socklen_t* optlen) const { + return getsockopt(sock, level, optname, optval, optlen); + } + + template + Status setsockopt(Fd sock, int level, int optname, const SockoptT& opt) const { + return setsockopt(sock, level, optname, &opt, sizeof(opt)); + } + + template + Status bind(Fd sock, const SockaddrT& addr) const { + return bind(sock, asSockaddrPtr(&addr), sizeof(addr)); + } + + template + Status connect(Fd sock, const SockaddrT& addr) const { + return connect(sock, asSockaddrPtr(&addr), sizeof(addr)); + } + + template + StatusOr> ppoll(const std::array& fds, uint16_t events, + double timeout) const { + std::array tmp; + for (size_t i = 0; i < size; ++i) { + tmp[i].fd = fds[i].get(); + tmp[i].events = events; + tmp[i].revents = 0; + } + RETURN_IF_NOT_OK(ppoll(tmp.data(), tmp.size(), timeout).status()); + std::array out; + for (size_t i = 0; i < size; ++i) { + out[i] = tmp[i].revents; + } + return out; + } + + template + StatusOr sendto(Fd sock, const Slice buf, int flags, const SockaddrT& dst) const { + return sendto(sock, buf, flags, asSockaddrPtr(&dst), sizeof(dst)); + } + + // Ignore src sockaddr + StatusOr recvfrom(Fd sock, const Slice dst, int flags) const { + return recvfrom(sock, dst, flags, nullptr, nullptr); + } + + template + StatusOr> recvfrom(Fd sock, const Slice dst, int flags) const { + SockaddrT addr = {}; + socklen_t addrlen = sizeof(addr); + ASSIGN_OR_RETURN(auto used, recvfrom(sock, dst, flags, asSockaddrPtr(&addr), &addrlen)); + return std::make_pair(used, addr); + } +}; + +// Specialized singleton that supports zero initialization and runtime +// override of contained pointer. +class SyscallsHolder { + public: + ~SyscallsHolder(); + + // Return a pointer to an unowned instance of Syscalls. + Syscalls& get(); + + // Testing only: set the value returned by getSyscalls. Return the old value. + // Callers are responsible for restoring the previous value returned + // by getSyscalls to avoid leaks. + Syscalls& swap(Syscalls& syscalls); + + private: + std::atomic mSyscalls{nullptr}; +}; + +// Syscalls instance used throughout netdutils +extern SyscallsHolder sSyscalls; + +} // namespace netdutils +} // namespace android + +#endif /* NETDUTILS_SYSCALLS_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/ThreadUtil.h b/staticlibs/netd/libnetdutils/include/netdutils/ThreadUtil.h new file mode 100644 index 0000000000..62e6f70c90 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/ThreadUtil.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETDUTILS_THREADUTIL_H +#define NETDUTILS_THREADUTIL_H + +#include +#include + +#include + +namespace android { +namespace netdutils { + +struct scoped_pthread_attr { + scoped_pthread_attr() { pthread_attr_init(&attr); } + ~scoped_pthread_attr() { pthread_attr_destroy(&attr); } + + int detach() { return -pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); } + + pthread_attr_t attr; +}; + +inline void setThreadName(std::string name) { + // MAX_TASK_COMM_LEN=16 is not exported by bionic. + const size_t MAX_TASK_COMM_LEN = 16; + + // Crop name to 16 bytes including the NUL byte, as required by pthread_setname_np() + if (name.size() >= MAX_TASK_COMM_LEN) name.resize(MAX_TASK_COMM_LEN - 1); + + if (int ret = pthread_setname_np(pthread_self(), name.c_str()); ret != 0) { + LOG(WARNING) << "Unable to set thread name to " << name << ": " << strerror(ret); + } +} + +template +inline void* runAndDelete(void* obj) { + std::unique_ptr handler(reinterpret_cast(obj)); + setThreadName(handler->threadName().c_str()); + handler->run(); + return nullptr; +} + +template +inline int threadLaunch(T* obj) { + if (obj == nullptr) { + return -EINVAL; + } + + scoped_pthread_attr scoped_attr; + + int rval = scoped_attr.detach(); + if (rval != 0) { + return rval; + } + + pthread_t thread; + rval = pthread_create(&thread, &scoped_attr.attr, &runAndDelete, obj); + if (rval != 0) { + LOG(WARNING) << __func__ << ": pthread_create failed: " << rval; + return -rval; + } + + return rval; +} + +} // namespace netdutils +} // namespace android + +#endif // NETDUTILS_THREADUTIL_H diff --git a/staticlibs/netd/libnetdutils/include/netdutils/UidConstants.h b/staticlibs/netd/libnetdutils/include/netdutils/UidConstants.h new file mode 100644 index 0000000000..42c10908aa --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/UidConstants.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef NETDUTILS_UID_CONSTANTS_H +#define NETDUTILS_UID_CONSTANTS_H + +// These are used by both eBPF kernel programs and netd, we cannot put them in NetdConstant.h since +// we have to minimize the number of headers included by the BPF kernel program. +#define MIN_SYSTEM_UID 0 +#define MAX_SYSTEM_UID 9999 + +#define PER_USER_RANGE 100000 + +#endif // NETDUTILS_UID_CONSTANTS_H diff --git a/staticlibs/netd/libnetdutils/include/netdutils/UniqueFd.h b/staticlibs/netd/libnetdutils/include/netdutils/UniqueFd.h new file mode 100644 index 0000000000..61101f95ac --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/UniqueFd.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETUTILS_UNIQUEFD_H +#define NETUTILS_UNIQUEFD_H + +#include +#include + +#include "netdutils/Fd.h" + +namespace android { +namespace netdutils { + +// Stricter unique_fd implementation that: +// *) Does not implement release() +// *) Does not implicitly cast to int +// *) Uses a strongly typed wrapper (Fd) for the underlying file descriptor +// +// Users of UniqueFd should endeavor to treat this as a completely +// opaque object. The only code that should interpret the wrapped +// value is in Syscalls.h +class UniqueFd { + public: + UniqueFd() = default; + + UniqueFd(Fd fd) : mFd(fd) {} + + ~UniqueFd() { reset(); } + + // Disallow copy + UniqueFd(const UniqueFd&) = delete; + UniqueFd& operator=(const UniqueFd&) = delete; + + // Allow move + UniqueFd(UniqueFd&& other) { std::swap(mFd, other.mFd); } + UniqueFd& operator=(UniqueFd&& other) { + std::swap(mFd, other.mFd); + return *this; + } + + // Cleanup any currently owned Fd, replacing it with the optional + // parameter fd + void reset(Fd fd = Fd()); + + // Implict cast to Fd + operator const Fd &() const { return mFd; } + + private: + Fd mFd; +}; + +std::ostream& operator<<(std::ostream& os, const UniqueFd& fd); + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_UNIQUEFD_H */ diff --git a/staticlibs/netd/libnetdutils/include/netdutils/UniqueFile.h b/staticlibs/netd/libnetdutils/include/netdutils/UniqueFile.h new file mode 100644 index 0000000000..6dd6d6728e --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/UniqueFile.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETDUTILS_UNIQUEFILE_H +#define NETDUTILS_UNIQUEFILE_H + +#include +#include + +namespace android { +namespace netdutils { + +struct UniqueFileDtor { + void operator()(FILE* file) const; +}; + +using UniqueFile = std::unique_ptr; + +} // namespace netdutils +} // namespace android + +#endif /* NETDUTILS_UNIQUEFILE_H */ From 601d6f9c7173056a0ae89ca4ea5c54d59ee76341 Mon Sep 17 00:00:00 2001 From: Aswin Sankar Date: Mon, 11 Oct 2021 13:12:16 -0700 Subject: [PATCH 281/777] Spin off DnsPacket into separate library - Packages that don't need the entire 'net-utils-framework-common' library can depend on this lightweight library. - This library does not depend on 'framework-annotations' which was a problem for the mainline modularization team in allowing other libs to depend on it. - Spins off the DnsRecord parsing logic into its own class so that custom DNS resolvers can re-use it. Test: atest NetworkStaticLibTests Bug: 193442330 Change-Id: I27d6ee4591d8ab126b7df31f0df8377794fa50f1 --- staticlibs/Android.bp | 14 ++- .../android/net/module/util/DnsPacket.java | 91 ++++---------- .../net/module/util/DnsPacketUtils.java | 116 ++++++++++++++++++ 3 files changed, 150 insertions(+), 71 deletions(-) create mode 100644 staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index e8918c61c5..0585c09c71 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -84,6 +84,19 @@ java_defaults { ], } +java_library { + name: "net-utils-dnspacket-common", + srcs: [ + "framework/**/DnsPacket.java", + "framework/**/DnsPacketUtils.java", + ], + sdk_version: "module_current", + visibility: [ + "//packages/services/Iwlan:__subpackages__", + ], + libs: ["framework-annotations-lib"], +} + filegroup { name: "net-utils-framework-common-srcs", srcs: ["framework/**/*.java"], @@ -91,7 +104,6 @@ filegroup { visibility: [ "//frameworks/base", "//packages/modules/Connectivity:__subpackages__", - "//frameworks/base/packages/Connectivity/framework", ], } diff --git a/staticlibs/framework/com/android/net/module/util/DnsPacket.java b/staticlibs/framework/com/android/net/module/util/DnsPacket.java index 5ac731cb0f..4c88000278 100644 --- a/staticlibs/framework/com/android/net/module/util/DnsPacket.java +++ b/staticlibs/framework/com/android/net/module/util/DnsPacket.java @@ -18,12 +18,11 @@ package com.android.net.module.util; import android.annotation.NonNull; import android.annotation.Nullable; -import android.text.TextUtils; + +import com.android.net.module.util.DnsPacketUtils.DnsRecordParser; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; -import java.text.DecimalFormat; -import java.text.FieldPosition; import java.util.ArrayList; import java.util.List; @@ -60,6 +59,11 @@ public abstract class DnsPacket { public final int rcode; private final int[] mRecordCount; + /* If this bit in the 'flags' field is set to 0, the DNS message corresponding to this + * header is a query; otherwise, it is a response. + */ + private static final int FLAGS_SECTION_QR_BIT = 15; + /** * Create a new DnsHeader from a positioned ByteBuffer. * @@ -79,6 +83,14 @@ public abstract class DnsPacket { } } + /** + * Determines if the DNS message corresponding to this header is a response, as defined in + * RFC 1035 Section 4.1.1. + */ + public boolean isResponse() { + return (flags & (1 << FLAGS_SECTION_QR_BIT)) != 0; + } + /** * Get record count by type. */ @@ -95,12 +107,8 @@ public abstract class DnsPacket { */ public class DnsRecord { private static final int MAXNAMESIZE = 255; - private static final int MAXLABELSIZE = 63; - private static final int MAXLABELCOUNT = 128; public static final int NAME_NORMAL = 0; public static final int NAME_COMPRESSION = 0xC0; - private final DecimalFormat mByteFormat = new DecimalFormat(); - private final FieldPosition mPos = new FieldPosition(0); private static final String TAG = "DnsRecord"; @@ -118,12 +126,12 @@ public abstract class DnsPacket { * advanced to the end of the DNS header record. * This is meant to chain with other methods reading a DNS response in sequence. * - * @param ByteBuffer input of record, must be in network byte order + * @param buf ByteBuffer input of record, must be in network byte order * (which is the default). */ DnsRecord(int recordType, @NonNull ByteBuffer buf) throws BufferUnderflowException, ParseException { - dName = parseName(buf, 0 /* Parse depth */); + dName = DnsRecordParser.parseName(buf, 0 /* Parse depth */); if (dName.length() > MAXNAMESIZE) { throw new ParseException( "Parse name fail, name size is too long: " + dName.length()); @@ -150,66 +158,6 @@ public abstract class DnsPacket { return (mRdata == null) ? null : mRdata.clone(); } - /** - * Convert label from {@code byte[]} to {@code String} - * - * Follows the same conversion rules of the native code (ns_name.c in libc) - */ - private String labelToString(@NonNull byte[] label) { - final StringBuffer sb = new StringBuffer(); - for (int i = 0; i < label.length; ++i) { - int b = Byte.toUnsignedInt(label[i]); - // Control characters and non-ASCII characters. - if (b <= 0x20 || b >= 0x7f) { - // Append the byte as an escaped decimal number, e.g., "\19" for 0x13. - sb.append('\\'); - mByteFormat.format(b, sb, mPos); - } else if (b == '"' || b == '.' || b == ';' || b == '\\' - || b == '(' || b == ')' || b == '@' || b == '$') { - // Append the byte as an escaped character, e.g., "\:" for 0x3a. - sb.append('\\'); - sb.append((char) b); - } else { - // Append the byte as a character, e.g., "a" for 0x61. - sb.append((char) b); - } - } - return sb.toString(); - } - - private String parseName(@NonNull ByteBuffer buf, int depth) throws - BufferUnderflowException, ParseException { - if (depth > MAXLABELCOUNT) { - throw new ParseException("Failed to parse name, too many labels"); - } - final int len = Byte.toUnsignedInt(buf.get()); - final int mask = len & NAME_COMPRESSION; - if (0 == len) { - return ""; - } else if (mask != NAME_NORMAL && mask != NAME_COMPRESSION) { - throw new ParseException("Parse name fail, bad label type"); - } else if (mask == NAME_COMPRESSION) { - // Name compression based on RFC 1035 - 4.1.4 Message compression - final int offset = ((len & ~NAME_COMPRESSION) << 8) + Byte.toUnsignedInt(buf.get()); - final int oldPos = buf.position(); - if (offset >= oldPos - 2) { - throw new ParseException("Parse compression name fail, invalid compression"); - } - buf.position(offset); - final String pointed = parseName(buf, depth + 1); - buf.position(oldPos); - return pointed; - } else { - final byte[] label = new byte[len]; - buf.get(label); - final String head = labelToString(label); - if (head.length() > MAXLABELSIZE) { - throw new ParseException("Parse name fail, invalid label length"); - } - final String tail = parseName(buf, depth + 1); - return TextUtils.isEmpty(tail) ? head : head + "." + tail; - } - } } public static final int QDSECTION = 0; @@ -224,7 +172,10 @@ public abstract class DnsPacket { protected final List[] mRecords; protected DnsPacket(@NonNull byte[] data) throws ParseException { - if (null == data) throw new ParseException("Parse header failed, null input data"); + if (null == data) { + throw new ParseException("Parse header failed, null input data"); + } + final ByteBuffer buffer; try { buffer = ByteBuffer.wrap(data); diff --git a/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java b/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java new file mode 100644 index 0000000000..677474c554 --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util; + +import static com.android.net.module.util.DnsPacket.DnsRecord.NAME_COMPRESSION; +import static com.android.net.module.util.DnsPacket.DnsRecord.NAME_NORMAL; + +import android.annotation.NonNull; +import android.text.TextUtils; + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.text.DecimalFormat; +import java.text.FieldPosition; + +/** + * Utilities for decoding the contents of a DnsPacket. + * + * @hide + */ +public final class DnsPacketUtils { + /** + * Reads the passed ByteBuffer from its current position and decodes a DNS record. + */ + public static class DnsRecordParser { + private static final int MAXLABELSIZE = 63; + private static final int MAXLABELCOUNT = 128; + + private static final DecimalFormat sByteFormat = new DecimalFormat(); + private static final FieldPosition sPos = new FieldPosition(0); + + /** + * Convert label from {@code byte[]} to {@code String} + * + *

Follows the same conversion rules of the native code (ns_name.c in libc). + */ + private static String labelToString(@NonNull byte[] label) { + final StringBuffer sb = new StringBuffer(); + + for (int i = 0; i < label.length; ++i) { + int b = Byte.toUnsignedInt(label[i]); + // Control characters and non-ASCII characters. + if (b <= 0x20 || b >= 0x7f) { + // Append the byte as an escaped decimal number, e.g., "\19" for 0x13. + sb.append('\\'); + sByteFormat.format(b, sb, sPos); + } else if (b == '"' || b == '.' || b == ';' || b == '\\' || b == '(' || b == ')' + || b == '@' || b == '$') { + // Append the byte as an escaped character, e.g., "\:" for 0x3a. + sb.append('\\'); + sb.append((char) b); + } else { + // Append the byte as a character, e.g., "a" for 0x61. + sb.append((char) b); + } + } + return sb.toString(); + } + + /** + * Parses the domain / target name of a DNS record. + */ + public static String parseName(ByteBuffer buf, int depth) throws + BufferUnderflowException, DnsPacket.ParseException { + if (depth > MAXLABELCOUNT) { + throw new DnsPacket.ParseException("Failed to parse name, too many labels"); + } + final int len = Byte.toUnsignedInt(buf.get()); + final int mask = len & NAME_COMPRESSION; + if (0 == len) { + return ""; + } else if (mask != NAME_NORMAL && mask != NAME_COMPRESSION) { + throw new DnsPacket.ParseException("Parse name fail, bad label type: " + mask); + } else if (mask == NAME_COMPRESSION) { + // Name compression based on RFC 1035 - 4.1.4 Message compression + final int offset = ((len & ~NAME_COMPRESSION) << 8) + Byte.toUnsignedInt(buf.get()); + final int oldPos = buf.position(); + if (offset >= oldPos - 2) { + throw new DnsPacket.ParseException( + "Parse compression name fail, invalid compression"); + } + buf.position(offset); + final String pointed = parseName(buf, depth + 1); + buf.position(oldPos); + return pointed; + } else { + final byte[] label = new byte[len]; + buf.get(label); + final String head = labelToString(label); + if (head.length() > MAXLABELSIZE) { + throw new DnsPacket.ParseException("Parse name fail, invalid label length"); + } + final String tail = parseName(buf, depth + 1); + return TextUtils.isEmpty(tail) ? head : head + "." + tail; + } + } + + private DnsRecordParser() {} + } + + private DnsPacketUtils() {} +} From cf858ba920c66565ae60ebbfc6321f4ce77260e2 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 24 Nov 2021 16:28:09 +0900 Subject: [PATCH 282/777] Replace assert with assertTrue in CleanupTest Test: NetworkStaticLibTests Change-Id: I9b403d4d3491a5ee34b69d1fa4767defdaff70c2 --- .../android/net/module/util/CleanupTest.kt | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt index f4a7d10385..af4d818d94 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt @@ -22,6 +22,7 @@ import kotlin.test.assertFailsWith import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +import kotlin.test.assertTrue import kotlin.test.fail private val TAG = CleanupTest::class.toString() @@ -38,11 +39,11 @@ class CleanupTest { x = 2 Log.e(TAG, "Do nothing") } cleanup { - assert(x == 2) + assertTrue(x == 2) x = 3 Log.e(TAG, "Do nothing") } - assert(x == 3) + assertTrue(x == 3) } @Test @@ -54,12 +55,12 @@ class CleanupTest { throw TestException1() x = 4 } cleanup { - assert(x == 2) + assertTrue(x == 2) x = 3 Log.e(TAG, "Do nothing") } } - assert(x == 3) + assertTrue(x == 3) } @Test @@ -70,13 +71,13 @@ class CleanupTest { x = 2 Log.e(TAG, "Do nothing") } cleanup { - assert(x == 2) + assertTrue(x == 2) x = 3 throw TestException2() x = 4 } } - assert(x == 3) + assertTrue(x == 3) } @Test @@ -88,15 +89,15 @@ class CleanupTest { throw TestException1() x = 3 } cleanup { - assert(x == 2) + assertTrue(x == 2) x = 4 throw TestException2() x = 5 } fail("Expected failure with TestException1") } catch (e: TestException1) { - assert(e.suppressedExceptions[0] is TestException2) + assertTrue(e.suppressedExceptions[0] is TestException2) } - assert(x == 4) + assertTrue(x == 4) } } From bfbcacef6de970a10041675cea903159dedfa02f Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 22 Nov 2021 21:21:25 +0900 Subject: [PATCH 283/777] Make sure no suppressed expression is present when they shouldn't In fact the test already passes, because addSuppressed contains an explicit test that if this === argument, then it doesn't add it. But otherwise that's a bug in tryCleanup Test: NetworkStaticLibTests Change-Id: I202790bbe8d82445c5affdd9076561c2c6ea9b59 --- .../com/android/net/module/util/CleanupTest.kt | 17 ++++++++--------- .../hostdevice/com/android/testutils/Cleanup.kt | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt index af4d818d94..05faed1cb0 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt @@ -18,14 +18,13 @@ package com.android.net.module.util import android.util.Log import com.android.testutils.tryTest -import kotlin.test.assertFailsWith import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +import kotlin.test.assertFailsWith import kotlin.test.assertTrue -import kotlin.test.fail -private val TAG = CleanupTest::class.toString() +private val TAG = CleanupTest::class.simpleName @RunWith(JUnit4::class) class CleanupTest { @@ -49,7 +48,7 @@ class CleanupTest { @Test fun testThrowTry() { var x = 1 - assertFailsWith { + val thrown = assertFailsWith { tryTest { x = 2 throw TestException1() @@ -60,13 +59,14 @@ class CleanupTest { Log.e(TAG, "Do nothing") } } + assertTrue(thrown.suppressedExceptions.isEmpty()) assertTrue(x == 3) } @Test fun testThrowCleanup() { var x = 1 - assertFailsWith { + val thrown = assertFailsWith { tryTest { x = 2 Log.e(TAG, "Do nothing") @@ -77,13 +77,14 @@ class CleanupTest { x = 4 } } + assertTrue(thrown.suppressedExceptions.isEmpty()) assertTrue(x == 3) } @Test fun testThrowBoth() { var x = 1 - try { + val thrown = assertFailsWith { tryTest { x = 2 throw TestException1() @@ -94,10 +95,8 @@ class CleanupTest { throw TestException2() x = 5 } - fail("Expected failure with TestException1") - } catch (e: TestException1) { - assertTrue(e.suppressedExceptions[0] is TestException2) } + assertTrue(thrown.suppressedExceptions[0] is TestException2) assertTrue(x == 4) } } diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt index 769d98068c..fb45582f97 100644 --- a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt +++ b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt @@ -63,7 +63,6 @@ class ExceptionCleanupBlock(val originalException: Exception?) { inline infix fun cleanup(block: () -> Unit) { try { block() - if (null != originalException) throw originalException } catch (e: Exception) { if (null == originalException) { throw e @@ -72,6 +71,7 @@ class ExceptionCleanupBlock(val originalException: Exception?) { throw originalException } } + if (null != originalException) throw originalException } } From 7df6f89c371857406e72c803b8a6bebe7a162851 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 24 Nov 2021 13:44:42 +0900 Subject: [PATCH 284/777] Disallow non-local returns in tryTest{} Non-local returns will prevent the execution of the cleanup{} block, which is too much of a footgun to allow. See the bug for details of how it happens. There doesn't seem to be a way to keep the nice syntax, allow non-local returns and still guarantee execution of the cleanup block in all cases. Thus, forbid non-local returns. Users can still use return@tryTest to accomplish almost the same thing, and the next patch will also let tryTest{} return its last evaluated value, fixing remaining cases. E.g. tryTest { foo() if (condition) return result bar() } cleanup { doCleanup() } can always be written return tryTest { foo() if (condition) return@tryTest result bar() } cleanup { doCleanup() } ...and it's a rare case, so the additional syntax is acceptable. Test: NetworkStaticLibTests Bug: 207358921 Change-Id: I40443acf7e4d86813641adc877e27fb2334d0daf --- .../testutils/hostdevice/com/android/testutils/Cleanup.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt index fb45582f97..bacbbe35b8 100644 --- a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt +++ b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt @@ -76,7 +76,7 @@ class ExceptionCleanupBlock(val originalException: Exception?) { } @CheckReturnValue -inline fun tryTest(block: () -> Unit): ExceptionCleanupBlock { +fun tryTest(block: () -> Unit): ExceptionCleanupBlock { try { block() } catch (e: Exception) { From b6fdf63095f59539c48df9e21a1f369e272bbb59 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 22 Nov 2021 19:28:34 +0900 Subject: [PATCH 285/777] tryTest to return its last evaluated expression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the same thing try{} does, and allows to lift return out of tryTest. This allows syntaxes like : fun foo() = try { "Foo"; } cleanup { doSomeCleanup() } } val network = try { registerNetworkCallback callback.getNetwork() } cleanup { unregisterNetworkCallback } } Note: bypassing ktlint because of b/185077240 Test: FrameworksNetTests Change-Id: Ib8f6fde7ccfd62fdcb3c1e3b7b03909ed94d4b23 --- .../android/net/module/util/CleanupTest.kt | 9 +++- .../net/module/util/CleanupTestJava.java | 4 +- staticlibs/testutils/Android.bp | 48 +++++++++++-------- .../com/android/testutils/Cleanup.kt | 34 +++++++------ 4 files changed, 59 insertions(+), 36 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt index 05faed1cb0..cc0f9bec14 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt @@ -34,15 +34,17 @@ class CleanupTest { @Test fun testNotThrow() { var x = 1 - tryTest { + val result = tryTest { x = 2 Log.e(TAG, "Do nothing") + 6 } cleanup { assertTrue(x == 2) x = 3 Log.e(TAG, "Do nothing") } assertTrue(x == 3) + assertTrue(result == 6) } @Test @@ -99,4 +101,9 @@ class CleanupTest { assertTrue(thrown.suppressedExceptions[0] is TestException2) assertTrue(x == 4) } + + @Test + fun testReturn() { + assertTrue(6 == tryTest { 6 } cleanup { Log.e(TAG, "tested") }) + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTestJava.java b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTestJava.java index ba4e679eb1..83abfa16d6 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTestJava.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTestJava.java @@ -35,14 +35,16 @@ public class CleanupTestJava { @Test public void testNotThrow() { final AtomicInteger x = new AtomicInteger(1); - testAndCleanup(() -> { + final int a = testAndCleanup(() -> { x.compareAndSet(1, 2); Log.e(TAG, "Do nothing"); + return 6; }, () -> { x.compareAndSet(2, 3); Log.e(TAG, "Do nothing"); }); assertEquals(3, x.get()); + assertEquals(6, a); } @Test diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index 2f0bcc3951..29df759b04 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -42,26 +42,34 @@ java_library { } java_library { - // Consider using net-tests-utils instead if writing device code. - // That library has a lot more useful tools into it for users that - // work on Android and includes this lib. - name: "net-tests-utils-host-device-common", - srcs: [ - "hostdevice/**/*.java", - "hostdevice/**/*.kt", - ], - host_supported: true, - visibility: [ - "//frameworks/libs/net/common/tests:__subpackages__", - "//frameworks/libs/net/client-libs/tests:__subpackages__", - ], - libs: [ - "jsr305", - ], - static_libs: [ - "kotlin-test" - ], - lint: { strict_updatability_linting: true }, + // Consider using net-tests-utils instead if writing device code. + // That library has a lot more useful tools into it for users that + // work on Android and includes this lib. + name: "net-tests-utils-host-device-common", + srcs: [ + "hostdevice/**/*.java", + "hostdevice/**/*.kt", + ], + host_supported: true, + visibility: [ + "//frameworks/libs/net/common/tests:__subpackages__", + "//frameworks/libs/net/client-libs/tests:__subpackages__", + ], + // sc-mainline-prod uses an old version of Kotlin that used + // to reserve the right to make breaking changes to the + // Result type and disallowed returning an instance of it. + // Later versions allowed this and there was never a change, + // so no matter the version returning Result is always fine, + // but on sc-mainline-prod the compiler rejects it without + // the following flag. + kotlincflags: ["-Xallow-result-return-type"], + libs: [ + "jsr305", + ], + static_libs: [ + "kotlin-test" + ], + lint: { strict_updatability_linting: true }, } java_test_host { diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt index bacbbe35b8..d93c7d0893 100644 --- a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt +++ b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt @@ -19,6 +19,7 @@ package com.android.testutils import com.android.testutils.ExceptionUtils.ThrowingRunnable +import com.android.testutils.ExceptionUtils.ThrowingSupplier import javax.annotation.CheckReturnValue /** @@ -59,11 +60,15 @@ import javax.annotation.CheckReturnValue * cleanup code * }); */ -class ExceptionCleanupBlock(val originalException: Exception?) { - inline infix fun cleanup(block: () -> Unit) { +// sc-mainline-prod has an older kotlin that doesn't know about value classes. TODO : Change this +// to "value class" when aosp no longer merges into sc-mainline-prod. +@Suppress("INLINE_CLASS_DEPRECATED") +inline class ExceptionCleanupBlock(val result: Result) { + inline infix fun cleanup(block: () -> Unit): T { try { block() } catch (e: Exception) { + val originalException = result.exceptionOrNull() if (null == originalException) { throw e } else { @@ -71,25 +76,26 @@ class ExceptionCleanupBlock(val originalException: Exception?) { throw originalException } } - if (null != originalException) throw originalException + return result.getOrThrow() } } @CheckReturnValue -fun tryTest(block: () -> Unit): ExceptionCleanupBlock { - try { - block() - } catch (e: Exception) { - return ExceptionCleanupBlock(e) - } - return ExceptionCleanupBlock(null) -} +fun tryTest(block: () -> T) = ExceptionCleanupBlock( + try { + Result.success(block()) + } catch (e: Exception) { + Result.failure(e) + }) // Java support -fun testAndCleanup(tryBlock: ThrowingRunnable, cleanupBlock: ThrowingRunnable) { - tryTest { - tryBlock.run() +fun testAndCleanup(tryBlock: ThrowingSupplier, cleanupBlock: ThrowingRunnable): T { + return tryTest { + tryBlock.get() } cleanup { cleanupBlock.run() } } +fun testAndCleanup(tryBlock: ThrowingRunnable, cleanupBlock: ThrowingRunnable) { + return testAndCleanup(ThrowingSupplier { tryBlock.run() }, cleanupBlock) +} From 8f0a33054b8b95a3d84793671bdfdfc63947cc1e Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 24 Nov 2021 14:29:53 +0900 Subject: [PATCH 286/777] Add catch{} to tryTest{} Usage is tryTest { ... }.catch { it } cleanup { ... } Test: New tests for this Change-Id: Idb7d9bd33034921c8f212288179b34a175e866f4 --- .../android/net/module/util/CleanupTest.kt | 66 +++++++++++++++++++ .../com/android/testutils/Cleanup.kt | 17 +++++ 2 files changed, 83 insertions(+) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt index cc0f9bec14..006793170b 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt @@ -21,8 +21,10 @@ import com.android.testutils.tryTest import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertTrue +import kotlin.test.fail private val TAG = CleanupTest::class.simpleName @@ -104,6 +106,70 @@ class CleanupTest { @Test fun testReturn() { + val resultIfSuccess = 11 + val resultIfException = 12 + fun doTestReturn(crash: Boolean) = tryTest { + if (crash) throw RuntimeException() else resultIfSuccess + }.catch { + resultIfException + } cleanup {} + assertTrue(6 == tryTest { 6 } cleanup { Log.e(TAG, "tested") }) + assertEquals(resultIfSuccess, doTestReturn(crash = false)) + assertEquals(resultIfException, doTestReturn(crash = true)) + } + + @Test + fun testCatch() { + var x = 1 + tryTest { + x = 2 + throw TestException1() + x = 3 + }.catch { + x = 4 + }.catch { + x = 5 + } cleanup { + assertTrue(x == 4) + x = 6 + } + assertTrue(x == 6) + } + + @Test + fun testNotCatch() { + var x = 1 + assertFailsWith { + tryTest { + x = 2 + throw TestException1() + }.catch { + fail("Caught TestException2 instead of TestException1") + } cleanup { + assertTrue(x == 2) + x = 3 + } + } + assertTrue(x == 3) + } + + @Test + fun testThrowInCatch() { + var x = 1 + val thrown = assertFailsWith { + tryTest { + x = 2 + throw TestException1() + }.catch { + x = 3 + throw TestException2() + } cleanup { + assertTrue(x == 3) + x = 4 + } + } + assertTrue(x == 4) + assertTrue(thrown.suppressedExceptions.isEmpty()) } } diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt index d93c7d0893..0f7ec70f89 100644 --- a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt +++ b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt @@ -52,6 +52,12 @@ import javax.annotation.CheckReturnValue * } cleanup { * cleanup code * } + * Catch blocks can be added with the following syntax : + * tryTest { + * testing code + * }.catch { it -> + * do something to it + * } * * Java doesn't allow this kind of syntax, so instead a function taking 2 lambdas is provided. * testAndCleanup(() -> { @@ -60,10 +66,21 @@ import javax.annotation.CheckReturnValue * cleanup code * }); */ + // sc-mainline-prod has an older kotlin that doesn't know about value classes. TODO : Change this // to "value class" when aosp no longer merges into sc-mainline-prod. @Suppress("INLINE_CLASS_DEPRECATED") inline class ExceptionCleanupBlock(val result: Result) { + inline infix fun catch(block: (E) -> T): ExceptionCleanupBlock { + val originalException = result.exceptionOrNull() + if (originalException !is E) return this + return ExceptionCleanupBlock(try { + Result.success(block(originalException)) + } catch (e: Exception) { + Result.failure(e) + }) + } + inline infix fun cleanup(block: () -> Unit): T { try { block() From 2918ada95870dcdd7acdb42520929880c89921df Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 24 Nov 2021 17:01:08 +0900 Subject: [PATCH 287/777] Rename ExceptionCleanupBlock into TryExpr This is a lot more inline with standard compiling theory Test: NetworkStaticLibTests Change-Id: I32c8926cb08a30b4a87bc6867ce194483a7f0c3a --- .../testutils/hostdevice/com/android/testutils/Cleanup.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt index 0f7ec70f89..22b9b6c63d 100644 --- a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt +++ b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt @@ -70,11 +70,11 @@ import javax.annotation.CheckReturnValue // sc-mainline-prod has an older kotlin that doesn't know about value classes. TODO : Change this // to "value class" when aosp no longer merges into sc-mainline-prod. @Suppress("INLINE_CLASS_DEPRECATED") -inline class ExceptionCleanupBlock(val result: Result) { - inline infix fun catch(block: (E) -> T): ExceptionCleanupBlock { +inline class TryExpr(val result: Result) { + inline infix fun catch(block: (E) -> T): TryExpr { val originalException = result.exceptionOrNull() if (originalException !is E) return this - return ExceptionCleanupBlock(try { + return TryExpr(try { Result.success(block(originalException)) } catch (e: Exception) { Result.failure(e) @@ -98,7 +98,7 @@ inline class ExceptionCleanupBlock(val result: Result) { } @CheckReturnValue -fun tryTest(block: () -> T) = ExceptionCleanupBlock( +fun tryTest(block: () -> T) = TryExpr( try { Result.success(block()) } catch (e: Exception) { From 28348e43aee99b159746d0e28e1814d25d25bffc Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 24 Nov 2021 17:34:53 +0900 Subject: [PATCH 288/777] Have tryTest{} work with throwables Test: NetworkStaticLibTests Change-Id: I9ee52e7d34866c82e169bbecbca3f928bfd79993 --- .../testutils/hostdevice/com/android/testutils/Cleanup.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt index 22b9b6c63d..eec8128df0 100644 --- a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt +++ b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt @@ -84,7 +84,7 @@ inline class TryExpr(val result: Result) { inline infix fun cleanup(block: () -> Unit): T { try { block() - } catch (e: Exception) { + } catch (e: Throwable) { val originalException = result.exceptionOrNull() if (null == originalException) { throw e @@ -101,7 +101,7 @@ inline class TryExpr(val result: Result) { fun tryTest(block: () -> T) = TryExpr( try { Result.success(block()) - } catch (e: Exception) { + } catch (e: Throwable) { Result.failure(e) }) From bb84528e38c470e4d061858eb1068b58ecbc3fa6 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 22 Sep 2021 09:26:32 +0000 Subject: [PATCH 289/777] Add more logs in TestableNetworkStatsProvider Test: m gts && atest \ GtsNetworkStackHostTestCases:NetworkStatsHostTest#testNetworkStatsProvider Bug: 175742577 Change-Id: Ib8f45a20879517af08f9bf9cbb2b16314351d2da --- .../com/android/testutils/TestableNetworkStatsProvider.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt index be5c9b2eab..4a7b351346 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProvider.kt @@ -17,6 +17,7 @@ package com.android.testutils import android.net.netstats.provider.NetworkStatsProvider +import android.util.Log import com.android.net.module.util.ArrayTrackRecord import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -43,23 +44,28 @@ open class TestableNetworkStatsProvider( data class OnSetAlert(val quotaBytes: Long) : CallbackType() } + private val TAG = this::class.simpleName val history = ArrayTrackRecord().newReadHead() // See ReadHead#mark val mark get() = history.mark override fun onRequestStatsUpdate(token: Int) { + Log.d(TAG, "onRequestStatsUpdate $token") history.add(CallbackType.OnRequestStatsUpdate(token)) } override fun onSetWarningAndLimit(iface: String, warningBytes: Long, limitBytes: Long) { + Log.d(TAG, "onSetWarningAndLimit $iface $warningBytes $limitBytes") history.add(CallbackType.OnSetWarningAndLimit(iface, warningBytes, limitBytes)) } override fun onSetLimit(iface: String, quotaBytes: Long) { + Log.d(TAG, "onSetLimit $iface $quotaBytes") history.add(CallbackType.OnSetLimit(iface, quotaBytes)) } override fun onSetAlert(quotaBytes: Long) { + Log.d(TAG, "onSetAlert $quotaBytes") history.add(CallbackType.OnSetAlert(quotaBytes)) } From fee2cab5d6d4ff1ce7bd2a6126043a8d064604a9 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 25 Nov 2021 19:54:31 +0900 Subject: [PATCH 290/777] Correct a comment Test: TH Change-Id: I08ac8f0f40b9e3732564da73057cd3d22c06c79b --- staticlibs/testutils/Android.bp | 4 ++-- .../com/android/testutils/Cleanup.kt | 20 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index 29df759b04..1be64c1e6c 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -55,8 +55,8 @@ java_library { "//frameworks/libs/net/common/tests:__subpackages__", "//frameworks/libs/net/client-libs/tests:__subpackages__", ], - // sc-mainline-prod uses an old version of Kotlin that used - // to reserve the right to make breaking changes to the + // There are downstream branches using an old version of Kotlin + // that used to reserve the right to make breaking changes to the // Result type and disallowed returning an instance of it. // Later versions allowed this and there was never a change, // so no matter the version returning Result is always fine, diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt index eec8128df0..1b67f68cc4 100644 --- a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt +++ b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt @@ -22,6 +22,14 @@ import com.android.testutils.ExceptionUtils.ThrowingRunnable import com.android.testutils.ExceptionUtils.ThrowingSupplier import javax.annotation.CheckReturnValue +@CheckReturnValue +fun tryTest(block: () -> T) = TryExpr( + try { + Result.success(block()) + } catch (e: Throwable) { + Result.failure(e) + }) + /** * Utility to do cleanup in tests without replacing exceptions with those from a finally block. * @@ -67,8 +75,8 @@ import javax.annotation.CheckReturnValue * }); */ -// sc-mainline-prod has an older kotlin that doesn't know about value classes. TODO : Change this -// to "value class" when aosp no longer merges into sc-mainline-prod. +// Some downstream branches have an older kotlin that doesn't know about value classes. +// TODO : Change this to "value class" when aosp no longer merges into such branches. @Suppress("INLINE_CLASS_DEPRECATED") inline class TryExpr(val result: Result) { inline infix fun catch(block: (E) -> T): TryExpr { @@ -97,14 +105,6 @@ inline class TryExpr(val result: Result) { } } -@CheckReturnValue -fun tryTest(block: () -> T) = TryExpr( - try { - Result.success(block()) - } catch (e: Throwable) { - Result.failure(e) - }) - // Java support fun testAndCleanup(tryBlock: ThrowingSupplier, cleanupBlock: ThrowingRunnable): T { return tryTest { From 0dc0f8770db7d3f716341cce85c160bdec70ddb7 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Tue, 14 Sep 2021 20:03:26 +0800 Subject: [PATCH 291/777] Add StructIpv4Header class to parse IPv4 header from a packet Note that this class doesn't contain options field. Test: atest NetworkStaticLibTests Change-Id: If5062d8612e277bb283e253a0c7aa79ea9a3ce60 --- .../net/module/util/structs/Ipv4Header.java | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/structs/Ipv4Header.java diff --git a/staticlibs/device/com/android/net/module/util/structs/Ipv4Header.java b/staticlibs/device/com/android/net/module/util/structs/Ipv4Header.java new file mode 100644 index 0000000000..5249454c44 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/Ipv4Header.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import androidx.annotation.VisibleForTesting; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.Inet4Address; + +/** + * L3 IPv4 header as per https://tools.ietf.org/html/rfc791. + * This class doesn't contain options field. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Version| IHL |Type of Service| Total Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Identification |Flags| Fragment Offset | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Time to Live | Protocol | Header Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source Address | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Destination Address | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class Ipv4Header extends Struct { + // IP Version=IPv4, IHL is always 5(*4bytes) because options are not supported. + @VisibleForTesting + public static final byte IPHDR_VERSION_IHL = 0x45; + + @Field(order = 0, type = Type.S8) + // version (4 bits), IHL (4 bits) + public final byte vi; + @Field(order = 1, type = Type.S8) + public final byte tos; + @Field(order = 2, type = Type.U16) + public final int totalLength; + @Field(order = 3, type = Type.S16) + public final short id; + @Field(order = 4, type = Type.S16) + // flags (3 bits), fragment offset (13 bits) + public final short flagsAndFragmentOffset; + @Field(order = 5, type = Type.U8) + public final short ttl; + @Field(order = 6, type = Type.S8) + public final byte protocol; + @Field(order = 7, type = Type.S16) + public final short checksum; + @Field(order = 8, type = Type.Ipv4Address) + public final Inet4Address srcIp; + @Field(order = 9, type = Type.Ipv4Address) + public final Inet4Address dstIp; + + public Ipv4Header(final byte tos, final int totalLength, final short id, + final short flagsAndFragmentOffset, final short ttl, final byte protocol, + final short checksum, final Inet4Address srcIp, final Inet4Address dstIp) { + this(IPHDR_VERSION_IHL, tos, totalLength, id, flagsAndFragmentOffset, ttl, + protocol, checksum, srcIp, dstIp); + } + + private Ipv4Header(final byte vi, final byte tos, final int totalLength, final short id, + final short flagsAndFragmentOffset, final short ttl, final byte protocol, + final short checksum, final Inet4Address srcIp, final Inet4Address dstIp) { + this.vi = vi; + this.tos = tos; + this.totalLength = totalLength; + this.id = id; + this.flagsAndFragmentOffset = flagsAndFragmentOffset; + this.ttl = ttl; + this.protocol = protocol; + this.checksum = checksum; + this.srcIp = srcIp; + this.dstIp = dstIp; + } +} From 0b2577504f5990057f9b5a49988003d1ddfab10d Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Tue, 14 Sep 2021 20:09:00 +0800 Subject: [PATCH 292/777] Add StructTcpHeader class to parse TCP header from a packet Note that this class does not contain option and data fields. Test: atest NetworkStaticLibTests Change-Id: Icda61c129c9693e504d3f19a05242677b9dc41da --- .../net/module/util/structs/TcpHeader.java | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/structs/TcpHeader.java diff --git a/staticlibs/device/com/android/net/module/util/structs/TcpHeader.java b/staticlibs/device/com/android/net/module/util/structs/TcpHeader.java new file mode 100644 index 0000000000..0c97401c78 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/TcpHeader.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * L4 TCP header as per https://tools.ietf.org/html/rfc793. + * This class does not contain option and data fields. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source Port | Destination Port | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Acknowledgment Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Data | |U|A|P|R|S|F| | + * | Offset| Reserved |R|C|S|S|Y|I| Window | + * | | |G|K|H|T|N|N| | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Checksum | Urgent Pointer | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Options | Padding | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | data | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class TcpHeader extends Struct { + @Field(order = 0, type = Type.U16) + public final int srcPort; + @Field(order = 1, type = Type.U16) + public final int dstPort; + @Field(order = 2, type = Type.U32) + public final long seq; + @Field(order = 3, type = Type.U32) + public final long ack; + @Field(order = 4, type = Type.S16) + // data Offset (4 bits), reserved (6 bits), control bits (6 bits) + // TODO: update with bitfields once class Struct supports it + public final short dataOffsetAndControlBits; + @Field(order = 5, type = Type.U16) + public final int window; + @Field(order = 6, type = Type.S16) + public final short checksum; + @Field(order = 7, type = Type.U16) + public final int urgentPointer; + + public TcpHeader(final int srcPort, final int dstPort, final long seq, final long ack, + final short dataOffsetAndControlBits, final int window, final short checksum, + final int urgentPointer) { + this.srcPort = srcPort; + this.dstPort = dstPort; + this.seq = seq; + this.ack = ack; + this.dataOffsetAndControlBits = dataOffsetAndControlBits; + this.window = window; + this.checksum = checksum; + this.urgentPointer = urgentPointer; + } +} From ab4bf15d76256e605225d9a226d0a36bc1b376a4 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Mon, 29 Nov 2021 06:57:17 +0000 Subject: [PATCH 293/777] Add IFF_UP device flag constant in NetlinkConstants. Bug: 163492391 Test: atest NetworkStaticLibTests Change-Id: I81965261e8ccecd680504d3d98378973d6f44436 --- .../com/android/net/module/util/netlink/NetlinkConstants.java | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java index 83a82b74bd..c44a5b4839 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java @@ -151,6 +151,7 @@ public class NetlinkConstants { public static final int RTMGRP_ND_USEROPT = 1 << (RTNLGRP_ND_USEROPT - 1); // Device flags. + public static final int IFF_UP = 1 << 0; public static final int IFF_LOWER_UP = 1 << 16; // Known values for struct rtmsg rtm_protocol. From 37176da85b534d14afc263398786b68011f0a329 Mon Sep 17 00:00:00 2001 From: Aswin Sankar Date: Wed, 24 Nov 2021 23:21:41 +0000 Subject: [PATCH 294/777] [DnsPacketUtils] Knob for name compression support - Allows clients of DnsRecordParser to explicitly mention whether name compression is supported. Test: atest NetworkStaticLibTests Bug: b/207710965 Change-Id: Iac92f062a16f8f28f58cb180ab27e7626a9bd701 --- .../android/net/module/util/DnsPacket.java | 3 +- .../net/module/util/DnsPacketUtils.java | 15 ++- .../net/module/util/DnsPacketUtilsTest.java | 119 ++++++++++++++++++ 3 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java diff --git a/staticlibs/framework/com/android/net/module/util/DnsPacket.java b/staticlibs/framework/com/android/net/module/util/DnsPacket.java index 4c88000278..080781c1ff 100644 --- a/staticlibs/framework/com/android/net/module/util/DnsPacket.java +++ b/staticlibs/framework/com/android/net/module/util/DnsPacket.java @@ -131,7 +131,8 @@ public abstract class DnsPacket { */ DnsRecord(int recordType, @NonNull ByteBuffer buf) throws BufferUnderflowException, ParseException { - dName = DnsRecordParser.parseName(buf, 0 /* Parse depth */); + dName = DnsRecordParser.parseName(buf, 0 /* Parse depth */, + /* isNameCompressionSupported= */ true); if (dName.length() > MAXNAMESIZE) { throw new ParseException( "Parse name fail, name size is too long: " + dName.length()); diff --git a/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java b/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java index 677474c554..3448cadf6f 100644 --- a/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java +++ b/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java @@ -73,8 +73,14 @@ public final class DnsPacketUtils { /** * Parses the domain / target name of a DNS record. + * + * As described in RFC 1035 Section 4.1.3, the NAME field of a DNS Resource Record always + * supports Name Compression, whereas domain names contained in the RDATA payload of a DNS + * record may or may not support Name Compression, depending on the record TYPE. Moreover, + * even if Name Compression is supported, its usage is left to the implementation. */ - public static String parseName(ByteBuffer buf, int depth) throws + public static String parseName(ByteBuffer buf, int depth, + boolean isNameCompressionSupported) throws BufferUnderflowException, DnsPacket.ParseException { if (depth > MAXLABELCOUNT) { throw new DnsPacket.ParseException("Failed to parse name, too many labels"); @@ -83,7 +89,8 @@ public final class DnsPacketUtils { final int mask = len & NAME_COMPRESSION; if (0 == len) { return ""; - } else if (mask != NAME_NORMAL && mask != NAME_COMPRESSION) { + } else if (mask != NAME_NORMAL && mask != NAME_COMPRESSION + || (!isNameCompressionSupported && mask == NAME_COMPRESSION)) { throw new DnsPacket.ParseException("Parse name fail, bad label type: " + mask); } else if (mask == NAME_COMPRESSION) { // Name compression based on RFC 1035 - 4.1.4 Message compression @@ -94,7 +101,7 @@ public final class DnsPacketUtils { "Parse compression name fail, invalid compression"); } buf.position(offset); - final String pointed = parseName(buf, depth + 1); + final String pointed = parseName(buf, depth + 1, isNameCompressionSupported); buf.position(oldPos); return pointed; } else { @@ -104,7 +111,7 @@ public final class DnsPacketUtils { if (head.length() > MAXLABELSIZE) { throw new DnsPacket.ParseException("Parse name fail, invalid label length"); } - final String tail = parseName(buf, depth + 1); + final String tail = parseName(buf, depth + 1, isNameCompressionSupported); return TextUtils.isEmpty(tail) ? head : head + "." + tail; } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java new file mode 100644 index 0000000000..48777acc7f --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util; + +import static com.android.net.module.util.DnsPacketUtils.DnsRecordParser; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.nio.ByteBuffer; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class DnsPacketUtilsTest { + + /** + * Verifies that the compressed NAME field in the answer section of the DNS message is parsed + * successfully when name compression is permitted. Additionally, verifies that a + * {@link DnsPacket.ParseException} is thrown in a hypothetical scenario where name compression + * is not expected. + */ + @Test + public void testParsingAnswerSectionNameCompressed() throws Exception { + final byte[] v4blobNameCompressedAnswer = new byte[] { + /* Header */ + 0x55, 0x66, /* Transaction ID */ + (byte) 0x81, (byte) 0x80, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x01, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + /* Answers */ + (byte) 0xc0, 0x0c, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + 0x00, 0x00, 0x01, 0x2b, /* TTL */ + 0x00, 0x04, /* Data length */ + (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 /* Address */ + }; + final int answerOffsetBytePosition = 32; + final ByteBuffer nameCompressedBuf = ByteBuffer.wrap(v4blobNameCompressedAnswer); + + nameCompressedBuf.position(answerOffsetBytePosition); + assertThrows(DnsPacket.ParseException.class, () -> DnsRecordParser.parseName( + nameCompressedBuf, /* depth= */ 0, /* isNameCompressionSupported= */false)); + + nameCompressedBuf.position(answerOffsetBytePosition); + String domainName = DnsRecordParser.parseName( + nameCompressedBuf, /* depth= */ 0, /* isNameCompressionSupported= */true); + assertEquals(domainName, "www.google.com"); + } + + /** + * Verifies that an uncompressed NAME field in the answer section of the DNS message is parsed + * successfully irrespective of whether name compression is permitted. + */ + @Test + public void testParsingAnswerSectionNoNameCompression() throws Exception { + final byte[] v4blobNoNameCompression = new byte[] { + /* Header */ + 0x55, 0x66, /* Transaction ID */ + (byte) 0x81, (byte) 0x80, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x01, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + /* Answers */ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + 0x00, 0x00, 0x01, 0x2b, /* TTL */ + 0x00, 0x04, /* Data length */ + (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 /* Address */ + }; + final int answerOffsetBytePosition = 32; + final ByteBuffer notNameCompressedBuf = ByteBuffer.wrap(v4blobNoNameCompression); + + notNameCompressedBuf.position(answerOffsetBytePosition); + String domainName = DnsRecordParser.parseName( + notNameCompressedBuf, /* depth= */ 0, /* isNameCompressionSupported= */ true); + assertEquals(domainName, "www.google.com"); + + notNameCompressedBuf.position(answerOffsetBytePosition); + domainName = DnsRecordParser.parseName( + notNameCompressedBuf, /* depth= */ 0, /* isNameCompressionSupported= */ false); + assertEquals(domainName, "www.google.com"); + } +} From 9adc333f21b651ce89ba35a62eaac3441fe59386 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Mon, 22 Nov 2021 06:59:13 +0000 Subject: [PATCH 295/777] Return null RtNetlinkAddressMessage if IFA_FLAGS attr is malformed. Bug: 163492391 Test: atest NetworkStaticLibsTests Change-Id: I62732634d7cc31c6ca8a3ea63bb76079d8d22c14 --- .../util/netlink/RtNetlinkAddressMessage.java | 7 ++--- .../net/module/util/netlink/StructNlAttr.java | 17 +++++++++--- .../module/util/netlink/StructNlAttrTest.java | 27 +++++++++++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java index a518c76b6b..f7b0d02fb7 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java @@ -114,9 +114,10 @@ public class RtNetlinkAddressMessage extends NetlinkMessage { // and will overwrite the flags set above. byteBuffer.position(baseOffset); nlAttr = StructNlAttr.findNextAttrOfType(IFA_FLAGS, byteBuffer); - if (nlAttr != null) { - addrMsg.mFlags = nlAttr.getValueAsInt(0 /* default value */); - } + if (nlAttr == null) return null; + final Integer value = nlAttr.getValueAsInteger(); + if (value == null) return null; + addrMsg.mFlags = value; return addrMsg; } diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNlAttr.java b/staticlibs/device/com/android/net/module/util/netlink/StructNlAttr.java index 485e67c84d..a9b6495082 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructNlAttr.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNlAttr.java @@ -287,14 +287,22 @@ public class StructNlAttr { } /** - * Get attribute value as Integer. + * Get attribute value as Integer, or null if malformed (e.g., length is not 4 bytes). */ - public int getValueAsInt(int defaultValue) { + public Integer getValueAsInteger() { final ByteBuffer byteBuffer = getValueAsByteBuffer(); if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) { - return defaultValue; + return null; } - return getValueAsByteBuffer().getInt(); + return byteBuffer.getInt(); + } + + /** + * Get attribute value as Int, default value if malformed. + */ + public int getValueAsInt(int defaultValue) { + final Integer value = getValueAsInteger(); + return (value != null) ? value : defaultValue; } /** @@ -341,6 +349,7 @@ public class StructNlAttr { public String getValueAsString() { if (nla_value == null) return null; // Check the attribute value length after removing string termination flag '\0'. + // This assumes that all netlink strings are null-terminated. if (nla_value.length < (nla_len - NLA_HEADERLEN - 1)) return null; try { diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlAttrTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlAttrTest.java index 72e179bc2e..af3fac2e7d 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlAttrTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlAttrTest.java @@ -16,6 +16,7 @@ package com.android.net.module.util.netlink; +import static com.android.net.module.util.netlink.RtNetlinkAddressMessage.IFA_FLAGS; import static com.android.net.module.util.netlink.RtNetlinkLinkMessage.IFLA_ADDRESS; import static com.android.net.module.util.netlink.RtNetlinkLinkMessage.IFLA_IFNAME; @@ -35,6 +36,7 @@ import org.junit.runner.RunWith; public class StructNlAttrTest { private static final MacAddress TEST_MAC_ADDRESS = MacAddress.fromString("00:11:22:33:44:55"); private static final String TEST_INTERFACE_NAME = "wlan0"; + private static final int TEST_ADDR_FLAGS = 0x80; @Test public void testGetValueAsMacAddress() { @@ -65,4 +67,29 @@ public class StructNlAttrTest { final String str2 = attr2.getValueAsString(); assertEquals(str2, TEST_INTERFACE_NAME); } + + @Test + public void testGetValueAsIntger() { + final StructNlAttr attr1 = new StructNlAttr(IFA_FLAGS, TEST_ADDR_FLAGS); + final Integer integer1 = attr1.getValueAsInteger(); + final int int1 = attr1.getValueAsInt(0x08 /* default value */); + assertEquals(integer1, new Integer(TEST_ADDR_FLAGS)); + assertEquals(int1, TEST_ADDR_FLAGS); + + // Malformed attribute. + final byte[] malformed_int = new byte[] { (byte) 0x0, (byte) 0x0, (byte) 0x80, }; + final StructNlAttr attr2 = new StructNlAttr(IFA_FLAGS, malformed_int); + final Integer integer2 = attr2.getValueAsInteger(); + final int int2 = attr2.getValueAsInt(0x08 /* default value */); + assertNull(integer2); + assertEquals(int2, 0x08 /* default value */); + + // Null attribute value. + final byte[] null_int = null; + final StructNlAttr attr3 = new StructNlAttr(IFA_FLAGS, null_int); + final Integer integer3 = attr3.getValueAsInteger(); + final int int3 = attr3.getValueAsInt(0x08 /* default value */); + assertNull(integer3); + assertEquals(int3, 0x08 /* default value */); + } } From 9efcabc929b2d62bdf37ae258a7c7fdee8a30c5b Mon Sep 17 00:00:00 2001 From: Alessio Balsini Date: Thu, 11 Nov 2021 15:12:18 +0000 Subject: [PATCH 296/777] Allow MediaProvider to use BPF utilities The FUSE daemon in MediaProvider needs to access the file descriptor of its pinned BPF program. The BPF syscall wrappers are handy and would avoid code duplication, thus extend this project visibility to MediaProvider. Bug: 202785178 Test: adb logcat FuseDaemon:V \*:S (in git_master) Signed-off-by: Alessio Balsini Change-Id: I406c760bb96d74597ca7d8f701cd12c3bd318f68 --- staticlibs/native/bpf_syscall_wrappers/Android.bp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index 1416b6bc70..379c8a94b2 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -30,12 +30,14 @@ cc_library_headers { min_sdk_version: "30", apex_available: [ "//apex_available:platform", + "com.android.mediaprovider", "com.android.tethering", ], visibility: [ "//frameworks/libs/net/common/native/bpfmapjni", "//packages/modules/Connectivity/service", "//packages/modules/Connectivity/Tethering", + "//packages/providers/MediaProvider/jni", "//system/bpf/libbpf_android", "//system/memory/lmkd", ], From fbbfadf3935a3eafb0505f695dcfe65cc6054b36 Mon Sep 17 00:00:00 2001 From: Tyler Wear Date: Thu, 2 Dec 2021 11:55:12 -0800 Subject: [PATCH 297/777] Move TestableNetworkAgent to Common Util Location To prep TestableNetworkAgent being accessible for multiple tests, move to common location. Change-Id: Ib885553550259509b4843cdbc91d2b4bbfaa5fb8 --- .../android/testutils/TestableNetworkAgent.kt | 200 ++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkAgent.kt diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkAgent.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkAgent.kt new file mode 100644 index 0000000000..40fb773338 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkAgent.kt @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2021 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 com.android.testutils; + +import android.content.Context +import android.net.KeepalivePacketData +import android.net.LinkProperties +import android.net.NetworkAgent +import android.net.NetworkAgentConfig +import android.net.NetworkCapabilities +import android.net.NetworkProvider +import android.net.QosFilter +import android.net.Uri +import android.os.Looper +import com.android.net.module.util.ArrayTrackRecord +import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnAddKeepalivePacketFilter +import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnAutomaticReconnectDisabled +import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnBandwidthUpdateRequested +import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkCreated +import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkDestroyed +import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted +import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnRegisterQosCallback +import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnRemoveKeepalivePacketFilter +import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnSaveAcceptUnvalidated +import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnSignalStrengthThresholdsUpdated +import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnStartSocketKeepalive +import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive +import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnUnregisterQosCallback +import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnValidationStatus +import java.time.Duration +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import kotlin.test.assertTrue +import org.junit.Assert.assertArrayEquals + +// Any legal score (0~99) for the test network would do, as it is going to be kept up by the +// requests filed by the test and should never match normal internet requests. 70 is the default +// score of Ethernet networks, it's as good a value as any other. +private const val TEST_NETWORK_SCORE = 70 + +private class Provider(context: Context, looper: Looper) : + NetworkProvider(context, looper, "NetworkAgentTest NetworkProvider") + +public open class TestableNetworkAgent( + context: Context, + looper: Looper, + val nc: NetworkCapabilities, + val lp: LinkProperties, + conf: NetworkAgentConfig +) : NetworkAgent(context, looper, TestableNetworkAgent::class.java.simpleName /* tag */, + nc, lp, TEST_NETWORK_SCORE, conf, Provider(context, looper)) { + + val DEFAULT_TIMEOUT_MS = 5000L + + val history = ArrayTrackRecord().newReadHead() + + sealed class CallbackEntry { + object OnBandwidthUpdateRequested : CallbackEntry() + object OnNetworkUnwanted : CallbackEntry() + data class OnAddKeepalivePacketFilter( + val slot: Int, + val packet: KeepalivePacketData + ) : CallbackEntry() + data class OnRemoveKeepalivePacketFilter(val slot: Int) : CallbackEntry() + data class OnStartSocketKeepalive( + val slot: Int, + val interval: Int, + val packet: KeepalivePacketData + ) : CallbackEntry() + data class OnStopSocketKeepalive(val slot: Int) : CallbackEntry() + data class OnSaveAcceptUnvalidated(val accept: Boolean) : CallbackEntry() + object OnAutomaticReconnectDisabled : CallbackEntry() + data class OnValidationStatus(val status: Int, val uri: Uri?) : CallbackEntry() + data class OnSignalStrengthThresholdsUpdated(val thresholds: IntArray) : CallbackEntry() + object OnNetworkCreated : CallbackEntry() + object OnNetworkDestroyed : CallbackEntry() + data class OnRegisterQosCallback( + val callbackId: Int, + val filter: QosFilter + ) : CallbackEntry() + data class OnUnregisterQosCallback(val callbackId: Int) : CallbackEntry() + } + + override fun onBandwidthUpdateRequested() { + history.add(OnBandwidthUpdateRequested) + } + + override fun onNetworkUnwanted() { + history.add(OnNetworkUnwanted) + } + + override fun onAddKeepalivePacketFilter(slot: Int, packet: KeepalivePacketData) { + history.add(OnAddKeepalivePacketFilter(slot, packet)) + } + + override fun onRemoveKeepalivePacketFilter(slot: Int) { + history.add(OnRemoveKeepalivePacketFilter(slot)) + } + + override fun onStartSocketKeepalive( + slot: Int, + interval: Duration, + packet: KeepalivePacketData + ) { + history.add(OnStartSocketKeepalive(slot, interval.seconds.toInt(), packet)) + } + + override fun onStopSocketKeepalive(slot: Int) { + history.add(OnStopSocketKeepalive(slot)) + } + + override fun onSaveAcceptUnvalidated(accept: Boolean) { + history.add(OnSaveAcceptUnvalidated(accept)) + } + + override fun onAutomaticReconnectDisabled() { + history.add(OnAutomaticReconnectDisabled) + } + + override fun onSignalStrengthThresholdsUpdated(thresholds: IntArray) { + history.add(OnSignalStrengthThresholdsUpdated(thresholds)) + } + + fun expectSignalStrengths(thresholds: IntArray? = intArrayOf()) { + expectCallback().let { + assertArrayEquals(thresholds, it.thresholds) + } + } + + override fun onQosCallbackRegistered(qosCallbackId: Int, filter: QosFilter) { + history.add(OnRegisterQosCallback(qosCallbackId, filter)) + } + + override fun onQosCallbackUnregistered(qosCallbackId: Int) { + history.add(OnUnregisterQosCallback(qosCallbackId)) + } + + override fun onValidationStatus(status: Int, uri: Uri?) { + history.add(OnValidationStatus(status, uri)) + } + + override fun onNetworkCreated() { + history.add(OnNetworkCreated) + } + + override fun onNetworkDestroyed() { + history.add(OnNetworkDestroyed) + } + + // Expects the initial validation event that always occurs immediately after registering + // a NetworkAgent whose network does not require validation (which test networks do + // not, since they lack the INTERNET capability). It always contains the default argument + // for the URI. + fun expectValidationBypassedStatus() = expectCallback().let { + assertEquals(it.status, VALID_NETWORK) + // The returned Uri is parsed from the empty string, which means it's an + // instance of the (private) Uri.StringUri. There are no real good ways + // to check this, the least bad is to just convert it to a string and + // make sure it's empty. + assertEquals("", it.uri.toString()) + } + + inline fun expectCallback(): T { + val foundCallback = history.poll(DEFAULT_TIMEOUT_MS) + assertTrue(foundCallback is T, "Expected ${T::class} but found $foundCallback") + return foundCallback + } + + inline fun expectCallback(valid: (T) -> Boolean) { + val foundCallback = history.poll(DEFAULT_TIMEOUT_MS) + assertTrue(foundCallback is T, "Expected ${T::class} but found $foundCallback") + assertTrue(valid(foundCallback), "Unexpected callback : $foundCallback") + } + + inline fun eventuallyExpect() = + history.poll(DEFAULT_TIMEOUT_MS) { it is T }.also { + assertNotNull(it, "Callback ${T::class} not received") + } as T + + fun assertNoCallback() { + assertTrue(waitForIdle(DEFAULT_TIMEOUT_MS), + "Handler didn't became idle after ${DEFAULT_TIMEOUT_MS}ms") + assertNull(history.peek()) + } +} \ No newline at end of file From de0bb525624bb559e90ad359ceb6962169f1f50f Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Mon, 25 Oct 2021 20:49:37 +0800 Subject: [PATCH 298/777] [NETD-BPF#15] Move BPF map definition and utils to frameworks/libs/net/ 1. Move BPF map definition and utilities to a common place that easy to be referenced from both mainline module and platform code. 2. Create cc_library_headers bpf_map_utils which includes BPF map definition and utils. Bug: 202086915 Test: m; flash; boot Test: cd system/netd/ && atest Test: cd packages/modules/Connectivity && atest Test: m gpuservice_unittest libtimeinstate_test bpf_module_test CtsAppOpsTestCases libbpf_load_test VtsBootconfigTest vts_test_binary_bpf_module bpf_benchmark libbpf_load_test libbpf_android_test Change-Id: I4d54b0d69029f593b8da3099d7ae16279692dabd --- staticlibs/native/bpf_map_utils/Android.bp | 73 +++++ .../native/bpf_map_utils/BpfMapTest.cpp | 244 ++++++++++++++++ staticlibs/native/bpf_map_utils/TEST_MAPPING | 7 + .../native/bpf_map_utils/include/bpf/BpfMap.h | 260 ++++++++++++++++++ .../bpf_map_utils/include/bpf/BpfUtils.h | 150 ++++++++++ .../include/bpf/WaitForProgsLoaded.h | 39 +++ 6 files changed, 773 insertions(+) create mode 100644 staticlibs/native/bpf_map_utils/Android.bp create mode 100644 staticlibs/native/bpf_map_utils/BpfMapTest.cpp create mode 100644 staticlibs/native/bpf_map_utils/TEST_MAPPING create mode 100644 staticlibs/native/bpf_map_utils/include/bpf/BpfMap.h create mode 100644 staticlibs/native/bpf_map_utils/include/bpf/BpfUtils.h create mode 100644 staticlibs/native/bpf_map_utils/include/bpf/WaitForProgsLoaded.h diff --git a/staticlibs/native/bpf_map_utils/Android.bp b/staticlibs/native/bpf_map_utils/Android.bp new file mode 100644 index 0000000000..521b682729 --- /dev/null +++ b/staticlibs/native/bpf_map_utils/Android.bp @@ -0,0 +1,73 @@ +// Copyright (C) 2021 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. + +cc_library_headers { + name: "bpf_map_utils", + vendor_available: true, + host_supported: true, + native_bridge_supported: true, + export_include_dirs: ["include"], + cflags: [ + "-Wall", + "-Werror", + ], + min_sdk_version: "30", + apex_available: [ + "//apex_available:platform", + "com.android.art.debug", + ], + visibility: [ + "//bootable/libbootloader/vts", + "//frameworks/base/services/core/jni", + "//frameworks/native/libs/cputimeinstate", + "//frameworks/native/services/gpuservice", + "//frameworks/native/services/gpuservice/gpumem", + "//frameworks/native/services/gpuservice/tests/unittests", + "//frameworks/native/services/gpuservice/tracing", + "//packages/modules/Connectivity/tests/unit/jni", + "//packages/modules/DnsResolver/tests", + "//system/bpf/bpfloader", + "//system/bpf/libbpf_android", + "//system/memory/libmeminfo", + "//system/netd/libnetdbpf", + "//system/netd/server", + "//system/netd/tests", + "//system/netd/tests/benchmarks", + "//test/vts-testcase/kernel/api/bpf_native_test", + ], +} + + +cc_test { + // TODO: Rename to bpf_map_test and modify .gcls as well. + name: "libbpf_android_test", + srcs: [ + "BpfMapTest.cpp", + ], + defaults: ["bpf_defaults"], + cflags: [ + "-Wall", + "-Werror", + "-Wno-error=unused-variable", + ], + static_libs: ["libgmock"], + shared_libs: [ + "libbpf_android", + "libbase", + "liblog", + "libutils", + ], + require_root: true, + test_suites: ["general-tests"], +} diff --git a/staticlibs/native/bpf_map_utils/BpfMapTest.cpp b/staticlibs/native/bpf_map_utils/BpfMapTest.cpp new file mode 100644 index 0000000000..d0737b0f78 --- /dev/null +++ b/staticlibs/native/bpf_map_utils/BpfMapTest.cpp @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2018 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. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "bpf/BpfMap.h" +#include "bpf/BpfUtils.h" + +using ::testing::Test; + +namespace android { +namespace bpf { + +using base::Result; +using base::unique_fd; + +constexpr uint32_t TEST_MAP_SIZE = 10; +constexpr uint32_t TEST_KEY1 = 1; +constexpr uint32_t TEST_VALUE1 = 10; +constexpr const char PINNED_MAP_PATH[] = "/sys/fs/bpf/testMap"; + +class BpfMapTest : public testing::Test { + protected: + BpfMapTest() {} + + void SetUp() { + EXPECT_EQ(0, setrlimitForTest()); + if (!access(PINNED_MAP_PATH, R_OK)) { + EXPECT_EQ(0, remove(PINNED_MAP_PATH)); + } + } + + void TearDown() { + if (!access(PINNED_MAP_PATH, R_OK)) { + EXPECT_EQ(0, remove(PINNED_MAP_PATH)); + } + } + + void checkMapInvalid(BpfMap& map) { + EXPECT_FALSE(map.isValid()); + EXPECT_EQ(-1, map.getMap().get()); + } + + void checkMapValid(BpfMap& map) { + EXPECT_LE(0, map.getMap().get()); + EXPECT_TRUE(map.isValid()); + } + + void writeToMapAndCheck(BpfMap& map, uint32_t key, uint32_t value) { + ASSERT_RESULT_OK(map.writeValue(key, value, BPF_ANY)); + uint32_t value_read; + ASSERT_EQ(0, findMapEntry(map.getMap(), &key, &value_read)); + checkValueAndStatus(value, value_read); + } + + void checkValueAndStatus(uint32_t refValue, Result value) { + ASSERT_RESULT_OK(value); + ASSERT_EQ(refValue, value.value()); + } + + void populateMap(uint32_t total, BpfMap& map) { + for (uint32_t key = 0; key < total; key++) { + uint32_t value = key * 10; + EXPECT_RESULT_OK(map.writeValue(key, value, BPF_ANY)); + } + } + + void expectMapEmpty(BpfMap& map) { + Result isEmpty = map.isEmpty(); + ASSERT_RESULT_OK(isEmpty); + ASSERT_TRUE(isEmpty.value()); + } +}; + +TEST_F(BpfMapTest, constructor) { + BpfMap testMap1; + checkMapInvalid(testMap1); + + BpfMap testMap2(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); + checkMapValid(testMap2); +} + +TEST_F(BpfMapTest, basicHelpers) { + BpfMap testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); + uint32_t key = TEST_KEY1; + uint32_t value_write = TEST_VALUE1; + writeToMapAndCheck(testMap, key, value_write); + Result value_read = testMap.readValue(key); + checkValueAndStatus(value_write, value_read); + Result key_read = testMap.getFirstKey(); + checkValueAndStatus(key, key_read); + ASSERT_RESULT_OK(testMap.deleteValue(key)); + ASSERT_GT(0, findMapEntry(testMap.getMap(), &key, &value_read)); + ASSERT_EQ(ENOENT, errno); +} + +TEST_F(BpfMapTest, reset) { + BpfMap testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); + uint32_t key = TEST_KEY1; + uint32_t value_write = TEST_VALUE1; + writeToMapAndCheck(testMap, key, value_write); + + testMap.reset(-1); + checkMapInvalid(testMap); + ASSERT_GT(0, findMapEntry(testMap.getMap(), &key, &value_write)); + ASSERT_EQ(EBADF, errno); +} + +TEST_F(BpfMapTest, moveConstructor) { + BpfMap testMap1(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); + BpfMap testMap2; + testMap2 = std::move(testMap1); + uint32_t key = TEST_KEY1; + checkMapInvalid(testMap1); + uint32_t value = TEST_VALUE1; + writeToMapAndCheck(testMap2, key, value); +} + +TEST_F(BpfMapTest, SetUpMap) { + EXPECT_NE(0, access(PINNED_MAP_PATH, R_OK)); + BpfMap testMap1(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); + ASSERT_EQ(0, bpfFdPin(testMap1.getMap(), PINNED_MAP_PATH)); + EXPECT_EQ(0, access(PINNED_MAP_PATH, R_OK)); + checkMapValid(testMap1); + BpfMap testMap2; + EXPECT_RESULT_OK(testMap2.init(PINNED_MAP_PATH)); + checkMapValid(testMap2); + uint32_t key = TEST_KEY1; + uint32_t value = TEST_VALUE1; + writeToMapAndCheck(testMap1, key, value); + Result value_read = testMap2.readValue(key); + checkValueAndStatus(value, value_read); +} + +TEST_F(BpfMapTest, iterate) { + BpfMap testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); + populateMap(TEST_MAP_SIZE, testMap); + int totalCount = 0; + int totalSum = 0; + const auto iterateWithDeletion = [&totalCount, &totalSum](const uint32_t& key, + BpfMap& map) { + EXPECT_GE((uint32_t)TEST_MAP_SIZE, key); + totalCount++; + totalSum += key; + return map.deleteValue(key); + }; + EXPECT_RESULT_OK(testMap.iterate(iterateWithDeletion)); + EXPECT_EQ((int)TEST_MAP_SIZE, totalCount); + EXPECT_EQ(((1 + TEST_MAP_SIZE - 1) * (TEST_MAP_SIZE - 1)) / 2, (uint32_t)totalSum); + expectMapEmpty(testMap); +} + +TEST_F(BpfMapTest, iterateWithValue) { + BpfMap testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); + populateMap(TEST_MAP_SIZE, testMap); + int totalCount = 0; + int totalSum = 0; + const auto iterateWithDeletion = [&totalCount, &totalSum](const uint32_t& key, + const uint32_t& value, + BpfMap& map) { + EXPECT_GE((uint32_t)TEST_MAP_SIZE, key); + EXPECT_EQ(value, key * 10); + totalCount++; + totalSum += value; + return map.deleteValue(key); + }; + EXPECT_RESULT_OK(testMap.iterateWithValue(iterateWithDeletion)); + EXPECT_EQ((int)TEST_MAP_SIZE, totalCount); + EXPECT_EQ(((1 + TEST_MAP_SIZE - 1) * (TEST_MAP_SIZE - 1)) * 5, (uint32_t)totalSum); + expectMapEmpty(testMap); +} + +TEST_F(BpfMapTest, mapIsEmpty) { + BpfMap testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); + expectMapEmpty(testMap); + uint32_t key = TEST_KEY1; + uint32_t value_write = TEST_VALUE1; + writeToMapAndCheck(testMap, key, value_write); + Result isEmpty = testMap.isEmpty(); + ASSERT_RESULT_OK(isEmpty); + ASSERT_FALSE(isEmpty.value()); + ASSERT_RESULT_OK(testMap.deleteValue(key)); + ASSERT_GT(0, findMapEntry(testMap.getMap(), &key, &value_write)); + ASSERT_EQ(ENOENT, errno); + expectMapEmpty(testMap); + int entriesSeen = 0; + EXPECT_RESULT_OK(testMap.iterate( + [&entriesSeen](const unsigned int&, + const BpfMap&) -> Result { + entriesSeen++; + return {}; + })); + EXPECT_EQ(0, entriesSeen); + EXPECT_RESULT_OK(testMap.iterateWithValue( + [&entriesSeen](const unsigned int&, const unsigned int&, + const BpfMap&) -> Result { + entriesSeen++; + return {}; + })); + EXPECT_EQ(0, entriesSeen); +} + +TEST_F(BpfMapTest, mapClear) { + BpfMap testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); + populateMap(TEST_MAP_SIZE, testMap); + Result isEmpty = testMap.isEmpty(); + ASSERT_RESULT_OK(isEmpty); + ASSERT_FALSE(*isEmpty); + ASSERT_RESULT_OK(testMap.clear()); + expectMapEmpty(testMap); +} + +} // namespace bpf +} // namespace android diff --git a/staticlibs/native/bpf_map_utils/TEST_MAPPING b/staticlibs/native/bpf_map_utils/TEST_MAPPING new file mode 100644 index 0000000000..9ec8a40853 --- /dev/null +++ b/staticlibs/native/bpf_map_utils/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "libbpf_android_test" + } + ] +} diff --git a/staticlibs/native/bpf_map_utils/include/bpf/BpfMap.h b/staticlibs/native/bpf_map_utils/include/bpf/BpfMap.h new file mode 100644 index 0000000000..bdffc0f0bb --- /dev/null +++ b/staticlibs/native/bpf_map_utils/include/bpf/BpfMap.h @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2018 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. + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include "bpf/BpfUtils.h" + +namespace android { +namespace bpf { + +// This is a class wrapper for eBPF maps. The eBPF map is a special in-kernel +// data structure that stores data in pairs. It can be read/write +// from userspace by passing syscalls with the map file descriptor. This class +// is used to generalize the procedure of interacting with eBPF maps and hide +// the implementation detail from other process. Besides the basic syscalls +// wrapper, it also provides some useful helper functions as well as an iterator +// nested class to iterate the map more easily. +// +// NOTE: A kernel eBPF map may be accessed by both kernel and userspace +// processes at the same time. Or if the map is pinned as a virtual file, it can +// be obtained by multiple eBPF map class object and accessed concurrently. +// Though the map class object and the underlying kernel map are thread safe, it +// is not safe to iterate over a map while another thread or process is deleting +// from it. In this case the iteration can return duplicate entries. +template +class BpfMap { + public: + BpfMap() {}; + + protected: + // flag must be within BPF_OBJ_FLAG_MASK, ie. 0, BPF_F_RDONLY, BPF_F_WRONLY + BpfMap(const char* pathname, uint32_t flags) { + int map_fd = mapRetrieve(pathname, flags); + if (map_fd >= 0) mMapFd.reset(map_fd); + } + + public: + explicit BpfMap(const char* pathname) : BpfMap(pathname, 0) {} + + BpfMap(bpf_map_type map_type, uint32_t max_entries, uint32_t map_flags = 0) { + int map_fd = createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags); + if (map_fd >= 0) mMapFd.reset(map_fd); + } + + base::Result getFirstKey() const { + Key firstKey; + if (getFirstMapKey(mMapFd, &firstKey)) { + return ErrnoErrorf("Get firstKey map {} failed", mMapFd.get()); + } + return firstKey; + } + + base::Result getNextKey(const Key& key) const { + Key nextKey; + if (getNextMapKey(mMapFd, &key, &nextKey)) { + return ErrnoErrorf("Get next key of map {} failed", mMapFd.get()); + } + return nextKey; + } + + base::Result writeValue(const Key& key, const Value& value, uint64_t flags) { + if (writeToMapEntry(mMapFd, &key, &value, flags)) { + return ErrnoErrorf("Write to map {} failed", mMapFd.get()); + } + return {}; + } + + base::Result readValue(const Key key) const { + Value value; + if (findMapEntry(mMapFd, &key, &value)) { + return ErrnoErrorf("Read value of map {} failed", mMapFd.get()); + } + return value; + } + + base::Result deleteValue(const Key& key) { + if (deleteMapEntry(mMapFd, &key)) { + return ErrnoErrorf("Delete entry from map {} failed", mMapFd.get()); + } + return {}; + } + + // Function that tries to get map from a pinned path. + base::Result init(const char* path); + + // Iterate through the map and handle each key retrieved based on the filter + // without modification of map content. + base::Result iterate( + const std::function(const Key& key, const BpfMap& map)>& + filter) const; + + // Iterate through the map and get each pair, handle each pair based on the filter without modification of map content. + base::Result iterateWithValue( + const std::function(const Key& key, const Value& value, + const BpfMap& map)>& filter) const; + + // Iterate through the map and handle each key retrieved based on the filter + base::Result iterate( + const std::function(const Key& key, BpfMap& map)>& + filter); + + // Iterate through the map and get each pair, handle each pair based on the filter. + base::Result iterateWithValue( + const std::function(const Key& key, const Value& value, + BpfMap& map)>& filter); + + const base::unique_fd& getMap() const { return mMapFd; }; + + // Copy assignment operator + BpfMap& operator=(const BpfMap& other) { + if (this != &other) mMapFd.reset(fcntl(other.mMapFd.get(), F_DUPFD_CLOEXEC, 0)); + return *this; + } + + // Move assignment operator + BpfMap& operator=(BpfMap&& other) noexcept { + mMapFd = std::move(other.mMapFd); + other.reset(-1); + return *this; + } + + void reset(base::unique_fd fd) = delete; + + void reset(int fd) { mMapFd.reset(fd); } + + bool isValid() const { return mMapFd != -1; } + + base::Result clear() { + while (true) { + auto key = getFirstKey(); + if (!key.ok()) { + if (key.error().code() == ENOENT) return {}; // empty: success + return key.error(); // Anything else is an error + } + auto res = deleteValue(key.value()); + if (!res.ok()) { + // Someone else could have deleted the key, so ignore ENOENT + if (res.error().code() == ENOENT) continue; + ALOGE("Failed to delete data %s", strerror(res.error().code())); + return res.error(); + } + } + } + + base::Result isEmpty() const { + auto key = getFirstKey(); + if (!key.ok()) { + // Return error code ENOENT means the map is empty + if (key.error().code() == ENOENT) return true; + return key.error(); + } + return false; + } + + private: + base::unique_fd mMapFd; +}; + +template +base::Result BpfMap::init(const char* path) { + mMapFd = base::unique_fd(mapRetrieveRW(path)); + if (mMapFd == -1) { + return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path); + } + return {}; +} + +template +base::Result BpfMap::iterate( + const std::function(const Key& key, const BpfMap& map)>& + filter) const { + base::Result curKey = getFirstKey(); + while (curKey.ok()) { + const base::Result& nextKey = getNextKey(curKey.value()); + base::Result status = filter(curKey.value(), *this); + if (!status.ok()) return status; + curKey = nextKey; + } + if (curKey.error().code() == ENOENT) return {}; + return curKey.error(); +} + +template +base::Result BpfMap::iterateWithValue( + const std::function(const Key& key, const Value& value, + const BpfMap& map)>& filter) const { + base::Result curKey = getFirstKey(); + while (curKey.ok()) { + const base::Result& nextKey = getNextKey(curKey.value()); + base::Result curValue = readValue(curKey.value()); + if (!curValue.ok()) return curValue.error(); + base::Result status = filter(curKey.value(), curValue.value(), *this); + if (!status.ok()) return status; + curKey = nextKey; + } + if (curKey.error().code() == ENOENT) return {}; + return curKey.error(); +} + +template +base::Result BpfMap::iterate( + const std::function(const Key& key, BpfMap& map)>& filter) { + base::Result curKey = getFirstKey(); + while (curKey.ok()) { + const base::Result& nextKey = getNextKey(curKey.value()); + base::Result status = filter(curKey.value(), *this); + if (!status.ok()) return status; + curKey = nextKey; + } + if (curKey.error().code() == ENOENT) return {}; + return curKey.error(); +} + +template +base::Result BpfMap::iterateWithValue( + const std::function(const Key& key, const Value& value, + BpfMap& map)>& filter) { + base::Result curKey = getFirstKey(); + while (curKey.ok()) { + const base::Result& nextKey = getNextKey(curKey.value()); + base::Result curValue = readValue(curKey.value()); + if (!curValue.ok()) return curValue.error(); + base::Result status = filter(curKey.value(), curValue.value(), *this); + if (!status.ok()) return status; + curKey = nextKey; + } + if (curKey.error().code() == ENOENT) return {}; + return curKey.error(); +} + +template +class BpfMapRO : public BpfMap { + public: + explicit BpfMapRO(const char* pathname) + : BpfMap(pathname, BPF_F_RDONLY) {} +}; + +} // namespace bpf +} // namespace android diff --git a/staticlibs/native/bpf_map_utils/include/bpf/BpfUtils.h b/staticlibs/native/bpf_map_utils/include/bpf/BpfUtils.h new file mode 100644 index 0000000000..265d4b6300 --- /dev/null +++ b/staticlibs/native/bpf_map_utils/include/bpf/BpfUtils.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2017 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "BpfSyscallWrappers.h" + +// The buffer size for the buffer that records program loading logs, needs to be large enough for +// the largest kernel program. + +namespace android { +namespace bpf { + +constexpr const int OVERFLOW_COUNTERSET = 2; + +constexpr const uint64_t NONEXISTENT_COOKIE = 0; + +static inline uint64_t getSocketCookie(int sockFd) { + uint64_t sock_cookie; + socklen_t cookie_len = sizeof(sock_cookie); + int res = getsockopt(sockFd, SOL_SOCKET, SO_COOKIE, &sock_cookie, &cookie_len); + if (res < 0) { + res = -errno; + ALOGE("Failed to get socket cookie: %s\n", strerror(errno)); + errno = -res; + // 0 is an invalid cookie. See sock_gen_cookie. + return NONEXISTENT_COOKIE; + } + return sock_cookie; +} + +static inline int synchronizeKernelRCU() { + // This is a temporary hack for network stats map swap on devices running + // 4.9 kernels. The kernel code of socket release on pf_key socket will + // explicitly call synchronize_rcu() which is exactly what we need. + int pfSocket = socket(AF_KEY, SOCK_RAW | SOCK_CLOEXEC, PF_KEY_V2); + + if (pfSocket < 0) { + int ret = -errno; + ALOGE("create PF_KEY socket failed: %s", strerror(errno)); + return ret; + } + + // When closing socket, synchronize_rcu() gets called in sock_release(). + if (close(pfSocket)) { + int ret = -errno; + ALOGE("failed to close the PF_KEY socket: %s", strerror(errno)); + return ret; + } + return 0; +} + +static inline int setrlimitForTest() { + // Set the memory rlimit for the test process if the default MEMLOCK rlimit is not enough. + struct rlimit limit = { + .rlim_cur = 1073741824, // 1 GiB + .rlim_max = 1073741824, // 1 GiB + }; + int res = setrlimit(RLIMIT_MEMLOCK, &limit); + if (res) { + ALOGE("Failed to set the default MEMLOCK rlimit: %s", strerror(errno)); + } + return res; +} + +#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c)) + +static inline unsigned kernelVersion() { + struct utsname buf; + int ret = uname(&buf); + if (ret) return 0; + + unsigned kver_major; + unsigned kver_minor; + unsigned kver_sub; + char unused; + ret = sscanf(buf.release, "%u.%u.%u%c", &kver_major, &kver_minor, &kver_sub, &unused); + // Check the device kernel version + if (ret < 3) return 0; + + return KVER(kver_major, kver_minor, kver_sub); +} + +static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) { + return kernelVersion() >= KVER(major, minor, sub); +} + +#define SKIP_IF_BPF_SUPPORTED \ + do { \ + if (android::bpf::isAtLeastKernelVersion(4, 9, 0)) { \ + GTEST_LOG_(INFO) << "This test is skipped since bpf is supported\n"; \ + return; \ + } \ + } while (0) + +#define SKIP_IF_BPF_NOT_SUPPORTED \ + do { \ + if (!android::bpf::isAtLeastKernelVersion(4, 9, 0)) { \ + GTEST_LOG_(INFO) << "This test is skipped since bpf is not supported\n"; \ + return; \ + } \ + } while (0) + +#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED \ + do { \ + if (!android::bpf::isAtLeastKernelVersion(4, 14, 0)) { \ + GTEST_LOG_(INFO) << "This test is skipped since extended bpf feature" \ + << "not supported\n"; \ + return; \ + } \ + } while (0) + +#define SKIP_IF_XDP_NOT_SUPPORTED \ + do { \ + if (!android::bpf::isAtLeastKernelVersion(5, 9, 0)) { \ + GTEST_LOG_(INFO) << "This test is skipped since xdp" \ + << "not supported\n"; \ + return; \ + } \ + } while (0) + +} // namespace bpf +} // namespace android diff --git a/staticlibs/native/bpf_map_utils/include/bpf/WaitForProgsLoaded.h b/staticlibs/native/bpf_map_utils/include/bpf/WaitForProgsLoaded.h new file mode 100644 index 0000000000..bc4168eed4 --- /dev/null +++ b/staticlibs/native/bpf_map_utils/include/bpf/WaitForProgsLoaded.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * Android BPF library - public API + * + * 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. + */ + +#pragma once + +#include + +#include + +namespace android { +namespace bpf { + +// Wait for bpfloader to load BPF programs. +static inline void waitForProgsLoaded() { + // infinite loop until success with 5/10/20/40/60/60/60... delay + for (int delay = 5;; delay *= 2) { + if (delay > 60) delay = 60; + if (android::base::WaitForProperty("bpf.progs_loaded", "1", std::chrono::seconds(delay))) + return; + ALOGW("Waited %ds for bpf.progs_loaded, still waiting...", delay); + } +} + +} // namespace bpf +} // namespace android From 76ce961e1f2c67f3b7be36ff571e2da4ec7aca15 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 25 Nov 2021 08:59:04 +0000 Subject: [PATCH 299/777] Add unit test to parse UTF-8 IFLA_IFNAME attribute. Bug: 163492391 Test: atest NetworkStaticLibsTests Change-Id: I6e2f8c642fa1612e14b2a6b104164c9b54345053 --- .../netlink/RtNetlinkLinkMessageTest.java | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java index 5d446b878d..9db63db1b4 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java @@ -47,7 +47,7 @@ public class RtNetlinkLinkMessageTest { private static final String RTM_NEWLINK_HEX = "64000000100000000000000000000000" // struct nlmsghr + "000001001E0000000210000000000000" // struct ifinfo - + "0A000300776C616E30000000" // IFLA_IFNAME + + "0A000300776C616E30000000" // IFLA_IFNAME(wlan0) + "08000D00B80B0000" // IFLA_PROTINFO + "0500100002000000" // IFLA_OPERSTATE + "0500110001000000" // IFLA_LINKMODE @@ -88,12 +88,47 @@ public class RtNetlinkLinkMessageTest { assertTrue(linkMsg.getInterfaceName().equals("wlan0")); } + /** + * Example: + * # adb shell ip tunnel add トン0 mode sit local any remote 8.8.8.8 + * # adb shell ip link show | grep トン + * 33: トン0@NONE: mtu 1480 qdisc noop state DOWN mode DEFAULT group + * default qlen 1000 + * + * IFLA_IFNAME attribute: \x0c\x00\x03\x00\xe3\x83\x88\xe3\x83\xb3\x30\x00 + * length: 0x000c + * type: 0x0003 + * value: \xe3\x83\x88\xe3\x83\xb3\x30\x00 + * ト (\xe3\x83\x88) + * ン (\xe3\x83\xb3) + * 0 (\x30) + * null terminated (\x00) + */ + private static final String RTM_NEWLINK_UTF8_HEX = + "34000000100000000000000000000000" // struct nlmsghr + + "000001001E0000000210000000000000" // struct ifinfo + + "08000400DC050000" // IFLA_MTU + + "0A00010092C3E3C9374E0000" // IFLA_ADDRESS + + "0C000300E38388E383B33000"; // IFLA_IFNAME(トン0) + + @Test + public void testParseRtmNewLink_utf8Ifname() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWLINK_UTF8_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkLinkMessage); + final RtNetlinkLinkMessage linkMsg = (RtNetlinkLinkMessage) msg; + + assertTrue(linkMsg.getInterfaceName().equals("トン0")); + } + private static final String RTM_NEWLINK_PACK_HEX = "34000000100000000000000000000000" // struct nlmsghr + "000001001E0000000210000000000000" // struct ifinfo + "08000400DC050000" // IFLA_MTU + "0A00010092C3E3C9374E0000" // IFLA_ADDRESS - + "0A000300776C616E30000000"; // IFLA_IFNAME + + "0A000300776C616E30000000"; // IFLA_IFNAME(wlan0) @Test public void testPackRtmNewLink() { @@ -117,7 +152,7 @@ public class RtNetlinkLinkMessageTest { + "0500100002000000" // IFLA_OPERSTATE + "0800010092C3E3C9" // IFLA_ADDRESS(truncated) + "0500110001000000" // IFLA_LINKMODE - + "0A000300776C616E30000000" // IFLA_IFNAME + + "0A000300776C616E30000000" // IFLA_IFNAME(wlan0) + "08000400DC050000"; // IFLA_MTU @Test From eb911f1cf119950fb2ea02678f0ef2613a468bc3 Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Fri, 29 Oct 2021 11:15:28 +0800 Subject: [PATCH 300/777] [NETD-BPF#30] bpf_map_utils add visibility for libnetd_mainline libnetd_mainline uses WaitForProgsLoaded() in bpf_map_utils. Bug: 202086915 Test: m; flash; boot Change-Id: Ia9546002b66e0ff7918c0f1145d38cbc6e28790c --- staticlibs/native/bpf_map_utils/Android.bp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/staticlibs/native/bpf_map_utils/Android.bp b/staticlibs/native/bpf_map_utils/Android.bp index 521b682729..e291bbc478 100644 --- a/staticlibs/native/bpf_map_utils/Android.bp +++ b/staticlibs/native/bpf_map_utils/Android.bp @@ -25,6 +25,7 @@ cc_library_headers { min_sdk_version: "30", apex_available: [ "//apex_available:platform", + "com.android.tethering", "com.android.art.debug", ], visibility: [ @@ -35,6 +36,7 @@ cc_library_headers { "//frameworks/native/services/gpuservice/gpumem", "//frameworks/native/services/gpuservice/tests/unittests", "//frameworks/native/services/gpuservice/tracing", + "//packages/modules/Connectivity/netd", "//packages/modules/Connectivity/tests/unit/jni", "//packages/modules/DnsResolver/tests", "//system/bpf/bpfloader", From 997300b9d18e8d8748cfc86ebd02374e5b1797a2 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 30 Nov 2021 18:55:59 +0900 Subject: [PATCH 301/777] Support multiple cleanup blocks in tryTest{} This is useful for some tests that need to make sure a few things all happen, but some of them may throw an exception. In vanilla Java you'd say try { ... } finally { try { ... } finally { try { ... } finally { ... } } } With this patch, you can pass a list of blocks to clean. Kotlin : tryTest { ... } cleanupStep { ... } cleanupStep { ... } cleanup { ... } Java : tryAndCleanup(() -> { ... }, () -> { ... }, () -> { ... }) This keeps the semantics of tryTest{} of throwing any exception that was thrown in tryTest{} and adding the exception in the cleanup steps as suppressed. Test: new tests for this Change-Id: Ie26b802cb4893e13a70646aa0b7887701dee1ec6 --- .../android/net/module/util/CleanupTest.kt | 29 +++++++++ .../net/module/util/CleanupTestJava.java | 25 ++++++++ .../com/android/testutils/Cleanup.kt | 59 +++++++++++-------- 3 files changed, 87 insertions(+), 26 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt index 006793170b..649b30e11d 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt @@ -32,6 +32,7 @@ private val TAG = CleanupTest::class.simpleName class CleanupTest { class TestException1 : Exception() class TestException2 : Exception() + class TestException3 : Exception() @Test fun testNotThrow() { @@ -172,4 +173,32 @@ class CleanupTest { assertTrue(x == 4) assertTrue(thrown.suppressedExceptions.isEmpty()) } + + @Test + fun testMultipleCleanups() { + var x = 1 + val thrown = assertFailsWith { + tryTest { + x = 2 + throw TestException1() + } cleanupStep { + assertTrue(x == 2) + x = 3 + throw TestException2() + x = 4 + } cleanupStep { + assertTrue(x == 3) + x = 5 + throw TestException3() + x = 6 + } cleanup { + assertTrue(x == 5) + x = 7 + } + } + assertEquals(2, thrown.suppressedExceptions.size) + assertTrue(thrown.suppressedExceptions[0] is TestException2) + assertTrue(thrown.suppressedExceptions[1] is TestException3) + assert(x == 7) + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTestJava.java b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTestJava.java index 83abfa16d6..8a13397b21 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTestJava.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTestJava.java @@ -20,6 +20,7 @@ import static com.android.testutils.Cleanup.testAndCleanup; import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import android.util.Log; @@ -31,6 +32,7 @@ public class CleanupTestJava { private static final String TAG = CleanupTestJava.class.getSimpleName(); private static final class TestException1 extends Exception {} private static final class TestException2 extends Exception {} + private static final class TestException3 extends Exception {} @Test public void testNotThrow() { @@ -93,4 +95,27 @@ public class CleanupTestJava { ); assertEquals(3, x.get()); } + + @Test + public void testMultipleCleanups() { + final AtomicInteger x = new AtomicInteger(1); + final TestException1 exception = assertThrows(TestException1.class, () -> + testAndCleanup(() -> { + x.compareAndSet(1, 2); + throw new TestException1(); + }, () -> { + x.compareAndSet(2, 3); + throw new TestException2(); + }, () -> { + x.compareAndSet(3, 4); + throw new TestException3(); + }, () -> { + x.compareAndSet(4, 5); + }) + ); + assertEquals(2, exception.getSuppressed().length); + assertTrue(exception.getSuppressed()[0] instanceof TestException2); + assertTrue(exception.getSuppressed()[1] instanceof TestException3); + assertEquals(5, x.get()); + } } diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt index 1b67f68cc4..45783d82db 100644 --- a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt +++ b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt @@ -22,14 +22,6 @@ import com.android.testutils.ExceptionUtils.ThrowingRunnable import com.android.testutils.ExceptionUtils.ThrowingSupplier import javax.annotation.CheckReturnValue -@CheckReturnValue -fun tryTest(block: () -> T) = TryExpr( - try { - Result.success(block()) - } catch (e: Throwable) { - Result.failure(e) - }) - /** * Utility to do cleanup in tests without replacing exceptions with those from a finally block. * @@ -54,11 +46,15 @@ fun tryTest(block: () -> T) = TryExpr( * to the standard try{}finally{}, if both throws, the construct throws the exception that happened * in tryTest{} rather than the one that happened in cleanup{}. * - * Kotlin usage is as try{}finally{} : + * Kotlin usage is as try{}finally{}, but with multiple finally{} blocks : * tryTest { * testing code + * } cleanupStep { + * cleanup code 1 + * } cleanupStep { + * cleanup code 2 * } cleanup { - * cleanup code + * cleanup code 3 * } * Catch blocks can be added with the following syntax : * tryTest { @@ -67,14 +63,24 @@ fun tryTest(block: () -> T) = TryExpr( * do something to it * } * - * Java doesn't allow this kind of syntax, so instead a function taking 2 lambdas is provided. + * Java doesn't allow this kind of syntax, so instead a function taking lambdas is provided. * testAndCleanup(() -> { * testing code * }, () -> { - * cleanup code + * cleanup code 1 + * }, () -> { + * cleanup code 2 * }); */ +@CheckReturnValue +fun tryTest(block: () -> T) = TryExpr( + try { + Result.success(block()) + } catch (e: Throwable) { + Result.failure(e) + }) + // Some downstream branches have an older kotlin that doesn't know about value classes. // TODO : Change this to "value class" when aosp no longer merges into such branches. @Suppress("INLINE_CLASS_DEPRECATED") @@ -89,30 +95,31 @@ inline class TryExpr(val result: Result) { }) } - inline infix fun cleanup(block: () -> Unit): T { + @CheckReturnValue + inline infix fun cleanupStep(block: () -> Unit): TryExpr { try { block() } catch (e: Throwable) { val originalException = result.exceptionOrNull() - if (null == originalException) { - throw e + return TryExpr(if (null == originalException) { + Result.failure(e) } else { originalException.addSuppressed(e) - throw originalException - } + Result.failure(originalException) + }) } - return result.getOrThrow() + return this } + + inline infix fun cleanup(block: () -> Unit): T = cleanupStep(block).result.getOrThrow() } // Java support -fun testAndCleanup(tryBlock: ThrowingSupplier, cleanupBlock: ThrowingRunnable): T { - return tryTest { - tryBlock.get() - } cleanup { - cleanupBlock.run() - } +fun testAndCleanup(tryBlock: ThrowingSupplier, vararg cleanupBlock: ThrowingRunnable): T { + return cleanupBlock.fold(tryTest { tryBlock.get() }) { previousExpr, nextCleanup -> + previousExpr.cleanupStep { nextCleanup.run() } + }.cleanup {} } -fun testAndCleanup(tryBlock: ThrowingRunnable, cleanupBlock: ThrowingRunnable) { - return testAndCleanup(ThrowingSupplier { tryBlock.run() }, cleanupBlock) +fun testAndCleanup(tryBlock: ThrowingRunnable, vararg cleanupBlock: ThrowingRunnable) { + return testAndCleanup(ThrowingSupplier { tryBlock.run() }, *cleanupBlock) } From 4bce28bc2a6b3dc43798586798eea2f5d210ab2f Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Fri, 29 Oct 2021 09:49:40 +0800 Subject: [PATCH 302/777] [NETD-BPF#25] Add bpf_syscall_wrappers visibility for libnetd_mainline retrieveProgram() in bpf_syscall_wrappers is used by libnetd_mainline. Bug: 202086915 Test: m; flash; boot Change-Id: I69573a6925fd9f5fcd65935d681e7a340ee73f17 --- staticlibs/native/bpf_syscall_wrappers/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index 379c8a94b2..037e10d8d8 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -35,6 +35,7 @@ cc_library_headers { ], visibility: [ "//frameworks/libs/net/common/native/bpfmapjni", + "//packages/modules/Connectivity/netd", "//packages/modules/Connectivity/service", "//packages/modules/Connectivity/Tethering", "//packages/providers/MediaProvider/jni", From 3250a84f93db8401d637f5ee35758c039714e393 Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Fri, 29 Oct 2021 06:20:20 +0800 Subject: [PATCH 303/777] [NETD-BPF#23] Make libnetdutils apex_available for tethering module libconn_for_netd.so in tethering module needs utilities in libnetdutils, e.g. Status class. Bug: 202086915 Test: m Change-Id: Idb7f11d146570972f2467b7faa624f41bd859062 --- staticlibs/netd/libnetdutils/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/netd/libnetdutils/Android.bp b/staticlibs/netd/libnetdutils/Android.bp index 3bb627069a..9f4d6e393e 100644 --- a/staticlibs/netd/libnetdutils/Android.bp +++ b/staticlibs/netd/libnetdutils/Android.bp @@ -36,6 +36,7 @@ cc_library { apex_available: [ "//apex_available:platform", "com.android.resolv", + "com.android.tethering", ], min_sdk_version: "29", } From 9afec3141755acbab58b33190b68284bc7917f29 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Wed, 15 Sep 2021 20:30:39 +0800 Subject: [PATCH 304/777] Add StructUdpHeader class to parse UDP header from a packet Test: atest NetworkStaticLibTests Change-Id: I98571b8ed916b8e0da5940fe3d8d1f66b24ad93e --- .../net/module/util/structs/UdpHeader.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/structs/UdpHeader.java diff --git a/staticlibs/device/com/android/net/module/util/structs/UdpHeader.java b/staticlibs/device/com/android/net/module/util/structs/UdpHeader.java new file mode 100644 index 0000000000..8b0316bf66 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/UdpHeader.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util.structs; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * L4 UDP header as per https://tools.ietf.org/html/rfc768. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source Port | Destination Port | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Length | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | data octets ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ... + */ +public class UdpHeader extends Struct { + @Field(order = 0, type = Type.U16) + public final int srcPort; + @Field(order = 1, type = Type.U16) + public final int dstPort; + @Field(order = 2, type = Type.U16) + public final int length; + @Field(order = 3, type = Type.S16) + public final short checksum; + + public UdpHeader(final int srcPort, final int dstPort, final int length, + final short checksum) { + this.srcPort = srcPort; + this.dstPort = dstPort; + this.length = length; + this.checksum = checksum; + } +} From 51800daf8ee60b66396ffe0a7137196d869be01b Mon Sep 17 00:00:00 2001 From: waynema Date: Wed, 8 Dec 2021 11:36:02 +0800 Subject: [PATCH 305/777] [NETD-TC#7] Move getIfaceNames() and getIfaceList() to libnetdutils. getIfaceNames() and getIfaceList() are used by Netd. Test: m; flash; boot Change-Id: Id95e2e7e83c07b2f420880feebdf12d4c477c958 --- staticlibs/netd/libnetdutils/Android.bp | 1 + staticlibs/netd/libnetdutils/Utils.cpp | 61 +++++++++++++++++++ .../libnetdutils/include/netdutils/Utils.h | 32 ++++++++++ 3 files changed, 94 insertions(+) create mode 100644 staticlibs/netd/libnetdutils/Utils.cpp create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/Utils.h diff --git a/staticlibs/netd/libnetdutils/Android.bp b/staticlibs/netd/libnetdutils/Android.bp index 9f4d6e393e..732e37d90a 100644 --- a/staticlibs/netd/libnetdutils/Android.bp +++ b/staticlibs/netd/libnetdutils/Android.bp @@ -18,6 +18,7 @@ cc_library { "Syscalls.cpp", "UniqueFd.cpp", "UniqueFile.cpp", + "Utils.cpp", ], defaults: ["netd_defaults"], cflags: ["-Wall", "-Werror"], diff --git a/staticlibs/netd/libnetdutils/Utils.cpp b/staticlibs/netd/libnetdutils/Utils.cpp new file mode 100644 index 0000000000..16ec8825f6 --- /dev/null +++ b/staticlibs/netd/libnetdutils/Utils.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2021 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. + */ + +#include + +#include + +#include "dirent.h" +#include "netdutils/Status.h" +#include "netdutils/Utils.h" + +namespace android { +namespace netdutils { + +StatusOr> getIfaceNames() { + std::vector ifaceNames; + DIR* d; + struct dirent* de; + + if (!(d = opendir("/sys/class/net"))) { + return statusFromErrno(errno, "Cannot open iface directory"); + } + while ((de = readdir(d))) { + if ((de->d_type != DT_DIR) && (de->d_type != DT_LNK)) continue; + if (de->d_name[0] == '.') continue; + ifaceNames.push_back(std::string(de->d_name)); + } + closedir(d); + return ifaceNames; +} + +StatusOr> getIfaceList() { + std::map ifacePairs; + + ASSIGN_OR_RETURN(auto ifaceNames, getIfaceNames()); + + for (const auto& name : ifaceNames) { + uint32_t ifaceIndex = if_nametoindex(name.c_str()); + if (ifaceIndex) { + ifacePairs.insert(std::pair(name, ifaceIndex)); + } + } + return ifacePairs; +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Utils.h b/staticlibs/netd/libnetdutils/include/netdutils/Utils.h new file mode 100644 index 0000000000..83c583b215 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/Utils.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 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. + */ + +#ifndef NETUTILS_UTILS_H +#define NETUTILS_UTILS_H + +#include "netdutils/StatusOr.h" + +namespace android { +namespace netdutils { + +StatusOr> getIfaceNames(); + +StatusOr> getIfaceList(); + +} // namespace netdutils +} // namespace android + +#endif /* NETUTILS_UTILS_H */ From 2b71c97f9995273f503ea4232036d8f74e82ecca Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Thu, 9 Dec 2021 13:57:00 -0800 Subject: [PATCH 306/777] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/libs/net Added SPDX-license-identifier-Apache-2.0 to: common/native/bpf_map_utils/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Change-Id: I4f254c63df574bcce60aa5854107fccbb888f424 --- staticlibs/native/bpf_map_utils/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/staticlibs/native/bpf_map_utils/Android.bp b/staticlibs/native/bpf_map_utils/Android.bp index e291bbc478..e14c259096 100644 --- a/staticlibs/native/bpf_map_utils/Android.bp +++ b/staticlibs/native/bpf_map_utils/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + cc_library_headers { name: "bpf_map_utils", vendor_available: true, From 9ad8a4a6aa15b410f05deaa6b205e898290c4642 Mon Sep 17 00:00:00 2001 From: Taras Antoshchuk Date: Mon, 29 Nov 2021 21:27:46 +0100 Subject: [PATCH 307/777] Suppress NewApi warnings for @SystemApi -> public APIs Android Lint doesn't handle API change from @SystemApi to public API correctly (see b/193460475). We have to manually suppress those warnings for now. This CL suppresses warnings related to: - IpPrefix(InetAddress, int) - RouteInfo#getType Bug: 186082280 Test: presubmit Change-Id: Ib24b2d3fb21b86bd9e3555316a5a5bcb94434c00 --- .../module/util/netlink/RtNetlinkRouteMessage.java | 2 ++ .../net/module/util/netlink/StructNdOptPref64.java | 2 ++ .../src/com/android/net/module/util/IpRangeTest.java | 12 ++++++++++++ .../net/module/util/LinkPropertiesUtilsTest.java | 2 ++ .../src/com/android/net/module/util/StructTest.java | 2 ++ .../module/util/netlink/StructNdOptPref64Test.java | 2 ++ 6 files changed, 22 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java index c5efcb2651..1705f1c803 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java @@ -22,6 +22,7 @@ import static android.system.OsConstants.AF_INET6; import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY; import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ANY; +import android.annotation.SuppressLint; import android.net.IpPrefix; import android.system.OsConstants; @@ -107,6 +108,7 @@ public class RtNetlinkRouteMessage extends NetlinkMessage { * @param header netlink message header. * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. */ + @SuppressLint("NewApi") @Nullable public static RtNetlinkRouteMessage parse(@NonNull final StructNlMsgHdr header, @NonNull final ByteBuffer byteBuffer) { diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java b/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java index f6b2e0e504..8226346649 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java @@ -16,6 +16,7 @@ package com.android.net.module.util.netlink; +import android.annotation.SuppressLint; import android.net.IpPrefix; import android.util.Log; @@ -107,6 +108,7 @@ public class StructNdOptPref64 extends NdOption { this.lifetime = lifetime & 0xfff8; } + @SuppressLint("NewApi") private StructNdOptPref64(@NonNull ByteBuffer buf) { super(buf.get(), Byte.toUnsignedInt(buf.get())); if (type != TYPE) throw new IllegalArgumentException("Invalid type " + type); diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java index f44b17d751..20bbd4a143 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.annotation.SuppressLint; import android.net.InetAddresses; import android.net.IpPrefix; @@ -92,6 +93,7 @@ public class IpRangeTest { } } + @SuppressLint("NewApi") @Test public void testConstructor() { IpRange r = new IpRange(new IpPrefix(IPV4_ADDR, 32)); @@ -119,6 +121,7 @@ public class IpRangeTest { assertEquals(IPV6_RANGE_END, r.getEndAddr()); } + @SuppressLint("NewApi") @Test public void testContainsRangeEqualRanges() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); @@ -129,6 +132,7 @@ public class IpRangeTest { assertEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testContainsRangeSubset() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 64)); @@ -139,6 +143,7 @@ public class IpRangeTest { assertNotEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testContainsRangeTruncatesLowerOrderBits() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 100)); @@ -149,6 +154,7 @@ public class IpRangeTest { assertEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testContainsRangeSubsetSameStartAddr() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); @@ -159,6 +165,7 @@ public class IpRangeTest { assertNotEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testContainsRangeOverlapping() { final IpRange r1 = new IpRange(new IpPrefix(address("2001:db9::"), 32)); @@ -169,6 +176,7 @@ public class IpRangeTest { assertNotEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testOverlapsRangeEqualRanges() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); @@ -179,6 +187,7 @@ public class IpRangeTest { assertEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testOverlapsRangeSubset() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); @@ -189,6 +198,7 @@ public class IpRangeTest { assertNotEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testOverlapsRangeDisjoint() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 32)); @@ -199,6 +209,7 @@ public class IpRangeTest { assertNotEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testOverlapsRangePartialOverlapLow() { final IpRange r1 = new IpRange(new IpPrefix(address("2001:db9::"), 32)); @@ -209,6 +220,7 @@ public class IpRangeTest { assertNotEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testOverlapsRangePartialOverlapHigh() { final IpRange r1 = new IpRange(new IpPrefix(address("2001:db7::"), 32)); diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java index 3d2d6ebaac..09f0490283 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import android.annotation.SuppressLint; import android.net.InetAddresses; import android.net.IpPrefix; import android.net.LinkAddress; @@ -46,6 +47,7 @@ import java.util.function.Function; @RunWith(AndroidJUnit4.class) public final class LinkPropertiesUtilsTest { + @SuppressLint("NewApi") private static final IpPrefix PREFIX = new IpPrefix(toInetAddress("75.208.6.0"), 24); private static final InetAddress V4_ADDR = toInetAddress("75.208.6.1"); private static final InetAddress V6_ADDR = toInetAddress( diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java index eabc14b4bf..4e46210649 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import android.annotation.SuppressLint; import android.net.InetAddresses; import android.net.IpPrefix; import android.net.MacAddress; @@ -453,6 +454,7 @@ public class StructTest { } } + @SuppressLint("NewApi") private void verifyPrefixByteArrayParsing(final PrefixMessage msg) throws Exception { // The original PREF64 option message has just 12 bytes for prefix byte array // (Highest 96 bits of the Prefix), copyOf pads the 128-bits IPv6 address with diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java index 57248eada6..beed838356 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java @@ -24,6 +24,7 @@ import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import android.annotation.SuppressLint; import android.net.IpPrefix; import androidx.test.filters.SmallTest; @@ -51,6 +52,7 @@ public class StructNdOptPref64Test { return prefixBytes; } + @SuppressLint("NewApi") private static IpPrefix prefix(String addrString, int prefixLength) throws Exception { return new IpPrefix(InetAddress.getByName(addrString), prefixLength); } From 00ef48f122269a98f0a577b725f5291c80a492e5 Mon Sep 17 00:00:00 2001 From: Taras Antoshchuk Date: Mon, 29 Nov 2021 21:27:46 +0100 Subject: [PATCH 308/777] Suppress NewApi warnings for @SystemApi -> public APIs Android Lint doesn't handle API change from @SystemApi to public API correctly (see b/193460475). We have to manually suppress those warnings for now. This CL suppresses warnings related to: - IpPrefix(InetAddress, int) - RouteInfo#getType Bug: 186082280 Test: presubmit Change-Id: Ib24b2d3fb21b86bd9e3555316a5a5bcb94434c00 --- .../client-libs/netd/com/android/net/module/util/NetdUtils.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java b/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java index e78e3367e7..de13d4267f 100644 --- a/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java +++ b/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java @@ -23,6 +23,7 @@ import static android.net.RouteInfo.RTN_UNICAST; import static android.net.RouteInfo.RTN_UNREACHABLE; import static android.system.OsConstants.EBUSY; +import android.annotation.SuppressLint; import android.net.INetd; import android.net.InterfaceConfigurationParcel; import android.net.IpPrefix; @@ -213,6 +214,7 @@ public class NetdUtils { return failures; } + @SuppressLint("NewApi") private static String findNextHop(final RouteInfo route) { final String nextHop; switch (route.getType()) { From 0aab03610127a0c500307f1bfd4fbb2861e866b1 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 9 Dec 2021 12:55:32 +0900 Subject: [PATCH 309/777] Move libipchecksum to frameworks/libs/net. This code is used by the DNS resolver mainline module, so it should be in a directory that is automerged to sc-mainline-prod, not in /system/core. Test: m Change-Id: I2d953afa3d2766ca2b4529e9e49151c098b466aa --- staticlibs/native/ip_checksum/Android.bp | 40 +++++++ staticlibs/native/ip_checksum/checksum.c | 145 +++++++++++++++++++++++ staticlibs/native/ip_checksum/checksum.h | 34 ++++++ 3 files changed, 219 insertions(+) create mode 100644 staticlibs/native/ip_checksum/Android.bp create mode 100644 staticlibs/native/ip_checksum/checksum.c create mode 100644 staticlibs/native/ip_checksum/checksum.h diff --git a/staticlibs/native/ip_checksum/Android.bp b/staticlibs/native/ip_checksum/Android.bp new file mode 100644 index 0000000000..d7e195d376 --- /dev/null +++ b/staticlibs/native/ip_checksum/Android.bp @@ -0,0 +1,40 @@ +// Copyright (C) 2021 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_library_static { + name: "libip_checksum", + + srcs: [ + "checksum.c", + ], + + cflags: [ + "-Wall", + "-Werror", + ], + + export_include_dirs: ["."], + + // Needed because libnetutils depends on libip_checksum, and libnetutils has + // vendor_available = true. Making this library vendor_available does not create any maintenance + // burden or version skew issues because this library is only static, not dynamic, and thus is + // not installed on the device. + // + // TODO: delete libnetutils from the VNDK in T, and remove this. + vendor_available: true, +} diff --git a/staticlibs/native/ip_checksum/checksum.c b/staticlibs/native/ip_checksum/checksum.c new file mode 100644 index 0000000000..04217a7992 --- /dev/null +++ b/staticlibs/native/ip_checksum/checksum.c @@ -0,0 +1,145 @@ +/* + * Copyright 2011 Daniel Drown + * + * 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. + * + * checksum.c - ipv4/ipv6 checksum calculation + */ +#include +#include +#include +#include +#include +#include +#include + +#include "checksum.h" + +/* function: ip_checksum_add + * adds data to a checksum. only known to work on little-endian hosts + * current - the current checksum (or 0 to start a new checksum) + * data - the data to add to the checksum + * len - length of data + */ +uint32_t ip_checksum_add(uint32_t current, const void* data, int len) { + uint32_t checksum = current; + int left = len; + const uint16_t* data_16 = data; + + while (left > 1) { + checksum += *data_16; + data_16++; + left -= 2; + } + if (left) { + checksum += *(uint8_t*)data_16; + } + + return checksum; +} + +/* function: ip_checksum_fold + * folds a 32-bit partial checksum into 16 bits + * temp_sum - sum from ip_checksum_add + * returns: the folded checksum in network byte order + */ +uint16_t ip_checksum_fold(uint32_t temp_sum) { + while (temp_sum > 0xffff) { + temp_sum = (temp_sum >> 16) + (temp_sum & 0xFFFF); + } + return temp_sum; +} + +/* function: ip_checksum_finish + * folds and closes the checksum + * temp_sum - sum from ip_checksum_add + * returns: a header checksum value in network byte order + */ +uint16_t ip_checksum_finish(uint32_t temp_sum) { + return ~ip_checksum_fold(temp_sum); +} + +/* function: ip_checksum + * combined ip_checksum_add and ip_checksum_finish + * data - data to checksum + * len - length of data + */ +uint16_t ip_checksum(const void* data, int len) { + // TODO: consider starting from 0xffff so the checksum of a buffer entirely consisting of zeros + // is correctly calculated as 0. + uint32_t temp_sum; + + temp_sum = ip_checksum_add(0, data, len); + return ip_checksum_finish(temp_sum); +} + +/* function: ipv6_pseudo_header_checksum + * calculate the pseudo header checksum for use in tcp/udp/icmp headers + * ip6 - the ipv6 header + * len - the transport length (transport header + payload) + * protocol - the transport layer protocol, can be different from ip6->ip6_nxt for fragments + */ +uint32_t ipv6_pseudo_header_checksum(const struct ip6_hdr* ip6, uint32_t len, uint8_t protocol) { + uint32_t checksum_len = htonl(len); + uint32_t checksum_next = htonl(protocol); + + uint32_t current = 0; + + current = ip_checksum_add(current, &(ip6->ip6_src), sizeof(struct in6_addr)); + current = ip_checksum_add(current, &(ip6->ip6_dst), sizeof(struct in6_addr)); + current = ip_checksum_add(current, &checksum_len, sizeof(checksum_len)); + current = ip_checksum_add(current, &checksum_next, sizeof(checksum_next)); + + return current; +} + +/* function: ipv4_pseudo_header_checksum + * calculate the pseudo header checksum for use in tcp/udp headers + * ip - the ipv4 header + * len - the transport length (transport header + payload) + */ +uint32_t ipv4_pseudo_header_checksum(const struct iphdr* ip, uint16_t len) { + uint16_t temp_protocol, temp_length; + + temp_protocol = htons(ip->protocol); + temp_length = htons(len); + + uint32_t current = 0; + + current = ip_checksum_add(current, &(ip->saddr), sizeof(uint32_t)); + current = ip_checksum_add(current, &(ip->daddr), sizeof(uint32_t)); + current = ip_checksum_add(current, &temp_protocol, sizeof(uint16_t)); + current = ip_checksum_add(current, &temp_length, sizeof(uint16_t)); + + return current; +} + +/* function: ip_checksum_adjust + * calculates a new checksum given a previous checksum and the old and new pseudo-header checksums + * checksum - the header checksum in the original packet in network byte order + * old_hdr_sum - the pseudo-header checksum of the original packet + * new_hdr_sum - the pseudo-header checksum of the translated packet + * returns: the new header checksum in network byte order + */ +uint16_t ip_checksum_adjust(uint16_t checksum, uint32_t old_hdr_sum, uint32_t new_hdr_sum) { + // Algorithm suggested in RFC 1624. + // http://tools.ietf.org/html/rfc1624#section-3 + checksum = ~checksum; + uint16_t folded_sum = ip_checksum_fold(checksum + new_hdr_sum); + uint16_t folded_old = ip_checksum_fold(old_hdr_sum); + if (folded_sum > folded_old) { + return ~(folded_sum - folded_old); + } else { + return ~(folded_sum - folded_old - 1); // end-around borrow + } +} diff --git a/staticlibs/native/ip_checksum/checksum.h b/staticlibs/native/ip_checksum/checksum.h new file mode 100644 index 0000000000..868217c5d1 --- /dev/null +++ b/staticlibs/native/ip_checksum/checksum.h @@ -0,0 +1,34 @@ +/* + * Copyright 2011 Daniel Drown + * + * 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. + * + * checksum.h - checksum functions + */ +#ifndef __CHECKSUM_H__ +#define __CHECKSUM_H__ + +#include +#include +#include + +uint32_t ip_checksum_add(uint32_t current, const void* data, int len); +uint16_t ip_checksum_finish(uint32_t temp_sum); +uint16_t ip_checksum(const void* data, int len); + +uint32_t ipv6_pseudo_header_checksum(const struct ip6_hdr* ip6, uint32_t len, uint8_t protocol); +uint32_t ipv4_pseudo_header_checksum(const struct iphdr* ip, uint16_t len); + +uint16_t ip_checksum_adjust(uint16_t checksum, uint32_t old_hdr_sum, uint32_t new_hdr_sum); + +#endif /* __CHECKSUM_H__ */ From 435833f2cd837caccff3160dc0d53b5e2e778f5c Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Tue, 14 Sep 2021 20:26:27 +0800 Subject: [PATCH 310/777] Add a class to build IPv4 TCP packet Note that IPv4 and TCP options are not supported. Test: atest NetworkStaticLibTests Change-Id: Ie62b95bf759b74d72a5e85d312d17978422f633b --- staticlibs/Android.bp | 1 + .../net/module/util/PacketBuilder.java | 222 ++++++++++++ .../module/util/NetworkStackConstants.java | 17 + .../net/module/util/PacketBuilderTest.java | 336 ++++++++++++++++++ 4 files changed, 576 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/PacketBuilder.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 0585c09c71..4c58228c6d 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -139,6 +139,7 @@ java_library { srcs: [ "device/com/android/net/module/util/HexDump.java", "device/com/android/net/module/util/Ipv6Utils.java", + "device/com/android/net/module/util/PacketBuilder.java", "device/com/android/net/module/util/Struct.java", "device/com/android/net/module/util/structs/*.java", ], diff --git a/staticlibs/device/com/android/net/module/util/PacketBuilder.java b/staticlibs/device/com/android/net/module/util/PacketBuilder.java new file mode 100644 index 0000000000..e9ecb94dec --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/PacketBuilder.java @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util; + +import static android.system.OsConstants.IPPROTO_IP; +import static android.system.OsConstants.IPPROTO_TCP; + +import static com.android.net.module.util.IpUtils.ipChecksum; +import static com.android.net.module.util.IpUtils.tcpChecksum; +import static com.android.net.module.util.NetworkStackConstants.IPV4_CHECKSUM_OFFSET; +import static com.android.net.module.util.NetworkStackConstants.IPV4_LENGTH_OFFSET; +import static com.android.net.module.util.NetworkStackConstants.TCP_CHECKSUM_OFFSET; + +import android.net.MacAddress; + +import androidx.annotation.NonNull; + +import com.android.net.module.util.structs.EthernetHeader; +import com.android.net.module.util.structs.Ipv4Header; +import com.android.net.module.util.structs.TcpHeader; + +import java.io.IOException; +import java.net.Inet4Address; +import java.nio.BufferOverflowException; +import java.nio.ByteBuffer; + +/** + * The class is used to build a packet. + * + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Layer 2 header (EthernetHeader) | (optional) + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Layer 3 header (Ipv4Header) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Layer 4 header (TcpHeader) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Payload | (optional) + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Below is a sample code to build a packet. + * + * // Initialize builder + * final ByteBuffer buf = ByteBuffer.allocate(...); + * final PacketBuilder pb = new PacketBuilder(buf); + * // Write headers + * pb.writeL2Header(...); + * pb.writeIpHeader(...); + * pb.writeTcpHeader(...); + * // Write payload + * buf.putInt(...); + * buf.putShort(...); + * buf.putByte(...); + * // Finalize and use the packet + * pb.finalizePacket(); + * sendPacket(buf); + */ +public class PacketBuilder { + private final ByteBuffer mBuffer; + + private int mIpv4HeaderOffset = -1; + private int mTcpHeaderOffset = -1; + + public PacketBuilder(@NonNull ByteBuffer buffer) { + mBuffer = buffer; + } + + /** + * Write an ethernet header. + * + * @param srcMac source MAC address + * @param dstMac destination MAC address + * @param etherType ether type + */ + public void writeL2Header(MacAddress srcMac, MacAddress dstMac, short etherType) throws + IOException { + final EthernetHeader ethv4Header = new EthernetHeader(dstMac, srcMac, etherType); + try { + ethv4Header.writeToByteBuffer(mBuffer); + } catch (IllegalArgumentException | BufferOverflowException e) { + throw new IOException("Error writing to buffer: ", e); + } + } + + /** + * Write an IPv4 header. + * The IP header length and checksum are calculated and written back in #finalizePacket. + * + * @param tos type of service + * @param id the identification + * @param flagsAndFragmentOffset flags and fragment offset + * @param ttl time to live + * @param protocol protocol + * @param srcIp source IP address + * @param dstIp destination IP address + */ + public void writeIpv4Header(byte tos, short id, short flagsAndFragmentOffset, byte ttl, + byte protocol, @NonNull final Inet4Address srcIp, @NonNull final Inet4Address dstIp) + throws IOException { + mIpv4HeaderOffset = mBuffer.position(); + final Ipv4Header ipv4Header = new Ipv4Header(tos, + (short) 0 /* totalLength, calculate in #finalizePacket */, id, + flagsAndFragmentOffset, ttl, protocol, + (short) 0 /* checksum, calculate in #finalizePacket */, srcIp, dstIp); + + try { + ipv4Header.writeToByteBuffer(mBuffer); + } catch (IllegalArgumentException | BufferOverflowException e) { + throw new IOException("Error writing to buffer: ", e); + } + } + + /** + * Write a TCP header. + * The TCP header checksum is calculated and written back in #finalizePacket. + * + * @param srcPort source port + * @param dstPort destination port + * @param seq sequence number + * @param ack acknowledgement number + * @param tcpFlags tcp flags + * @param window window size + * @param urgentPointer urgent pointer + */ + public void writeTcpHeader(short srcPort, short dstPort, short seq, short ack, + byte tcpFlags, short window, short urgentPointer) throws IOException { + mTcpHeaderOffset = mBuffer.position(); + final TcpHeader tcpHeader = new TcpHeader(srcPort, dstPort, seq, ack, + (short) ((short) 0x5000 | ((byte) 0x3f & tcpFlags)) /* dataOffsetAndControlBits, + dataOffset is always 5(*4bytes) because options not supported */, window, + (short) 0 /* checksum, calculate in #finalizePacket */, + urgentPointer); + + try { + tcpHeader.writeToByteBuffer(mBuffer); + } catch (IllegalArgumentException | BufferOverflowException e) { + throw new IOException("Error writing to buffer: ", e); + } + } + + /** + * Finalize the packet. + * + * Call after writing L4 header (no payload) or payload to the buffer used by the builder. + * L3 header length, L3 header checksum and L4 header checksum are calculated and written back + * after finalization. + */ + @NonNull + public ByteBuffer finalizePacket() throws IOException { + if (mIpv4HeaderOffset < 0) { + // TODO: add support for IPv6 + throw new IOException("Packet is missing IPv4 header"); + } + + // Populate the IPv4 totalLength field. + mBuffer.putShort(mIpv4HeaderOffset + IPV4_LENGTH_OFFSET, + (short) (mBuffer.position() - mIpv4HeaderOffset)); + + // Populate the IPv4 header checksum field. + mBuffer.putShort(mIpv4HeaderOffset + IPV4_CHECKSUM_OFFSET, + ipChecksum(mBuffer, mIpv4HeaderOffset /* headerOffset */)); + + // Populate the TCP header checksum field. + if (mTcpHeaderOffset > 0) { + mBuffer.putShort(mTcpHeaderOffset + TCP_CHECKSUM_OFFSET, tcpChecksum(mBuffer, + mIpv4HeaderOffset /* ipOffset */, mTcpHeaderOffset /* transportOffset */, + mBuffer.position() - mTcpHeaderOffset /* transportLen */)); + } else { // TODO: add support for UDP + throw new IOException("Packet is missing TCP header"); + } + + mBuffer.flip(); + return mBuffer; + } + + /** + * Allocate bytebuffer for building the packet. + * + * @param hasEther has ethernet header. Set this flag to indicate that the packet has an + * ethernet header. + * @param l3proto the layer 3 protocol. Only {@code IPPROTO_IP} currently supported. + * @param l4proto the layer 4 protocol. Only {@code IPPROTO_TCP} currently supported. + * @param payloadLen length of the payload. + */ + @NonNull + public static ByteBuffer allocate(boolean hasEther, int l3proto, int l4proto, int payloadLen) { + if (l3proto != IPPROTO_IP) { + // TODO: add support for IPv6 + throw new IllegalArgumentException("Unsupported layer 3 protocol " + l3proto); + } + + if (l4proto != IPPROTO_TCP) { + // TODO: add support for UDP + throw new IllegalArgumentException("Unsupported layer 4 protocol " + l4proto); + } + + if (payloadLen < 0) { + throw new IllegalArgumentException("Invalid payload length " + payloadLen); + } + + int packetLen = 0; + if (hasEther) packetLen += Struct.getSize(EthernetHeader.class); + packetLen += Struct.getSize(Ipv4Header.class); + packetLen += Struct.getSize(TcpHeader.class); + packetLen += payloadLen; + + return ByteBuffer.allocate(packetLen); + } +} diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index f7151d7b17..378e4857a6 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -89,9 +89,11 @@ public final class NetworkStackConstants { public static final int IPV4_MAX_MTU = 65_535; public static final int IPV4_HEADER_MIN_LEN = 20; public static final int IPV4_IHL_MASK = 0xf; + public static final int IPV4_LENGTH_OFFSET = 2; public static final int IPV4_FLAGS_OFFSET = 6; public static final int IPV4_FRAGMENT_MASK = 0x1fff; public static final int IPV4_PROTOCOL_OFFSET = 9; + public static final int IPV4_CHECKSUM_OFFSET = 10; public static final int IPV4_SRC_ADDR_OFFSET = 12; public static final int IPV4_DST_ADDR_OFFSET = 16; public static final int IPV4_ADDR_LEN = 4; @@ -163,6 +165,21 @@ public final class NetworkStackConstants { public static final byte PIO_FLAG_ON_LINK = (byte) (1 << 7); public static final byte PIO_FLAG_AUTONOMOUS = (byte) (1 << 6); + /** + * TCP constants. + * + * See also: + * - https://tools.ietf.org/html/rfc793 + */ + public static final int TCP_HEADER_MIN_LEN = 20; + public static final int TCP_CHECKSUM_OFFSET = 16; + public static final byte TCPHDR_FIN = (byte) (1 << 0); + public static final byte TCPHDR_SYN = (byte) (1 << 1); + public static final byte TCPHDR_RST = (byte) (1 << 2); + public static final byte TCPHDR_PSH = (byte) (1 << 3); + public static final byte TCPHDR_ACK = (byte) (1 << 4); + public static final byte TCPHDR_URG = (byte) (1 << 5); + /** * UDP constants. * diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java new file mode 100644 index 0000000000..275aa847d3 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util; + +import static android.system.OsConstants.IPPROTO_IP; +import static android.system.OsConstants.IPPROTO_TCP; + +import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV4; +import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN; +import static com.android.net.module.util.NetworkStackConstants.TCPHDR_ACK; +import static com.android.net.module.util.NetworkStackConstants.TCP_HEADER_MIN_LEN; +import static com.android.testutils.MiscAsserts.assertThrows; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import android.net.InetAddresses; +import android.net.MacAddress; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.net.module.util.structs.EthernetHeader; +import com.android.net.module.util.structs.Ipv4Header; +import com.android.net.module.util.structs.TcpHeader; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.IOException; +import java.net.Inet4Address; +import java.nio.ByteBuffer; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class PacketBuilderTest { + private static final MacAddress SRC_MAC = MacAddress.fromString("11:22:33:44:55:66"); + private static final MacAddress DST_MAC = MacAddress.fromString("aa:bb:cc:dd:ee:ff"); + private static final Inet4Address IPV4_SRC_ADDR = addr("192.0.2.1"); + private static final Inet4Address IPV4_DST_ADDR = addr("198.51.100.1"); + private static final short SRC_PORT = 9876; + private static final short DST_PORT = 433; + private static final short SEQ_NO = 13579; + private static final short ACK_NO = 24680; + private static final byte TYPE_OF_SERVICE = 0; + private static final short ID = 27149; + private static final short FLAGS_AND_FRAGMENT_OFFSET = (short) 0x4000; // flags=DF, offset=0 + private static final byte TIME_TO_LIVE = (byte) 0x40; + private static final short WINDOW = (short) 0x2000; + private static final short URGENT_POINTER = 0; + private static final ByteBuffer DATA = ByteBuffer.wrap(new byte[] { + (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef + }); + + private static final byte[] TEST_PACKET_ETHERHDR_IPV4HDR_TCPHDR = + new byte[] { + // packet = (scapy.Ether(src="11:22:33:44:55:66", dst="aa:bb:cc:dd:ee:ff", + // type='IPv4') / + // scapy.IP(src="192.0.2.1", dst="198.51.100.1", + // tos=0, id=27149, flags='DF') / + // scapy.TCP(sport=9876, dport=433, seq=13579, ack=24680, + // flags='A', window=8192, urgptr=0)) + // Ether header + (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, + (byte) 0xee, (byte) 0xff, (byte) 0x11, (byte) 0x22, + (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66, + (byte) 0x08, (byte) 0x00, + // IPv4 header + (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x28, + (byte) 0x6a, (byte) 0x0d, (byte) 0x40, (byte) 0x00, + (byte) 0x40, (byte) 0x06, (byte) 0xe4, (byte) 0x8c, + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, + (byte) 0xc6, (byte) 0x33, (byte) 0x64, (byte) 0x01, + // TCP header + (byte) 0x26, (byte) 0x94, (byte) 0x01, (byte) 0xb1, + (byte) 0x00, (byte) 0x00, (byte) 0x35, (byte) 0x0b, + (byte) 0x00, (byte) 0x00, (byte) 0x60, (byte) 0x68, + (byte) 0x50, (byte) 0x10, (byte) 0x20, (byte) 0x00, + (byte) 0xe5, (byte) 0xe5, (byte) 0x00, (byte) 0x00 + }; + + private static final byte[] TEST_PACKET_ETHERHDR_IPV4HDR_TCPHDR_DATA = + new byte[] { + // packet = (scapy.Ether(src="11:22:33:44:55:66", dst="aa:bb:cc:dd:ee:ff", + // type='IPv4') / + // scapy.IP(src="192.0.2.1", dst="198.51.100.1", + // tos=0, id=27149, flags='DF') / + // scapy.TCP(sport=9876, dport=433, seq=13579, ack=24680, + // flags='A', window=8192, urgptr=0) / + // b'\xde\xad\xbe\xef') + // Ether header + (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, + (byte) 0xee, (byte) 0xff, (byte) 0x11, (byte) 0x22, + (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66, + (byte) 0x08, (byte) 0x00, + // IPv4 header + (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x2c, + (byte) 0x6a, (byte) 0x0d, (byte) 0x40, (byte) 0x00, + (byte) 0x40, (byte) 0x06, (byte) 0xe4, (byte) 0x88, + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, + (byte) 0xc6, (byte) 0x33, (byte) 0x64, (byte) 0x01, + // TCP header + (byte) 0x26, (byte) 0x94, (byte) 0x01, (byte) 0xb1, + (byte) 0x00, (byte) 0x00, (byte) 0x35, (byte) 0x0b, + (byte) 0x00, (byte) 0x00, (byte) 0x60, (byte) 0x68, + (byte) 0x50, (byte) 0x10, (byte) 0x20, (byte) 0x00, + (byte) 0x48, (byte) 0x44, (byte) 0x00, (byte) 0x00, + // Data + (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef + }; + + private static final byte[] TEST_PACKET_IPV4HDR_TCPHDR = + new byte[] { + // packet = (scapy.IP(src="192.0.2.1", dst="198.51.100.1", + // tos=0, id=27149, flags='DF') / + // scapy.TCP(sport=9876, dport=433, seq=13579, ack=24680, + // flags='A', window=8192, urgptr=0)) + // IPv4 header + (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x28, + (byte) 0x6a, (byte) 0x0d, (byte) 0x40, (byte) 0x00, + (byte) 0x40, (byte) 0x06, (byte) 0xe4, (byte) 0x8c, + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, + (byte) 0xc6, (byte) 0x33, (byte) 0x64, (byte) 0x01, + // TCP header + (byte) 0x26, (byte) 0x94, (byte) 0x01, (byte) 0xb1, + (byte) 0x00, (byte) 0x00, (byte) 0x35, (byte) 0x0b, + (byte) 0x00, (byte) 0x00, (byte) 0x60, (byte) 0x68, + (byte) 0x50, (byte) 0x10, (byte) 0x20, (byte) 0x00, + (byte) 0xe5, (byte) 0xe5, (byte) 0x00, (byte) 0x00 + }; + + private static final byte[] TEST_PACKET_IPV4HDR_TCPHDR_DATA = + new byte[] { + // packet = (scapy.IP(src="192.0.2.1", dst="198.51.100.1", + // tos=0, id=27149, flags='DF') / + // scapy.TCP(sport=9876, dport=433, seq=13579, ack=24680, + // flags='A', window=8192, urgptr=0) / + // b'\xde\xad\xbe\xef') + // IPv4 header + (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x2c, + (byte) 0x6a, (byte) 0x0d, (byte) 0x40, (byte) 0x00, + (byte) 0x40, (byte) 0x06, (byte) 0xe4, (byte) 0x88, + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, + (byte) 0xc6, (byte) 0x33, (byte) 0x64, (byte) 0x01, + // TCP header + (byte) 0x26, (byte) 0x94, (byte) 0x01, (byte) 0xb1, + (byte) 0x00, (byte) 0x00, (byte) 0x35, (byte) 0x0b, + (byte) 0x00, (byte) 0x00, (byte) 0x60, (byte) 0x68, + (byte) 0x50, (byte) 0x10, (byte) 0x20, (byte) 0x00, + (byte) 0x48, (byte) 0x44, (byte) 0x00, (byte) 0x00, + // Data + (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef + }; + + /** + * Build a TCPv4 packet which has ether header, IPv4 header, TCP header and data. + * The ethernet header and data are optional. Note that both source mac address and + * destination mac address are required for ethernet header. + * + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Layer 2 header (EthernetHeader) | (optional) + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Layer 3 header (Ipv4Header) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Layer 4 header (TcpHeader) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Payload | (optional) + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * @param srcMac source MAC address. used by L2 ether header. + * @param dstMac destination MAC address. used by L2 ether header. + * @param payload the payload. + */ + @NonNull + private ByteBuffer buildTcpv4Packet(@Nullable final MacAddress srcMac, + @Nullable final MacAddress dstMac, @Nullable final ByteBuffer payload) + throws Exception { + final boolean hasEther = (srcMac != null && dstMac != null); + final int payloadLen = (payload == null) ? 0 : payload.limit(); + final ByteBuffer buffer = PacketBuilder.allocate(hasEther, IPPROTO_IP, IPPROTO_TCP, + payloadLen); + final PacketBuilder packetBuilder = new PacketBuilder(buffer); + + if (hasEther) packetBuilder.writeL2Header(srcMac, dstMac, (short) ETHER_TYPE_IPV4); + packetBuilder.writeIpv4Header(TYPE_OF_SERVICE, ID, FLAGS_AND_FRAGMENT_OFFSET, + TIME_TO_LIVE, (byte) IPPROTO_TCP, IPV4_SRC_ADDR, IPV4_DST_ADDR); + packetBuilder.writeTcpHeader(SRC_PORT, DST_PORT, SEQ_NO, ACK_NO, + TCPHDR_ACK, WINDOW, URGENT_POINTER); + if (payload != null) { + buffer.put(payload); + // in case data might be reused by caller, restore the position and + // limit of bytebuffer. + payload.clear(); + } + + return packetBuilder.finalizePacket(); + } + + private void checkEtherHeader(final ByteBuffer actual) { + final EthernetHeader eth = Struct.parse(EthernetHeader.class, actual); + assertEquals(SRC_MAC, eth.srcMac); + assertEquals(DST_MAC, eth.dstMac); + assertEquals(ETHER_TYPE_IPV4, eth.etherType); + } + + private void checkIpv4Header(final boolean hasData, final ByteBuffer actual) { + final Ipv4Header ipv4Header = Struct.parse(Ipv4Header.class, actual); + assertEquals(Ipv4Header.IPHDR_VERSION_IHL, ipv4Header.vi); + assertEquals(TYPE_OF_SERVICE, ipv4Header.tos); + assertEquals(ID, ipv4Header.id); + assertEquals(FLAGS_AND_FRAGMENT_OFFSET, ipv4Header.flagsAndFragmentOffset); + assertEquals(TIME_TO_LIVE, ipv4Header.ttl); + assertEquals(IPV4_SRC_ADDR, ipv4Header.srcIp); + assertEquals(IPV4_DST_ADDR, ipv4Header.dstIp); + + final int dataLength = hasData ? DATA.limit() : 0; + assertEquals(IPV4_HEADER_MIN_LEN + TCP_HEADER_MIN_LEN + dataLength, + ipv4Header.totalLength); + assertEquals((byte) IPPROTO_TCP, ipv4Header.protocol); + assertEquals(hasData ? (short) 0xe488 : (short) 0xe48c, ipv4Header.checksum); + } + + private void checkTcpv4Packet(final boolean hasEther, final boolean hasData, + final ByteBuffer actual) { + if (hasEther) { + checkEtherHeader(actual); + } + checkIpv4Header(hasData, actual); + + final TcpHeader tcpHeader = Struct.parse(TcpHeader.class, actual); + assertEquals(SRC_PORT, tcpHeader.srcPort); + assertEquals(DST_PORT, tcpHeader.dstPort); + assertEquals(SEQ_NO, tcpHeader.seq); + assertEquals(ACK_NO, tcpHeader.ack); + assertEquals((short) 0x5010 /* offset=5(*4bytes), control bits=ACK */, + tcpHeader.dataOffsetAndControlBits); + assertEquals(WINDOW, tcpHeader.window); + assertEquals(hasData ? (short) 0x4844 : (short) 0xe5e5, tcpHeader.checksum); + assertEquals(URGENT_POINTER, tcpHeader.urgentPointer); + } + + @Test + public void testBuildPacketEtherIPv4Tcp() throws Exception { + final ByteBuffer packet = buildTcpv4Packet(SRC_MAC, DST_MAC, null /* data */); + checkTcpv4Packet(true /* hasEther */, false /* hasData */, packet); + assertArrayEquals(TEST_PACKET_ETHERHDR_IPV4HDR_TCPHDR, packet.array()); + } + + @Test + public void testBuildPacketEtherIPv4TcpData() throws Exception { + final ByteBuffer packet = buildTcpv4Packet(SRC_MAC, DST_MAC, DATA); + checkTcpv4Packet(true /* hasEther */, true /* hasData */, packet); + assertArrayEquals(TEST_PACKET_ETHERHDR_IPV4HDR_TCPHDR_DATA, + packet.array()); + } + + @Test + public void testBuildPacketIPv4Tcp() throws Exception { + final ByteBuffer packet = buildTcpv4Packet(null /* srcMac */, null /* dstMac */, + null /* data */); + checkTcpv4Packet(false /* hasEther */, false /* hasData */, packet); + assertArrayEquals(TEST_PACKET_IPV4HDR_TCPHDR, packet.array()); + } + + @Test + public void testBuildPacketIPv4TcpData() throws Exception { + final ByteBuffer packet = buildTcpv4Packet(null /* srcMac */, null /* dstMac */, DATA); + checkTcpv4Packet(false /* hasEther */, true /* hasData */, packet); + assertArrayEquals(TEST_PACKET_IPV4HDR_TCPHDR_DATA, packet.array()); + } + + @Test + public void testFinalizePacketWithoutIpv4Header() throws Exception { + final ByteBuffer buffer = PacketBuilder.allocate(false /* hasEther */, IPPROTO_IP, + IPPROTO_TCP, 0 /* payloadLen */); + final PacketBuilder packetBuilder = new PacketBuilder(buffer); + packetBuilder.writeTcpHeader(SRC_PORT, DST_PORT, SEQ_NO, ACK_NO, + TCPHDR_ACK, WINDOW, URGENT_POINTER); + assertThrows("java.io.IOException: Packet is missing IPv4 header", IOException.class, + () -> packetBuilder.finalizePacket()); + } + + @Test + public void testFinalizePacketWithoutTcpHeader() throws Exception { + final ByteBuffer buffer = PacketBuilder.allocate(false /* hasEther */, IPPROTO_IP, + IPPROTO_TCP, 0 /* payloadLen */); + final PacketBuilder packetBuilder = new PacketBuilder(buffer); + packetBuilder.writeIpv4Header(TYPE_OF_SERVICE, ID, FLAGS_AND_FRAGMENT_OFFSET, + TIME_TO_LIVE, (byte) IPPROTO_TCP, IPV4_SRC_ADDR, IPV4_DST_ADDR); + assertThrows("java.io.IOException: Packet is missing TCP headers", IOException.class, + () -> packetBuilder.finalizePacket()); + } + + @Test + public void testWriteL2HeaderToInsufficientBuffer() throws Exception { + final PacketBuilder packetBuilder = new PacketBuilder(ByteBuffer.allocate(1)); + assertThrows(IOException.class, + () -> packetBuilder.writeL2Header(SRC_MAC, DST_MAC, (short) ETHER_TYPE_IPV4)); + } + + @Test + public void testWriteIpv4HeaderToInsufficientBuffer() throws Exception { + final PacketBuilder packetBuilder = new PacketBuilder(ByteBuffer.allocate(1)); + assertThrows(IOException.class, + () -> packetBuilder.writeIpv4Header(TYPE_OF_SERVICE, ID, FLAGS_AND_FRAGMENT_OFFSET, + TIME_TO_LIVE, (byte) IPPROTO_TCP, IPV4_SRC_ADDR, IPV4_DST_ADDR)); + } + + @Test + public void testWriteTcpHeaderToInsufficientBuffer() throws Exception { + final PacketBuilder packetBuilder = new PacketBuilder(ByteBuffer.allocate(1)); + assertThrows(IOException.class, + () -> packetBuilder.writeTcpHeader(SRC_PORT, DST_PORT, SEQ_NO, ACK_NO, + TCPHDR_ACK, WINDOW, URGENT_POINTER)); + } + + private static Inet4Address addr(String addr) { + return (Inet4Address) InetAddresses.parseNumericAddress(addr); + } +} From de9ac2853b26e5908738bd3fe7e76dc53cf40396 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Wed, 15 Sep 2021 20:32:05 +0800 Subject: [PATCH 311/777] PacketBuilder: add support for UDP Note that IPv4 and UDP options are not supported. Test: atest NetworkStaticLibTests Change-Id: I15757da19311c5bae9b8b56674bef467afa7142a --- .../net/module/util/PacketBuilder.java | 51 +++- .../module/util/NetworkStackConstants.java | 3 +- .../net/module/util/PacketBuilderTest.java | 242 ++++++++++++++++-- 3 files changed, 264 insertions(+), 32 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/PacketBuilder.java b/staticlibs/device/com/android/net/module/util/PacketBuilder.java index e9ecb94dec..c9085289e8 100644 --- a/staticlibs/device/com/android/net/module/util/PacketBuilder.java +++ b/staticlibs/device/com/android/net/module/util/PacketBuilder.java @@ -18,12 +18,16 @@ package com.android.net.module.util; import static android.system.OsConstants.IPPROTO_IP; import static android.system.OsConstants.IPPROTO_TCP; +import static android.system.OsConstants.IPPROTO_UDP; import static com.android.net.module.util.IpUtils.ipChecksum; import static com.android.net.module.util.IpUtils.tcpChecksum; +import static com.android.net.module.util.IpUtils.udpChecksum; import static com.android.net.module.util.NetworkStackConstants.IPV4_CHECKSUM_OFFSET; import static com.android.net.module.util.NetworkStackConstants.IPV4_LENGTH_OFFSET; import static com.android.net.module.util.NetworkStackConstants.TCP_CHECKSUM_OFFSET; +import static com.android.net.module.util.NetworkStackConstants.UDP_CHECKSUM_OFFSET; +import static com.android.net.module.util.NetworkStackConstants.UDP_LENGTH_OFFSET; import android.net.MacAddress; @@ -32,6 +36,7 @@ import androidx.annotation.NonNull; import com.android.net.module.util.structs.EthernetHeader; import com.android.net.module.util.structs.Ipv4Header; import com.android.net.module.util.structs.TcpHeader; +import com.android.net.module.util.structs.UdpHeader; import java.io.IOException; import java.net.Inet4Address; @@ -46,7 +51,7 @@ import java.nio.ByteBuffer; * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Layer 3 header (Ipv4Header) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Layer 4 header (TcpHeader) | + * | Layer 4 header (TcpHeader, UdpHeader) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Payload | (optional) * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -73,6 +78,7 @@ public class PacketBuilder { private int mIpv4HeaderOffset = -1; private int mTcpHeaderOffset = -1; + private int mUdpHeaderOffset = -1; public PacketBuilder(@NonNull ByteBuffer buffer) { mBuffer = buffer; @@ -151,6 +157,26 @@ public class PacketBuilder { } } + /** + * Write a UDP header. + * The UDP header length and checksum are calculated and written back in #finalizePacket. + * + * @param srcPort source port + * @param dstPort destination port + */ + public void writeUdpHeader(short srcPort, short dstPort) throws IOException { + mUdpHeaderOffset = mBuffer.position(); + final UdpHeader udpHeader = new UdpHeader(srcPort, dstPort, + (short) 0 /* length, calculate in #finalizePacket */, + (short) 0 /* checksum, calculate in #finalizePacket */); + + try { + udpHeader.writeToByteBuffer(mBuffer); + } catch (IllegalArgumentException | BufferOverflowException e) { + throw new IOException("Error writing to buffer: ", e); + } + } + /** * Finalize the packet. * @@ -173,13 +199,21 @@ public class PacketBuilder { mBuffer.putShort(mIpv4HeaderOffset + IPV4_CHECKSUM_OFFSET, ipChecksum(mBuffer, mIpv4HeaderOffset /* headerOffset */)); - // Populate the TCP header checksum field. if (mTcpHeaderOffset > 0) { + // Populate the TCP header checksum field. mBuffer.putShort(mTcpHeaderOffset + TCP_CHECKSUM_OFFSET, tcpChecksum(mBuffer, mIpv4HeaderOffset /* ipOffset */, mTcpHeaderOffset /* transportOffset */, mBuffer.position() - mTcpHeaderOffset /* transportLen */)); - } else { // TODO: add support for UDP - throw new IOException("Packet is missing TCP header"); + } else if (mUdpHeaderOffset > 0) { + // Populate the UDP header length field. + mBuffer.putShort(mUdpHeaderOffset + UDP_LENGTH_OFFSET, + (short) (mBuffer.position() - mUdpHeaderOffset)); + + // Populate the UDP header checksum field. + mBuffer.putShort(mUdpHeaderOffset + UDP_CHECKSUM_OFFSET, udpChecksum(mBuffer, + mIpv4HeaderOffset /* ipOffset */, mUdpHeaderOffset /* transportOffset */)); + } else { + throw new IOException("Packet is missing neither TCP nor UDP header"); } mBuffer.flip(); @@ -192,7 +226,8 @@ public class PacketBuilder { * @param hasEther has ethernet header. Set this flag to indicate that the packet has an * ethernet header. * @param l3proto the layer 3 protocol. Only {@code IPPROTO_IP} currently supported. - * @param l4proto the layer 4 protocol. Only {@code IPPROTO_TCP} currently supported. + * @param l4proto the layer 4 protocol. Only {@code IPPROTO_TCP} and {@code IPPROTO_UDP} + * currently supported. * @param payloadLen length of the payload. */ @NonNull @@ -202,8 +237,7 @@ public class PacketBuilder { throw new IllegalArgumentException("Unsupported layer 3 protocol " + l3proto); } - if (l4proto != IPPROTO_TCP) { - // TODO: add support for UDP + if (l4proto != IPPROTO_TCP && l4proto != IPPROTO_UDP) { throw new IllegalArgumentException("Unsupported layer 4 protocol " + l4proto); } @@ -214,7 +248,8 @@ public class PacketBuilder { int packetLen = 0; if (hasEther) packetLen += Struct.getSize(EthernetHeader.class); packetLen += Struct.getSize(Ipv4Header.class); - packetLen += Struct.getSize(TcpHeader.class); + packetLen += (l4proto == IPPROTO_TCP) ? Struct.getSize(TcpHeader.class) + : Struct.getSize(UdpHeader.class); packetLen += payloadLen; return ByteBuffer.allocate(packetLen); diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 378e4857a6..353fe6921e 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -187,7 +187,8 @@ public final class NetworkStackConstants { * - https://tools.ietf.org/html/rfc768 */ public static final int UDP_HEADER_LEN = 8; - + public static final int UDP_LENGTH_OFFSET = 4; + public static final int UDP_CHECKSUM_OFFSET = 6; /** * DHCP constants. diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java index 275aa847d3..8f9a1f996e 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java @@ -18,15 +18,18 @@ package com.android.net.module.util; import static android.system.OsConstants.IPPROTO_IP; import static android.system.OsConstants.IPPROTO_TCP; +import static android.system.OsConstants.IPPROTO_UDP; import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV4; import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN; import static com.android.net.module.util.NetworkStackConstants.TCPHDR_ACK; import static com.android.net.module.util.NetworkStackConstants.TCP_HEADER_MIN_LEN; +import static com.android.net.module.util.NetworkStackConstants.UDP_HEADER_LEN; import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import android.net.InetAddresses; import android.net.MacAddress; @@ -39,6 +42,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.net.module.util.structs.EthernetHeader; import com.android.net.module.util.structs.Ipv4Header; import com.android.net.module.util.structs.TcpHeader; +import com.android.net.module.util.structs.UdpHeader; import org.junit.Test; import org.junit.runner.RunWith; @@ -168,8 +172,92 @@ public class PacketBuilderTest { (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef }; + private static final byte[] TEST_PACKET_ETHERHDR_IPV4HDR_UDPHDR = + new byte[] { + // packet = (scapy.Ether(src="11:22:33:44:55:66", dst="aa:bb:cc:dd:ee:ff", + // type='IPv4') / + // scapy.IP(src="192.0.2.1", dst="198.51.100.1", + // tos=0, id=27149, flags='DF') / + // scapy.UDP(sport=9876, dport=433)) + // Ether header + (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, + (byte) 0xee, (byte) 0xff, (byte) 0x11, (byte) 0x22, + (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66, + (byte) 0x08, (byte) 0x00, + // IP header + (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x1c, + (byte) 0x6a, (byte) 0x0d, (byte) 0x40, (byte) 0x00, + (byte) 0x40, (byte) 0x11, (byte) 0xe4, (byte) 0x8d, + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, + (byte) 0xc6, (byte) 0x33, (byte) 0x64, (byte) 0x01, + // UDP header + (byte) 0x26, (byte) 0x94, (byte) 0x01, (byte) 0xb1, + (byte) 0x00, (byte) 0x08, (byte) 0xeb, (byte) 0x62 + }; + + private static final byte[] TEST_PACKET_ETHERHDR_IPV4HDR_UDPHDR_DATA = + new byte[] { + // packet = (scapy.Ether(src="11:22:33:44:55:66", dst="aa:bb:cc:dd:ee:ff", + // type='IPv4') / + // scapy.IP(src="192.0.2.1", dst="198.51.100.1", + // tos=0, id=27149, flags='DF') / + // scapy.UDP(sport=9876, dport=433) / + // b'\xde\xad\xbe\xef') + // Ether header + (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, + (byte) 0xee, (byte) 0xff, (byte) 0x11, (byte) 0x22, + (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66, + (byte) 0x08, (byte) 0x00, + // IP header + (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x20, + (byte) 0x6a, (byte) 0x0d, (byte) 0x40, (byte) 0x00, + (byte) 0x40, (byte) 0x11, (byte) 0xe4, (byte) 0x89, + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, + (byte) 0xc6, (byte) 0x33, (byte) 0x64, (byte) 0x01, + // UDP header + (byte) 0x26, (byte) 0x94, (byte) 0x01, (byte) 0xb1, + (byte) 0x00, (byte) 0x0c, (byte) 0x4d, (byte) 0xbd, + // Data + (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef + }; + + private static final byte[] TEST_PACKET_IPV4HDR_UDPHDR = + new byte[] { + // packet = (scapy.IP(src="192.0.2.1", dst="198.51.100.1", + // tos=0, id=27149, flags='DF') / + // scapy.UDP(sport=9876, dport=433)) + // IP header + (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x1c, + (byte) 0x6a, (byte) 0x0d, (byte) 0x40, (byte) 0x00, + (byte) 0x40, (byte) 0x11, (byte) 0xe4, (byte) 0x8d, + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, + (byte) 0xc6, (byte) 0x33, (byte) 0x64, (byte) 0x01, + // UDP header + (byte) 0x26, (byte) 0x94, (byte) 0x01, (byte) 0xb1, + (byte) 0x00, (byte) 0x08, (byte) 0xeb, (byte) 0x62 + }; + + private static final byte[] TEST_PACKET_IPV4HDR_UDPHDR_DATA = + new byte[] { + // packet = (scapy.IP(src="192.0.2.1", dst="198.51.100.1", + // tos=0, id=27149, flags='DF') / + // scapy.UDP(sport=9876, dport=433) / + // b'\xde\xad\xbe\xef') + // IP header + (byte) 0x45, (byte) 0x00, (byte) 0x00, (byte) 0x20, + (byte) 0x6a, (byte) 0x0d, (byte) 0x40, (byte) 0x00, + (byte) 0x40, (byte) 0x11, (byte) 0xe4, (byte) 0x89, + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, + (byte) 0xc6, (byte) 0x33, (byte) 0x64, (byte) 0x01, + // UDP header + (byte) 0x26, (byte) 0x94, (byte) 0x01, (byte) 0xb1, + (byte) 0x00, (byte) 0x0c, (byte) 0x4d, (byte) 0xbd, + // Data + (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef + }; + /** - * Build a TCPv4 packet which has ether header, IPv4 header, TCP header and data. + * Build an IPv4 packet which has ether header, IPv4 header, TCP/UDP header and data. * The ethernet header and data are optional. Note that both source mac address and * destination mac address are required for ethernet header. * @@ -178,30 +266,40 @@ public class PacketBuilderTest { * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Layer 3 header (Ipv4Header) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Layer 4 header (TcpHeader) | + * | Layer 4 header (TcpHeader, UdpHeader) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Payload | (optional) * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * @param srcMac source MAC address. used by L2 ether header. * @param dstMac destination MAC address. used by L2 ether header. + * @param l4proto the layer 4 protocol. support either IPPROTO_TCP or IPPROTO_UDP. * @param payload the payload. */ @NonNull - private ByteBuffer buildTcpv4Packet(@Nullable final MacAddress srcMac, - @Nullable final MacAddress dstMac, @Nullable final ByteBuffer payload) + private ByteBuffer buildIpv4Packet(@Nullable final MacAddress srcMac, + @Nullable final MacAddress dstMac, final int l4proto, + @Nullable final ByteBuffer payload) throws Exception { + if (l4proto != IPPROTO_TCP && l4proto != IPPROTO_UDP) { + fail("Unsupported layer 4 protocol " + l4proto); + } + final boolean hasEther = (srcMac != null && dstMac != null); final int payloadLen = (payload == null) ? 0 : payload.limit(); - final ByteBuffer buffer = PacketBuilder.allocate(hasEther, IPPROTO_IP, IPPROTO_TCP, + final ByteBuffer buffer = PacketBuilder.allocate(hasEther, IPPROTO_IP, l4proto, payloadLen); final PacketBuilder packetBuilder = new PacketBuilder(buffer); if (hasEther) packetBuilder.writeL2Header(srcMac, dstMac, (short) ETHER_TYPE_IPV4); packetBuilder.writeIpv4Header(TYPE_OF_SERVICE, ID, FLAGS_AND_FRAGMENT_OFFSET, - TIME_TO_LIVE, (byte) IPPROTO_TCP, IPV4_SRC_ADDR, IPV4_DST_ADDR); - packetBuilder.writeTcpHeader(SRC_PORT, DST_PORT, SEQ_NO, ACK_NO, - TCPHDR_ACK, WINDOW, URGENT_POINTER); + TIME_TO_LIVE, (byte) l4proto, IPV4_SRC_ADDR, IPV4_DST_ADDR); + if (l4proto == IPPROTO_TCP) { + packetBuilder.writeTcpHeader(SRC_PORT, DST_PORT, SEQ_NO, ACK_NO, + TCPHDR_ACK, WINDOW, URGENT_POINTER); + } else if (l4proto == IPPROTO_UDP) { + packetBuilder.writeUdpHeader(SRC_PORT, DST_PORT); + } if (payload != null) { buffer.put(payload); // in case data might be reused by caller, restore the position and @@ -212,6 +310,11 @@ public class PacketBuilderTest { return packetBuilder.finalizePacket(); } + /** + * Check ethernet header. + * + * @param actual the packet to check. + */ private void checkEtherHeader(final ByteBuffer actual) { final EthernetHeader eth = Struct.parse(EthernetHeader.class, actual); assertEquals(SRC_MAC, eth.srcMac); @@ -219,7 +322,19 @@ public class PacketBuilderTest { assertEquals(ETHER_TYPE_IPV4, eth.etherType); } - private void checkIpv4Header(final boolean hasData, final ByteBuffer actual) { + /** + * Check IPv4 header. + * + * @param l4proto the layer 4 protocol. support either IPPROTO_TCP or IPPROTO_UDP. + * @param hasData true if the packet has data payload; false otherwise. + * @param actual the packet to check. + */ + private void checkIpv4Header(final int l4proto, final boolean hasData, + final ByteBuffer actual) { + if (l4proto != IPPROTO_TCP && l4proto != IPPROTO_UDP) { + fail("Unsupported layer 4 protocol " + l4proto); + } + final Ipv4Header ipv4Header = Struct.parse(Ipv4Header.class, actual); assertEquals(Ipv4Header.IPHDR_VERSION_IHL, ipv4Header.vi); assertEquals(TYPE_OF_SERVICE, ipv4Header.tos); @@ -230,18 +345,32 @@ public class PacketBuilderTest { assertEquals(IPV4_DST_ADDR, ipv4Header.dstIp); final int dataLength = hasData ? DATA.limit() : 0; - assertEquals(IPV4_HEADER_MIN_LEN + TCP_HEADER_MIN_LEN + dataLength, - ipv4Header.totalLength); - assertEquals((byte) IPPROTO_TCP, ipv4Header.protocol); - assertEquals(hasData ? (short) 0xe488 : (short) 0xe48c, ipv4Header.checksum); + if (l4proto == IPPROTO_TCP) { + assertEquals(IPV4_HEADER_MIN_LEN + TCP_HEADER_MIN_LEN + dataLength, + ipv4Header.totalLength); + assertEquals((byte) IPPROTO_TCP, ipv4Header.protocol); + assertEquals(hasData ? (short) 0xe488 : (short) 0xe48c, ipv4Header.checksum); + } else if (l4proto == IPPROTO_UDP) { + assertEquals(IPV4_HEADER_MIN_LEN + UDP_HEADER_LEN + dataLength, + ipv4Header.totalLength); + assertEquals((byte) IPPROTO_UDP, ipv4Header.protocol); + assertEquals(hasData ? (short) 0xe489 : (short) 0xe48d, ipv4Header.checksum); + } } + /** + * Check TCPv4 packet. + * + * @param hasEther true if the packet has ether header; false otherwise. + * @param hasData true if the packet has data payload; false otherwise. + * @param actual the packet to check. + */ private void checkTcpv4Packet(final boolean hasEther, final boolean hasData, final ByteBuffer actual) { if (hasEther) { checkEtherHeader(actual); } - checkIpv4Header(hasData, actual); + checkIpv4Header(IPPROTO_TCP, hasData, actual); final TcpHeader tcpHeader = Struct.parse(TcpHeader.class, actual); assertEquals(SRC_PORT, tcpHeader.srcPort); @@ -253,18 +382,48 @@ public class PacketBuilderTest { assertEquals(WINDOW, tcpHeader.window); assertEquals(hasData ? (short) 0x4844 : (short) 0xe5e5, tcpHeader.checksum); assertEquals(URGENT_POINTER, tcpHeader.urgentPointer); + + if (hasData) { + assertEquals(0xdeadbeef, actual.getInt()); + } + } + + /** + * Check UDPv4 packet. + * + * @param hasEther true if the packet has ether header; false otherwise. + * @param hasData true if the packet has data payload; false otherwise. + * @param actual the packet to check. + */ + private void checkUdpv4Packet(final boolean hasEther, final boolean hasData, + final ByteBuffer actual) { + if (hasEther) { + checkEtherHeader(actual); + } + checkIpv4Header(IPPROTO_UDP, hasData, actual); + + final UdpHeader udpHeader = Struct.parse(UdpHeader.class, actual); + assertEquals(SRC_PORT, udpHeader.srcPort); + assertEquals(DST_PORT, udpHeader.dstPort); + final int dataLength = hasData ? DATA.limit() : 0; + assertEquals(UDP_HEADER_LEN + dataLength, udpHeader.length); + assertEquals(hasData ? (short) 0x4dbd : (short) 0xeb62, udpHeader.checksum); + + if (hasData) { + assertEquals(0xdeadbeef, actual.getInt()); + } } @Test public void testBuildPacketEtherIPv4Tcp() throws Exception { - final ByteBuffer packet = buildTcpv4Packet(SRC_MAC, DST_MAC, null /* data */); + final ByteBuffer packet = buildIpv4Packet(SRC_MAC, DST_MAC, IPPROTO_TCP, null /* data */); checkTcpv4Packet(true /* hasEther */, false /* hasData */, packet); assertArrayEquals(TEST_PACKET_ETHERHDR_IPV4HDR_TCPHDR, packet.array()); } @Test public void testBuildPacketEtherIPv4TcpData() throws Exception { - final ByteBuffer packet = buildTcpv4Packet(SRC_MAC, DST_MAC, DATA); + final ByteBuffer packet = buildIpv4Packet(SRC_MAC, DST_MAC, IPPROTO_TCP, DATA); checkTcpv4Packet(true /* hasEther */, true /* hasData */, packet); assertArrayEquals(TEST_PACKET_ETHERHDR_IPV4HDR_TCPHDR_DATA, packet.array()); @@ -272,19 +431,50 @@ public class PacketBuilderTest { @Test public void testBuildPacketIPv4Tcp() throws Exception { - final ByteBuffer packet = buildTcpv4Packet(null /* srcMac */, null /* dstMac */, - null /* data */); + final ByteBuffer packet = buildIpv4Packet(null /* srcMac */, null /* dstMac */, + IPPROTO_TCP, null /* data */); checkTcpv4Packet(false /* hasEther */, false /* hasData */, packet); assertArrayEquals(TEST_PACKET_IPV4HDR_TCPHDR, packet.array()); } @Test - public void testBuildPacketIPv4TcpData() throws Exception { - final ByteBuffer packet = buildTcpv4Packet(null /* srcMac */, null /* dstMac */, DATA); + public void testBuildPacketIPv4TcpData() throws Exception { + final ByteBuffer packet = buildIpv4Packet(null /* srcMac */, null /* dstMac */, + IPPROTO_TCP, DATA); checkTcpv4Packet(false /* hasEther */, true /* hasData */, packet); assertArrayEquals(TEST_PACKET_IPV4HDR_TCPHDR_DATA, packet.array()); } + @Test + public void testBuildPacketEtherIPv4Udp() throws Exception { + final ByteBuffer packet = buildIpv4Packet(SRC_MAC, DST_MAC, IPPROTO_UDP, null /* data */); + checkUdpv4Packet(true /* hasEther */, false /* hasData */, packet); + assertArrayEquals(TEST_PACKET_ETHERHDR_IPV4HDR_UDPHDR, packet.array()); + } + + @Test + public void testBuildPacketEtherIPv4UdpData() throws Exception { + final ByteBuffer packet = buildIpv4Packet(SRC_MAC, DST_MAC, IPPROTO_UDP, DATA); + checkUdpv4Packet(true /* hasEther */, true /* hasData */, packet); + assertArrayEquals(TEST_PACKET_ETHERHDR_IPV4HDR_UDPHDR_DATA, packet.array()); + } + + @Test + public void testBuildPacketIPv4Udp() throws Exception { + final ByteBuffer packet = buildIpv4Packet(null /* srcMac */, null /* dstMac */, + IPPROTO_UDP, null /*data*/); + checkUdpv4Packet(false /* hasEther */, false /* hasData */, packet); + assertArrayEquals(TEST_PACKET_IPV4HDR_UDPHDR, packet.array()); + } + + @Test + public void testBuildPacketIPv4UdpData() throws Exception { + final ByteBuffer packet = buildIpv4Packet(null /* srcMac */, null /* dstMac */, + IPPROTO_UDP, DATA); + checkUdpv4Packet(false /* hasEther */, true /* hasData */, packet); + assertArrayEquals(TEST_PACKET_IPV4HDR_UDPHDR_DATA, packet.array()); + } + @Test public void testFinalizePacketWithoutIpv4Header() throws Exception { final ByteBuffer buffer = PacketBuilder.allocate(false /* hasEther */, IPPROTO_IP, @@ -297,14 +487,14 @@ public class PacketBuilderTest { } @Test - public void testFinalizePacketWithoutTcpHeader() throws Exception { + public void testFinalizePacketWithoutL4Header() throws Exception { final ByteBuffer buffer = PacketBuilder.allocate(false /* hasEther */, IPPROTO_IP, IPPROTO_TCP, 0 /* payloadLen */); final PacketBuilder packetBuilder = new PacketBuilder(buffer); packetBuilder.writeIpv4Header(TYPE_OF_SERVICE, ID, FLAGS_AND_FRAGMENT_OFFSET, TIME_TO_LIVE, (byte) IPPROTO_TCP, IPV4_SRC_ADDR, IPV4_DST_ADDR); - assertThrows("java.io.IOException: Packet is missing TCP headers", IOException.class, - () -> packetBuilder.finalizePacket()); + assertThrows("java.io.IOException: Packet is missing neither TCP nor UDP header", + IOException.class, () -> packetBuilder.finalizePacket()); } @Test @@ -330,6 +520,12 @@ public class PacketBuilderTest { TCPHDR_ACK, WINDOW, URGENT_POINTER)); } + @Test + public void testWriteUdpHeaderToInsufficientBuffer() throws Exception { + final PacketBuilder packetBuilder = new PacketBuilder(ByteBuffer.allocate(1)); + assertThrows(IOException.class, () -> packetBuilder.writeUdpHeader(SRC_PORT, DST_PORT)); + } + private static Inet4Address addr(String addr) { return (Inet4Address) InetAddresses.parseNumericAddress(addr); } From 5b33e07357b77df3b2695248212900aec4dbe5c5 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 15 Dec 2021 09:48:20 +0900 Subject: [PATCH 312/777] Remove apex_available for bluetooth.updatable The build will pass without it, showing that it's not exercised today, and the bluetooth apex is being renamed anyway. Bug: 206614050 Test: m Change-Id: I71dac10159b799b9f23550d27424f19d077164cc --- staticlibs/netd/Android.bp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index 530ccd30d7..c3f93747a2 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -25,7 +25,6 @@ java_library { ], apex_available: [ "//apex_available:platform", // used from services.net - "com.android.bluetooth.updatable", "com.android.tethering", "com.android.wifi", ], @@ -89,7 +88,6 @@ aidl_interface { // either outside the system server or use jarjar to rename the generated AIDL classes. apex_available: [ "//apex_available:platform", // used from services.net - "com.android.bluetooth.updatable", "com.android.tethering", "com.android.wifi", ], @@ -125,7 +123,6 @@ java_library { ], apex_available: [ "//apex_available:platform", - "com.android.bluetooth.updatable", "com.android.wifi", "com.android.tethering", ], @@ -149,7 +146,6 @@ aidl_interface { java: { apex_available: [ "//apex_available:platform", - "com.android.bluetooth.updatable", "com.android.wifi", "com.android.tethering", ], From c57b00d86337a70aeae8ecf6a3e82acd99fd4b91 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 15 Dec 2021 02:28:13 +0000 Subject: [PATCH 313/777] Clarify that JNI libraries used for jarjar'd classes must be statically linked. This appears to be necessary for safety. Change-Id: I1db3c38a5e4bbcfd1b785e310313ab25ef557280 Test: documentation-only change --- staticlibs/native/README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/staticlibs/native/README.md b/staticlibs/native/README.md index 18d19c464e..1f505c4de1 100644 --- a/staticlibs/native/README.md +++ b/staticlibs/native/README.md @@ -22,6 +22,9 @@ When you want to use JNI library from frameworks/lib/net: * Each module creates a native library in their directory, which statically links against the common native library (e.g. libnet_utils_device_common_bpf), and calls the native registered - function by hardcoding the post-jarjar class_name. - - + function by hardcoding the post-jarjar class_name. Linkage *MUST* be static because common + functions in the file (e.g., `register_com_android_net_module_util_BpfMap`) will appear in the + library (`.so`) file, and different versions of the library loaded in the same process by + different modules will in general have different versions. It's important that each of these + libraries loads the common function from its own library. Static linkage should guarantee this + because static linkage resolves symbols at build time, not runtime. \ No newline at end of file From 85bff36a5862d5a07c98e990cff68f11baff374e Mon Sep 17 00:00:00 2001 From: Ayush Sharma Date: Thu, 16 Dec 2021 14:40:13 +0000 Subject: [PATCH 314/777] Revert "Suppress NewApi warnings for @SystemApi -> public APIs" Revert "Add VpnServiceBuilderShim for VpnService.Builder" Revert submission 1551943-vpn-impl Reason for revert: , bug b/210979001 Reverted Changes: I0e7aa077a:Add VpnServiceBuilderShim for VpnService.Builder Ib12f5ab39:Suppress NewApi warnings for @SystemApi -> public ... I59b9185cf:Unhide RouteInfo#getType and related fields Ie5b62b2b2:Unhide IpPrefix(InetAddress, int) I993a32d40:Add CTS tests for exclude VPN routes APIs Ib24b2d3fb:Suppress NewApi warnings for @SystemApi -> public ... Ic3b10464a:Add APIs that allow to exclude routes from VPN Change-Id: I5b918dbf4293168c2a02cfe1c0f6ca8342b3195c BUG: 210979001 --- .../module/util/netlink/RtNetlinkRouteMessage.java | 2 -- .../net/module/util/netlink/StructNdOptPref64.java | 2 -- .../src/com/android/net/module/util/IpRangeTest.java | 12 ------------ .../net/module/util/LinkPropertiesUtilsTest.java | 2 -- .../src/com/android/net/module/util/StructTest.java | 2 -- .../module/util/netlink/StructNdOptPref64Test.java | 2 -- 6 files changed, 22 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java index 1705f1c803..c5efcb2651 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java @@ -22,7 +22,6 @@ import static android.system.OsConstants.AF_INET6; import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY; import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ANY; -import android.annotation.SuppressLint; import android.net.IpPrefix; import android.system.OsConstants; @@ -108,7 +107,6 @@ public class RtNetlinkRouteMessage extends NetlinkMessage { * @param header netlink message header. * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. */ - @SuppressLint("NewApi") @Nullable public static RtNetlinkRouteMessage parse(@NonNull final StructNlMsgHdr header, @NonNull final ByteBuffer byteBuffer) { diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java b/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java index 8226346649..f6b2e0e504 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java @@ -16,7 +16,6 @@ package com.android.net.module.util.netlink; -import android.annotation.SuppressLint; import android.net.IpPrefix; import android.util.Log; @@ -108,7 +107,6 @@ public class StructNdOptPref64 extends NdOption { this.lifetime = lifetime & 0xfff8; } - @SuppressLint("NewApi") private StructNdOptPref64(@NonNull ByteBuffer buf) { super(buf.get(), Byte.toUnsignedInt(buf.get())); if (type != TYPE) throw new IllegalArgumentException("Invalid type " + type); diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java index 20bbd4a143..f44b17d751 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java @@ -22,7 +22,6 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import android.annotation.SuppressLint; import android.net.InetAddresses; import android.net.IpPrefix; @@ -93,7 +92,6 @@ public class IpRangeTest { } } - @SuppressLint("NewApi") @Test public void testConstructor() { IpRange r = new IpRange(new IpPrefix(IPV4_ADDR, 32)); @@ -121,7 +119,6 @@ public class IpRangeTest { assertEquals(IPV6_RANGE_END, r.getEndAddr()); } - @SuppressLint("NewApi") @Test public void testContainsRangeEqualRanges() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); @@ -132,7 +129,6 @@ public class IpRangeTest { assertEquals(r1, r2); } - @SuppressLint("NewApi") @Test public void testContainsRangeSubset() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 64)); @@ -143,7 +139,6 @@ public class IpRangeTest { assertNotEquals(r1, r2); } - @SuppressLint("NewApi") @Test public void testContainsRangeTruncatesLowerOrderBits() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 100)); @@ -154,7 +149,6 @@ public class IpRangeTest { assertEquals(r1, r2); } - @SuppressLint("NewApi") @Test public void testContainsRangeSubsetSameStartAddr() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); @@ -165,7 +159,6 @@ public class IpRangeTest { assertNotEquals(r1, r2); } - @SuppressLint("NewApi") @Test public void testContainsRangeOverlapping() { final IpRange r1 = new IpRange(new IpPrefix(address("2001:db9::"), 32)); @@ -176,7 +169,6 @@ public class IpRangeTest { assertNotEquals(r1, r2); } - @SuppressLint("NewApi") @Test public void testOverlapsRangeEqualRanges() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); @@ -187,7 +179,6 @@ public class IpRangeTest { assertEquals(r1, r2); } - @SuppressLint("NewApi") @Test public void testOverlapsRangeSubset() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); @@ -198,7 +189,6 @@ public class IpRangeTest { assertNotEquals(r1, r2); } - @SuppressLint("NewApi") @Test public void testOverlapsRangeDisjoint() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 32)); @@ -209,7 +199,6 @@ public class IpRangeTest { assertNotEquals(r1, r2); } - @SuppressLint("NewApi") @Test public void testOverlapsRangePartialOverlapLow() { final IpRange r1 = new IpRange(new IpPrefix(address("2001:db9::"), 32)); @@ -220,7 +209,6 @@ public class IpRangeTest { assertNotEquals(r1, r2); } - @SuppressLint("NewApi") @Test public void testOverlapsRangePartialOverlapHigh() { final IpRange r1 = new IpRange(new IpPrefix(address("2001:db7::"), 32)); diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java index 09f0490283..3d2d6ebaac 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java @@ -22,7 +22,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import android.annotation.SuppressLint; import android.net.InetAddresses; import android.net.IpPrefix; import android.net.LinkAddress; @@ -47,7 +46,6 @@ import java.util.function.Function; @RunWith(AndroidJUnit4.class) public final class LinkPropertiesUtilsTest { - @SuppressLint("NewApi") private static final IpPrefix PREFIX = new IpPrefix(toInetAddress("75.208.6.0"), 24); private static final InetAddress V4_ADDR = toInetAddress("75.208.6.1"); private static final InetAddress V6_ADDR = toInetAddress( diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java index 4e46210649..eabc14b4bf 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java @@ -24,7 +24,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; -import android.annotation.SuppressLint; import android.net.InetAddresses; import android.net.IpPrefix; import android.net.MacAddress; @@ -454,7 +453,6 @@ public class StructTest { } } - @SuppressLint("NewApi") private void verifyPrefixByteArrayParsing(final PrefixMessage msg) throws Exception { // The original PREF64 option message has just 12 bytes for prefix byte array // (Highest 96 bits of the Prefix), copyOf pads the 128-bits IPv6 address with diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java index beed838356..57248eada6 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java @@ -24,7 +24,6 @@ import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import android.annotation.SuppressLint; import android.net.IpPrefix; import androidx.test.filters.SmallTest; @@ -52,7 +51,6 @@ public class StructNdOptPref64Test { return prefixBytes; } - @SuppressLint("NewApi") private static IpPrefix prefix(String addrString, int prefixLength) throws Exception { return new IpPrefix(InetAddress.getByName(addrString), prefixLength); } From 95c8d0b833fef36b4deb0af530b5c92d61e21807 Mon Sep 17 00:00:00 2001 From: Ayush Sharma Date: Thu, 16 Dec 2021 14:40:13 +0000 Subject: [PATCH 315/777] Revert "Suppress NewApi warnings for @SystemApi -> public APIs" Revert "Add VpnServiceBuilderShim for VpnService.Builder" Revert submission 1551943-vpn-impl Reason for revert: , bug b/210979001 Reverted Changes: I0e7aa077a:Add VpnServiceBuilderShim for VpnService.Builder Ib12f5ab39:Suppress NewApi warnings for @SystemApi -> public ... I59b9185cf:Unhide RouteInfo#getType and related fields Ie5b62b2b2:Unhide IpPrefix(InetAddress, int) I993a32d40:Add CTS tests for exclude VPN routes APIs Ib24b2d3fb:Suppress NewApi warnings for @SystemApi -> public ... Ic3b10464a:Add APIs that allow to exclude routes from VPN Change-Id: I5b918dbf4293168c2a02cfe1c0f6ca8342b3195c BUG: 210979001 --- .../client-libs/netd/com/android/net/module/util/NetdUtils.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java b/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java index de13d4267f..e78e3367e7 100644 --- a/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java +++ b/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java @@ -23,7 +23,6 @@ import static android.net.RouteInfo.RTN_UNICAST; import static android.net.RouteInfo.RTN_UNREACHABLE; import static android.system.OsConstants.EBUSY; -import android.annotation.SuppressLint; import android.net.INetd; import android.net.InterfaceConfigurationParcel; import android.net.IpPrefix; @@ -214,7 +213,6 @@ public class NetdUtils { return failures; } - @SuppressLint("NewApi") private static String findNextHop(final RouteInfo route) { final String nextHop; switch (route.getType()) { From 7e266d7f561a6a4b493e042ecdb2e8e4c2703bda Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 16 Dec 2021 13:33:58 -0800 Subject: [PATCH 316/777] Added a new network capability MMTEL Added NET_CAPABILITY_MMTEL to indicate a network support MMTEL (Multimedia telephony). This is for IMS service to request an IMS network that supports voice or PS (VoPS for 4G, VoNR for 5G). Bug: 210774375 Test: atest ConnectivityServiceTest Change-Id: I38655bef234e86b08ba4dbfd6fcc1634f379ade9 --- .../com/android/net/module/util/NetworkCapabilitiesUtils.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 903214e22c..d5f23b7580 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -25,6 +25,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MCX; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_MMTEL; import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS; import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL; @@ -129,7 +130,8 @@ public final class NetworkCapabilitiesUtils { | (1 << NET_CAPABILITY_RCS) | (1 << NET_CAPABILITY_VEHICLE_INTERNAL) | (1 << NET_CAPABILITY_VSIM) - | (1 << NET_CAPABILITY_XCAP); + | (1 << NET_CAPABILITY_XCAP) + | (1L << NET_CAPABILITY_MMTEL); /** * Capabilities that force network to be restricted. From 98905d9ab714a50cd904781ef3d84cf4fbef697d Mon Sep 17 00:00:00 2001 From: Taras Antoshchuk Date: Sun, 19 Dec 2021 12:04:26 +0000 Subject: [PATCH 317/777] Revert "Revert "Suppress NewApi warnings for @SystemApi -> public APIs"" This reverts commit d654277abfa0abd1268acc6db1753536509e41c8. Reason for revert: Re-landing changes not related to postsubmit failure Change-Id: I72fd6b908deeb293f1f3a342f006515029972089 --- .../module/util/netlink/RtNetlinkRouteMessage.java | 2 ++ .../net/module/util/netlink/StructNdOptPref64.java | 2 ++ .../src/com/android/net/module/util/IpRangeTest.java | 12 ++++++++++++ .../net/module/util/LinkPropertiesUtilsTest.java | 2 ++ .../src/com/android/net/module/util/StructTest.java | 2 ++ .../module/util/netlink/StructNdOptPref64Test.java | 2 ++ 6 files changed, 22 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java index c5efcb2651..1705f1c803 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java @@ -22,6 +22,7 @@ import static android.system.OsConstants.AF_INET6; import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY; import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ANY; +import android.annotation.SuppressLint; import android.net.IpPrefix; import android.system.OsConstants; @@ -107,6 +108,7 @@ public class RtNetlinkRouteMessage extends NetlinkMessage { * @param header netlink message header. * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. */ + @SuppressLint("NewApi") @Nullable public static RtNetlinkRouteMessage parse(@NonNull final StructNlMsgHdr header, @NonNull final ByteBuffer byteBuffer) { diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java b/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java index f6b2e0e504..8226346649 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNdOptPref64.java @@ -16,6 +16,7 @@ package com.android.net.module.util.netlink; +import android.annotation.SuppressLint; import android.net.IpPrefix; import android.util.Log; @@ -107,6 +108,7 @@ public class StructNdOptPref64 extends NdOption { this.lifetime = lifetime & 0xfff8; } + @SuppressLint("NewApi") private StructNdOptPref64(@NonNull ByteBuffer buf) { super(buf.get(), Byte.toUnsignedInt(buf.get())); if (type != TYPE) throw new IllegalArgumentException("Invalid type " + type); diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java index f44b17d751..20bbd4a143 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/IpRangeTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.annotation.SuppressLint; import android.net.InetAddresses; import android.net.IpPrefix; @@ -92,6 +93,7 @@ public class IpRangeTest { } } + @SuppressLint("NewApi") @Test public void testConstructor() { IpRange r = new IpRange(new IpPrefix(IPV4_ADDR, 32)); @@ -119,6 +121,7 @@ public class IpRangeTest { assertEquals(IPV6_RANGE_END, r.getEndAddr()); } + @SuppressLint("NewApi") @Test public void testContainsRangeEqualRanges() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); @@ -129,6 +132,7 @@ public class IpRangeTest { assertEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testContainsRangeSubset() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 64)); @@ -139,6 +143,7 @@ public class IpRangeTest { assertNotEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testContainsRangeTruncatesLowerOrderBits() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 100)); @@ -149,6 +154,7 @@ public class IpRangeTest { assertEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testContainsRangeSubsetSameStartAddr() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); @@ -159,6 +165,7 @@ public class IpRangeTest { assertNotEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testContainsRangeOverlapping() { final IpRange r1 = new IpRange(new IpPrefix(address("2001:db9::"), 32)); @@ -169,6 +176,7 @@ public class IpRangeTest { assertNotEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testOverlapsRangeEqualRanges() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); @@ -179,6 +187,7 @@ public class IpRangeTest { assertEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testOverlapsRangeSubset() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 35)); @@ -189,6 +198,7 @@ public class IpRangeTest { assertNotEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testOverlapsRangeDisjoint() { final IpRange r1 = new IpRange(new IpPrefix(IPV6_ADDR, 32)); @@ -199,6 +209,7 @@ public class IpRangeTest { assertNotEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testOverlapsRangePartialOverlapLow() { final IpRange r1 = new IpRange(new IpPrefix(address("2001:db9::"), 32)); @@ -209,6 +220,7 @@ public class IpRangeTest { assertNotEquals(r1, r2); } + @SuppressLint("NewApi") @Test public void testOverlapsRangePartialOverlapHigh() { final IpRange r1 = new IpRange(new IpPrefix(address("2001:db7::"), 32)); diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java index 3d2d6ebaac..09f0490283 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import android.annotation.SuppressLint; import android.net.InetAddresses; import android.net.IpPrefix; import android.net.LinkAddress; @@ -46,6 +47,7 @@ import java.util.function.Function; @RunWith(AndroidJUnit4.class) public final class LinkPropertiesUtilsTest { + @SuppressLint("NewApi") private static final IpPrefix PREFIX = new IpPrefix(toInetAddress("75.208.6.0"), 24); private static final InetAddress V4_ADDR = toInetAddress("75.208.6.1"); private static final InetAddress V6_ADDR = toInetAddress( diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java index eabc14b4bf..4e46210649 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import android.annotation.SuppressLint; import android.net.InetAddresses; import android.net.IpPrefix; import android.net.MacAddress; @@ -453,6 +454,7 @@ public class StructTest { } } + @SuppressLint("NewApi") private void verifyPrefixByteArrayParsing(final PrefixMessage msg) throws Exception { // The original PREF64 option message has just 12 bytes for prefix byte array // (Highest 96 bits of the Prefix), copyOf pads the 128-bits IPv6 address with diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java index 57248eada6..beed838356 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNdOptPref64Test.java @@ -24,6 +24,7 @@ import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import android.annotation.SuppressLint; import android.net.IpPrefix; import androidx.test.filters.SmallTest; @@ -51,6 +52,7 @@ public class StructNdOptPref64Test { return prefixBytes; } + @SuppressLint("NewApi") private static IpPrefix prefix(String addrString, int prefixLength) throws Exception { return new IpPrefix(InetAddress.getByName(addrString), prefixLength); } From ec655bb3b58cc067b63bb84828b58b236033e9c3 Mon Sep 17 00:00:00 2001 From: Taras Antoshchuk Date: Sun, 19 Dec 2021 12:04:26 +0000 Subject: [PATCH 318/777] Revert "Revert "Suppress NewApi warnings for @SystemApi -> public APIs"" This reverts commit d654277abfa0abd1268acc6db1753536509e41c8. Reason for revert: Re-landing changes not related to postsubmit failure Change-Id: I72fd6b908deeb293f1f3a342f006515029972089 --- .../client-libs/netd/com/android/net/module/util/NetdUtils.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java b/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java index e78e3367e7..de13d4267f 100644 --- a/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java +++ b/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java @@ -23,6 +23,7 @@ import static android.net.RouteInfo.RTN_UNICAST; import static android.net.RouteInfo.RTN_UNREACHABLE; import static android.system.OsConstants.EBUSY; +import android.annotation.SuppressLint; import android.net.INetd; import android.net.InterfaceConfigurationParcel; import android.net.IpPrefix; @@ -213,6 +214,7 @@ public class NetdUtils { return failures; } + @SuppressLint("NewApi") private static String findNextHop(final RouteInfo route) { final String nextHop; switch (route.getType()) { From e1ac304dc60ce049135883eb2bd6a88797fc880b Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Thu, 16 Dec 2021 23:17:44 +0900 Subject: [PATCH 319/777] Remove ambiguity when using error().code(). A recent change in android::base::Result has changed the type of error().code() from int to Errno. The latter is a new type that provides a type-safe way of handling errno values. The new type supports conversion to and from int for compatibility reasons. However, that conversion has caused an ambiguity when int and Error are used at the same time in a ternary operator. The type of an expression "(cond) ? 0 : ret.error().code()" is ambiguous. It can be int because error().code() can be converted to an int. It can also be Error because 0 can be converted to Errno. To eliminate the ambiguity, add a static cast. Bug: 209929099 Test: m Change-Id: I0ad634310d9094868c29754f96c5c98e6180b738 --- staticlibs/netd/libnetdutils/include/netdutils/Status.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Status.h b/staticlibs/netd/libnetdutils/include/netdutils/Status.h index bc347d5e9e..7b0bd4729d 100644 --- a/staticlibs/netd/libnetdutils/include/netdutils/Status.h +++ b/staticlibs/netd/libnetdutils/include/netdutils/Status.h @@ -42,7 +42,7 @@ class [[nodiscard]] Status { Status(int code, std::string msg) : mCode(code), mMsg(std::move(msg)) { assert(!ok()); } Status(android::base::Result result) - : mCode(result.ok() ? 0 : result.error().code()), + : mCode(result.ok() ? 0 : static_cast(result.error().code())), mMsg(result.ok() ? "" : result.error().message()) {} int code() const { return mCode; } From 0c538d941530025a1b8ebdccddee64d7a25ef4f1 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 20 Dec 2021 08:58:16 +0000 Subject: [PATCH 320/777] [MS10.3] Move multiplySafeByRational to NetworkStatsUtils Test: atest NetworkStaticLibTests:com.android.net.moduletests.util.NetworkStatsUtilsTest Bug: 204830222 Change-Id: I87df4dc754f6fc46ea1a7e8770a3c76c019e097e --- .../net/module/util/NetworkStatsUtils.java | 55 ++++++++++++++++++ .../net/module/util/NetworkStatsUtilsTest.kt | 58 +++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/NetworkStatsUtilsTest.kt diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java new file mode 100644 index 0000000000..13bbe76e83 --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util; + +/** + * Various utilities used for NetworkStats related code. + * + * @hide + */ +public class NetworkStatsUtils { + /** + * Safely multiple a value by a rational. + *

+ * Internally it uses integer-based math whenever possible, but switches + * over to double-based math if values would overflow. + * @hide + */ + public static long multiplySafeByRational(long value, long num, long den) { + if (den == 0) { + throw new ArithmeticException("Invalid Denominator"); + } + long x = value; + long y = num; + + // Logic shamelessly borrowed from Math.multiplyExact() + long r = x * y; + long ax = Math.abs(x); + long ay = Math.abs(y); + if (((ax | ay) >>> 31 != 0)) { + // Some bits greater than 2^31 that might cause overflow + // Check the result using the divide operator + // and check for the special case of Long.MIN_VALUE * -1 + if (((y != 0) && (r / y != x)) + || (x == Long.MIN_VALUE && y == -1)) { + // Use double math to avoid overflowing + return (long) (((double) num / den) * value); + } + } + return r / den; + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkStatsUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkStatsUtilsTest.kt new file mode 100644 index 0000000000..820eb9b5fd --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkStatsUtilsTest.kt @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util + +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.testutils.assertThrows +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.test.assertEquals + +@RunWith(AndroidJUnit4::class) +@SmallTest +class NetworkStatsUtilsTest { + @Test + fun testMultiplySafeByRational() { + // Verify basic cases that the method equals to a * b / c. + assertEquals(3 * 5 / 2, NetworkStatsUtils.multiplySafeByRational(3, 5, 2)) + + // Verify input with zeros. + assertEquals(0 * 7 / 3, NetworkStatsUtils.multiplySafeByRational(0, 7, 3)) + assertEquals(7 * 0 / 3, NetworkStatsUtils.multiplySafeByRational(7, 0, 3)) + assertEquals(0 * 0 / 1, NetworkStatsUtils.multiplySafeByRational(0, 0, 1)) + assertEquals(0, NetworkStatsUtils.multiplySafeByRational(0, Long.MAX_VALUE, Long.MAX_VALUE)) + assertEquals(0, NetworkStatsUtils.multiplySafeByRational(Long.MAX_VALUE, 0, Long.MAX_VALUE)) + assertThrows(ArithmeticException::class.java) { + NetworkStatsUtils.multiplySafeByRational(7, 3, 0) + } + assertThrows(ArithmeticException::class.java) { + NetworkStatsUtils.multiplySafeByRational(0, 0, 0) + } + + // Verify cases where a * b overflows. + assertEquals(101, NetworkStatsUtils.multiplySafeByRational( + 101, Long.MAX_VALUE, Long.MAX_VALUE)) + assertEquals(721, NetworkStatsUtils.multiplySafeByRational( + Long.MAX_VALUE, 721, Long.MAX_VALUE)) + assertEquals(Long.MAX_VALUE, NetworkStatsUtils.multiplySafeByRational( + Long.MAX_VALUE, Long.MAX_VALUE, Long.MAX_VALUE)) + assertThrows(ArithmeticException::class.java) { + NetworkStatsUtils.multiplySafeByRational(Long.MAX_VALUE, Long.MAX_VALUE, 0) + } + } +} \ No newline at end of file From 0b5b2cd9f44480d3554e7eab1dc720e00fb92e7f Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 20 Dec 2021 23:09:10 +0900 Subject: [PATCH 321/777] Import constants from NetCaps instead of defining them All downstream branches are now S+. Test: m Change-Id: I3a4a291b7469bc51c0298fac4ee6639908ec26d5 --- .../module/util/NetworkCapabilitiesUtils.java | 42 +++---------------- 1 file changed, 5 insertions(+), 37 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 903214e22c..d6222a7fc1 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -16,9 +16,11 @@ package com.android.net.module.util; +import static android.net.NetworkCapabilities.NET_CAPABILITY_BIP; import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE; import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA; import static android.net.NetworkCapabilities.NET_CAPABILITY_IA; import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; @@ -26,8 +28,11 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MCX; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; +import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE; import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS; import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VSIM; import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P; import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP; import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; @@ -73,43 +78,6 @@ public final class NetworkCapabilitiesUtils { // realistic as possible. }; - /** - * See android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE - * TODO: Use API constant when all downstream branches are S-based - */ - public static final int NET_CAPABILITY_OEM_PRIVATE = 26; - - /** - * See android.net.NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL - * TODO: Use API constant when all downstream branches are S-based - */ - public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; - - /** - * See android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED - * TODO: Use API constant when all downstream branches are S-based - */ - public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; - - /** - * See android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE - * TODO: Use API constant when all downstream branches are S-based - */ - public static final int NET_CAPABILITY_ENTERPRISE = 29; - - /** - * See android.net.NetworkCapabilities.NET_CAPABILITY_VSIM - * TODO: Use API constant when all downstream branches are S-based - */ - public static final int NET_CAPABILITY_VSIM = 30; - - /** - * See android.net.NetworkCapabilities.NET_CAPABILITY_BIP - * TODO: Use API constant when all downstream branches are S-based - */ - public static final int NET_CAPABILITY_BIP = 31; - - /** * Capabilities that suggest that a network is restricted. * See {@code NetworkCapabilities#maybeMarkCapabilitiesRestricted}, From ed3e1c3cfcf25c91277e9aae27877798a8bc4068 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 20 Dec 2021 10:07:37 +0000 Subject: [PATCH 322/777] Revert "Add net-utils-annotations lib" This reverts commit 9caba5092ae90669a1df13dcf491bdceef07bf55. Reason for revert: Plan to move the annotation class into Connecitivty module Change-Id: I2fa17921d3dceda4082fa04d696fe9f5bbccbc1b --- staticlibs/Android.bp | 28 --------------- .../net/annotations/PolicyDirection.java | 35 ------------------- 2 files changed, 63 deletions(-) delete mode 100644 staticlibs/annotations/android/net/annotations/PolicyDirection.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 4c58228c6d..50cfb02b80 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -334,31 +334,3 @@ filegroup { "//packages/modules/Wifi/service", ], } - -// This file group is deprecated; new users should use net-utils-annotations -filegroup { - name: "net-utils-annotations-srcs", - srcs: [ - "annotations/android/net/annotations/PolicyDirection.java", - ], - visibility: [ - "//frameworks/base", - ], -} - - -java_library { - name: "net-utils-annotations", - srcs: [":net-utils-annotations-srcs"], - libs: [ - "framework-annotations-lib", - ], - sdk_version: "system_current", - min_sdk_version: "30", - visibility: ["//visibility:public"], - apex_available: [ - "//apex_available:anyapex", - "//apex_available:platform", - ], - lint: { strict_updatability_linting: true }, -} diff --git a/staticlibs/annotations/android/net/annotations/PolicyDirection.java b/staticlibs/annotations/android/net/annotations/PolicyDirection.java deleted file mode 100644 index febd9b4061..0000000000 --- a/staticlibs/annotations/android/net/annotations/PolicyDirection.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2019 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.annotations; - -import android.annotation.IntDef; -import android.net.IpSecManager; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * IPsec traffic direction. - * - *

Mainline modules cannot reference hidden @IntDef. Moving this annotation to a separate class - * to allow others to statically include it. - * - * @hide - */ -@IntDef(value = {IpSecManager.DIRECTION_IN, IpSecManager.DIRECTION_OUT}) -@Retention(RetentionPolicy.SOURCE) -public @interface PolicyDirection {} From 0f1ee4ca8151cfe2823a29fff091ccf3e6f37da5 Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Tue, 21 Dec 2021 15:58:45 +0800 Subject: [PATCH 323/777] Rename bpf_map_utils to bpf_headers Use a generic name so that it can contain more bpf related headers. Bug: 202086915 Test: build Change-Id: I5a76948db394d8d7bb6eaedb570a2ca5bc99a289 --- staticlibs/native/{bpf_map_utils => bpf_headers}/Android.bp | 2 +- staticlibs/native/{bpf_map_utils => bpf_headers}/BpfMapTest.cpp | 0 staticlibs/native/{bpf_map_utils => bpf_headers}/TEST_MAPPING | 0 .../native/{bpf_map_utils => bpf_headers}/include/bpf/BpfMap.h | 0 .../{bpf_map_utils => bpf_headers}/include/bpf/BpfUtils.h | 0 .../include/bpf/WaitForProgsLoaded.h | 0 6 files changed, 1 insertion(+), 1 deletion(-) rename staticlibs/native/{bpf_map_utils => bpf_headers}/Android.bp (98%) rename staticlibs/native/{bpf_map_utils => bpf_headers}/BpfMapTest.cpp (100%) rename staticlibs/native/{bpf_map_utils => bpf_headers}/TEST_MAPPING (100%) rename staticlibs/native/{bpf_map_utils => bpf_headers}/include/bpf/BpfMap.h (100%) rename staticlibs/native/{bpf_map_utils => bpf_headers}/include/bpf/BpfUtils.h (100%) rename staticlibs/native/{bpf_map_utils => bpf_headers}/include/bpf/WaitForProgsLoaded.h (100%) diff --git a/staticlibs/native/bpf_map_utils/Android.bp b/staticlibs/native/bpf_headers/Android.bp similarity index 98% rename from staticlibs/native/bpf_map_utils/Android.bp rename to staticlibs/native/bpf_headers/Android.bp index e14c259096..4ec4d581e9 100644 --- a/staticlibs/native/bpf_map_utils/Android.bp +++ b/staticlibs/native/bpf_headers/Android.bp @@ -17,7 +17,7 @@ package { } cc_library_headers { - name: "bpf_map_utils", + name: "bpf_headers", vendor_available: true, host_supported: true, native_bridge_supported: true, diff --git a/staticlibs/native/bpf_map_utils/BpfMapTest.cpp b/staticlibs/native/bpf_headers/BpfMapTest.cpp similarity index 100% rename from staticlibs/native/bpf_map_utils/BpfMapTest.cpp rename to staticlibs/native/bpf_headers/BpfMapTest.cpp diff --git a/staticlibs/native/bpf_map_utils/TEST_MAPPING b/staticlibs/native/bpf_headers/TEST_MAPPING similarity index 100% rename from staticlibs/native/bpf_map_utils/TEST_MAPPING rename to staticlibs/native/bpf_headers/TEST_MAPPING diff --git a/staticlibs/native/bpf_map_utils/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h similarity index 100% rename from staticlibs/native/bpf_map_utils/include/bpf/BpfMap.h rename to staticlibs/native/bpf_headers/include/bpf/BpfMap.h diff --git a/staticlibs/native/bpf_map_utils/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h similarity index 100% rename from staticlibs/native/bpf_map_utils/include/bpf/BpfUtils.h rename to staticlibs/native/bpf_headers/include/bpf/BpfUtils.h diff --git a/staticlibs/native/bpf_map_utils/include/bpf/WaitForProgsLoaded.h b/staticlibs/native/bpf_headers/include/bpf/WaitForProgsLoaded.h similarity index 100% rename from staticlibs/native/bpf_map_utils/include/bpf/WaitForProgsLoaded.h rename to staticlibs/native/bpf_headers/include/bpf/WaitForProgsLoaded.h From 318a3eed1c3a9da838c5899cdb1a8d7cae817348 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 21 Dec 2021 09:21:06 +0000 Subject: [PATCH 324/777] [MS15.3] Move SUBSCRIBER_ID_MATCH_RULE_* constants to static lib Subscriber Id Match Rules won't be exposed as system Api. Any caller who references NetworkTemplate#SUBSCRIBER_ID_MATCH_RULE_* should use the one in NetworkStatsUtils instead. And remove the need of the constants as soon as possible. Test: atest NetworkPolicyManagerServiceTest \ FrameworksNetTests Bug: 204830222 Change-Id: I7c0ca89c8e2a860f5bab29ac6f9bc5af2a548b99 --- .../android/net/module/util/NetworkStatsUtils.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java index 13bbe76e83..7ea40a145d 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java @@ -52,4 +52,18 @@ public class NetworkStatsUtils { } return r / den; } + + /** + * Value of the match rule of the subscriberId to match networks with specific subscriberId. + * + * @hide + */ + public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0; + /** + * Value of the match rule of the subscriberId to match networks with any subscriberId which + * includes null and non-null. + * + * @hide + */ + public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1; } From 0de46b2b44fa2efccf37a922e11d697117041ce5 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 21 Dec 2021 11:24:01 +0000 Subject: [PATCH 325/777] Revert "Added a new network capability MMTEL" Revert submission 1927643-mmtel_capability Reason for revert: b/211586152 Reverted Changes: Ifea8b1e40:Added a new network capability MMTEL I38655bef2:Added a new network capability MMTEL I837606d9e:Added setup/tear down data support I2c7b291fe:Added a new network capability MMTEL Change-Id: Ibd7f8e486562230b50d99a8e03d70841a9900e6f --- .../com/android/net/module/util/NetworkCapabilitiesUtils.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index d5f23b7580..903214e22c 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -25,7 +25,6 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MCX; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; -import static android.net.NetworkCapabilities.NET_CAPABILITY_MMTEL; import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS; import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL; @@ -130,8 +129,7 @@ public final class NetworkCapabilitiesUtils { | (1 << NET_CAPABILITY_RCS) | (1 << NET_CAPABILITY_VEHICLE_INTERNAL) | (1 << NET_CAPABILITY_VSIM) - | (1 << NET_CAPABILITY_XCAP) - | (1L << NET_CAPABILITY_MMTEL); + | (1 << NET_CAPABILITY_XCAP); /** * Capabilities that force network to be restricted. From 45c7b15553cc838e50d24df35b8b47a666a39772 Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Mon, 20 Dec 2021 18:22:06 +0800 Subject: [PATCH 326/777] [NETD-BPF#23] Move a few headers to frameworks/libs/net BPF headers used by both platform and mainline modules should be in frameworks/libs/net. Bug: 202086915 Test: build and boot Test: cd packages/modules/Connectivity/netd; atest Change-Id: Ie6f257b022cdea6bab3389a9fa41791f893e54c3 --- .../bpf_headers/include/bpf/bpf_helpers.h | 216 ++++++++++++++++++ .../bpf_headers/include/bpf/bpf_map_def.h | 177 ++++++++++++++ 2 files changed, 393 insertions(+) create mode 100644 staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h create mode 100644 staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h new file mode 100644 index 0000000000..878bb103a0 --- /dev/null +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -0,0 +1,216 @@ +/* Common BPF helpers to be used by all BPF programs loaded by Android */ + +#include +#include +#include + +#include "bpf_map_def.h" + +/****************************************************************************** + * WARNING: CHANGES TO THIS FILE OUTSIDE OF AOSP/MASTER ARE LIKELY TO BREAK * + * DEVICE COMPATIBILITY WITH MAINLINE MODULES SHIPPING EBPF CODE. * + * * + * THIS WILL LIKELY RESULT IN BRICKED DEVICES AT SOME ARBITRARY FUTURE TIME * + * * + * THAT GOES ESPECIALLY FOR THE 'SECTION' 'LICENSE' AND 'CRITICAL' MACROS * + * * + * We strongly suggest that if you need changes to bpfloader functionality * + * you get your changes reviewed and accepted into aosp/master. * + * * + ******************************************************************************/ + +/* For mainline module use, you can #define BPFLOADER_{MIN/MAX}_VER + * before #include "bpf_helpers.h" to change which bpfloaders will + * process the resulting .o file. + * + * While this will work outside of mainline too, there just is no point to + * using it when the .o and the bpfloader ship in sync with each other. + */ +#ifndef BPFLOADER_MIN_VER +#define BPFLOADER_MIN_VER DEFAULT_BPFLOADER_MIN_VER +#endif + +#ifndef BPFLOADER_MAX_VER +#define BPFLOADER_MAX_VER DEFAULT_BPFLOADER_MAX_VER +#endif + +/* place things in different elf sections */ +#define SECTION(NAME) __attribute__((section(NAME), used)) + +/* Must be present in every program, example usage: + * LICENSE("GPL"); or LICENSE("Apache 2.0"); + * + * We also take this opportunity to embed a bunch of other useful values in + * the resulting .o (This is to enable some limited forward compatibility + * with mainline module shipped ebpf programs) + * + * The bpfloader_{min/max}_ver defines the [min, max) range of bpfloader + * versions that should load this .o file (bpfloaders outside of this range + * will simply ignore/skip this *entire* .o) + * The [inclusive,exclusive) matches what we do for kernel ver dependencies. + * + * The size_of_bpf_{map,prog}_def allow the bpfloader to load programs where + * these structures have been extended with additional fields (they will of + * course simply be ignored then). + * + * If missing, bpfloader_{min/max}_ver default to 0/0x10000 ie. [v0.0, v1.0), + * while size_of_bpf_{map/prog}_def default to 32/20 which are the v0.0 sizes. + */ +#define LICENSE(NAME) \ + unsigned int _bpfloader_min_ver SECTION("bpfloader_min_ver") = BPFLOADER_MIN_VER; \ + unsigned int _bpfloader_max_ver SECTION("bpfloader_max_ver") = BPFLOADER_MAX_VER; \ + size_t _size_of_bpf_map_def SECTION("size_of_bpf_map_def") = sizeof(struct bpf_map_def); \ + size_t _size_of_bpf_prog_def SECTION("size_of_bpf_prog_def") = sizeof(struct bpf_prog_def); \ + char _license[] SECTION("license") = (NAME) + +/* flag the resulting bpf .o file as critical to system functionality, + * loading all kernel version appropriate programs in it must succeed + * for bpfloader success + */ +#define CRITICAL(REASON) char _critical[] SECTION("critical") = (REASON) + +/* + * Helper functions called from eBPF programs written in C. These are + * implemented in the kernel sources. + */ + +#define KVER_NONE 0 +#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c)) +#define KVER_INF 0xFFFFFFFFu + +/* generic functions */ + +/* + * Type-unsafe bpf map functions - avoid if possible. + * + * Using these it is possible to pass in keys/values of the wrong type/size, + * or, for 'bpf_map_lookup_elem_unsafe' receive into a pointer to the wrong type. + * You will not get a compile time failure, and for certain types of errors you + * might not even get a failure from the kernel's ebpf verifier during program load, + * instead stuff might just not work right at runtime. + * + * Instead please use: + * DEFINE_BPF_MAP(foo_map, TYPE, KeyType, ValueType, num_entries) + * where TYPE can be something like HASH or ARRAY, and num_entries is an integer. + * + * This defines the map (hence this should not be used in a header file included + * from multiple locations) and provides type safe accessors: + * ValueType * bpf_foo_map_lookup_elem(const KeyType *) + * int bpf_foo_map_update_elem(const KeyType *, const ValueType *, flags) + * int bpf_foo_map_delete_elem(const KeyType *) + * + * This will make sure that if you change the type of a map you'll get compile + * errors at any spots you forget to update with the new type. + * + * Note: these all take pointers to const map because from the C/eBPF point of view + * the map struct is really just a readonly map definition of the in kernel object. + * Runtime modification of the map defining struct is meaningless, since + * the contents is only ever used during bpf program loading & map creation + * by the bpf loader, and not by the eBPF program itself. + */ +static void* (*bpf_map_lookup_elem_unsafe)(const struct bpf_map_def* map, + const void* key) = (void*)BPF_FUNC_map_lookup_elem; +static int (*bpf_map_update_elem_unsafe)(const struct bpf_map_def* map, const void* key, + const void* value, unsigned long long flags) = (void*) + BPF_FUNC_map_update_elem; +static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, + const void* key) = (void*)BPF_FUNC_map_delete_elem; + +/* type safe macro to declare a map and related accessor functions */ +#define DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, usr, grp, md) \ + const struct bpf_map_def SECTION("maps") the_map = { \ + .type = BPF_MAP_TYPE_##TYPE, \ + .key_size = sizeof(TypeOfKey), \ + .value_size = sizeof(TypeOfValue), \ + .max_entries = (num_entries), \ + .map_flags = 0, \ + .uid = (usr), \ + .gid = (grp), \ + .mode = (md), \ + .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER, \ + .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER, \ + .min_kver = KVER_NONE, \ + .max_kver = KVER_INF, \ + }; \ + \ + static inline __always_inline __unused TypeOfValue* bpf_##the_map##_lookup_elem( \ + const TypeOfKey* k) { \ + return bpf_map_lookup_elem_unsafe(&the_map, k); \ + }; \ + \ + static inline __always_inline __unused int bpf_##the_map##_update_elem( \ + const TypeOfKey* k, const TypeOfValue* v, unsigned long long flags) { \ + return bpf_map_update_elem_unsafe(&the_map, k, v, flags); \ + }; \ + \ + static inline __always_inline __unused int bpf_##the_map##_delete_elem(const TypeOfKey* k) { \ + return bpf_map_delete_elem_unsafe(&the_map, k); \ + }; + +#define DEFINE_BPF_MAP(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, AID_ROOT, 0600) + +#define DEFINE_BPF_MAP_GWO(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, gid) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, gid, 0620) + +#define DEFINE_BPF_MAP_GRO(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, gid) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, gid, 0640) + +#define DEFINE_BPF_MAP_GRW(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, gid) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, gid, 0660) + +static int (*bpf_probe_read)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read; +static int (*bpf_probe_read_str)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read_str; +static unsigned long long (*bpf_ktime_get_ns)(void) = (void*) BPF_FUNC_ktime_get_ns; +static unsigned long long (*bpf_ktime_get_boot_ns)(void) = (void*)BPF_FUNC_ktime_get_boot_ns; +static int (*bpf_trace_printk)(const char* fmt, int fmt_size, ...) = (void*) BPF_FUNC_trace_printk; +static unsigned long long (*bpf_get_current_pid_tgid)(void) = (void*) BPF_FUNC_get_current_pid_tgid; +static unsigned long long (*bpf_get_current_uid_gid)(void) = (void*) BPF_FUNC_get_current_uid_gid; +static unsigned long long (*bpf_get_smp_processor_id)(void) = (void*) BPF_FUNC_get_smp_processor_id; + +#define DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \ + opt) \ + const struct bpf_prog_def SECTION("progs") the_prog##_def = { \ + .uid = (prog_uid), \ + .gid = (prog_gid), \ + .min_kver = (min_kv), \ + .max_kver = (max_kv), \ + .optional = (opt), \ + .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER, \ + .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER, \ + }; \ + SECTION(SECTION_NAME) \ + int the_prog + +// Programs (here used in the sense of functions/sections) marked optional are allowed to fail +// to load (for example due to missing kernel patches). +// The bpfloader will just ignore these failures and continue processing the next section. +// +// A non-optional program (function/section) failing to load causes a failure and aborts +// processing of the entire .o, if the .o is additionally marked critical, this will result +// in the entire bpfloader process terminating with a failure and not setting the bpf.progs_loaded +// system property. This in turn results in waitForProgsLoaded() never finishing. +// +// ie. a non-optional program in a critical .o is mandatory for kernels matching the min/max kver. + +// programs requiring a kernel version >= min_kv && < max_kv +#define DEFINE_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv) \ + DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \ + false) +#define DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, \ + max_kv) \ + DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, true) + +// programs requiring a kernel version >= min_kv +#define DEFINE_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv) \ + DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, KVER_INF, \ + false) +#define DEFINE_OPTIONAL_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv) \ + DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, KVER_INF, \ + true) + +// programs with no kernel version requirements +#define DEFINE_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \ + DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, 0, KVER_INF, false) +#define DEFINE_OPTIONAL_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \ + DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, 0, KVER_INF, true) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h new file mode 100644 index 0000000000..02b2096d9a --- /dev/null +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2020 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. + */ + +#pragma once + +/* This file is separate because it's included both by eBPF programs (via include + * in bpf_helpers.h) and directly by the boot time bpfloader (Loader.cpp). + */ + +#include + +// Pull in AID_* constants from //system/core/libcutils/include/private/android_filesystem_config.h +#include + +/****************************************************************************** + * * + * ! ! ! W A R N I N G ! ! ! * + * * + * CHANGES TO THESE STRUCTURE DEFINITIONS OUTSIDE OF AOSP/MASTER *WILL* BREAK * + * MAINLINE MODULE COMPATIBILITY * + * * + * AND THUS MAY RESULT IN YOUR DEVICE BRICKING AT SOME ARBITRARY POINT IN * + * THE FUTURE * + * * + * (and even in aosp/master you may only append new fields at the very end, * + * you may *never* delete fields, change their types, ordering, insert in * + * the middle, etc. If a mainline module using the old definition has * + * already shipped (which happens roughly monthly), then it's set in stone) * + * * + ******************************************************************************/ + +// These are the values used if these fields are missing +#define DEFAULT_BPFLOADER_MIN_VER 0u // v0.0 (this is inclusive ie. >= v0.0) +#define DEFAULT_BPFLOADER_MAX_VER 0x10000u // v1.0 (this is exclusive ie. < v1.0) +#define DEFAULT_SIZEOF_BPF_MAP_DEF 32 // v0.0 struct: enum (uint sized) + 7 uint +#define DEFAULT_SIZEOF_BPF_PROG_DEF 20 // v0.0 struct: 4 uint + bool + 3 byte alignment pad + +/* + * The bpf_{map,prog}_def structures are compiled for different architectures. + * Once by the BPF compiler for the BPF architecture, and once by a C++ + * compiler for the native Android architecture for the bpfloader. + * + * For things to work, their layout must be the same between the two. + * The BPF architecture is platform independent ('64-bit LSB bpf'). + * So this effectively means these structures must be the same layout + * on 5 architectures, all of them little endian: + * 64-bit BPF, x86_64, arm and 32-bit x86 and arm + * + * As such for any types we use inside of these structs we must make sure that + * the size and alignment are the same, so the same amount of padding is used. + * + * Currently we only use: bool, enum bpf_map_type and unsigned int. + * Additionally we use char for padding. + * + * !!! WARNING: HERE BE DRAGONS !!! + * + * Be particularly careful with 64-bit integers. + * You will need to manually override their alignment to 8 bytes. + * + * To quote some parts of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69560 + * + * Some types have weaker alignment requirements when they are structure members. + * + * unsigned long long on x86 is such a type. + * + * C distinguishes C11 _Alignof (the minimum alignment the type is guaranteed + * to have in all contexts, so 4, see min_align_of_type) from GNU C __alignof + * (the normal alignment of the type, so 8). + * + * alignof / _Alignof == minimum alignment required by target ABI + * __alignof / __alignof__ == preferred alignment + * + * When in a struct, apparently the minimum alignment is used. + */ + +_Static_assert(sizeof(bool) == 1, "sizeof bool != 1"); +_Static_assert(__alignof__(bool) == 1, "__alignof__ bool != 1"); +_Static_assert(_Alignof(bool) == 1, "_Alignof bool != 1"); + +_Static_assert(sizeof(char) == 1, "sizeof char != 1"); +_Static_assert(__alignof__(char) == 1, "__alignof__ char != 1"); +_Static_assert(_Alignof(char) == 1, "_Alignof char != 1"); + +// This basically verifies that an enum is 'just' a 32-bit int +_Static_assert(sizeof(enum bpf_map_type) == 4, "sizeof enum bpf_map_type != 4"); +_Static_assert(__alignof__(enum bpf_map_type) == 4, "__alignof__ enum bpf_map_type != 4"); +_Static_assert(_Alignof(enum bpf_map_type) == 4, "_Alignof enum bpf_map_type != 4"); + +// Linux kernel requires sizeof(int) == 4, sizeof(void*) == sizeof(long), sizeof(long long) == 8 +_Static_assert(sizeof(unsigned int) == 4, "sizeof unsigned int != 4"); +_Static_assert(__alignof__(unsigned int) == 4, "__alignof__ unsigned int != 4"); +_Static_assert(_Alignof(unsigned int) == 4, "_Alignof unsigned int != 4"); + +// We don't currently use any 64-bit types in these structs, so this is purely to document issue. +// Here sizeof & __alignof__ are consistent, but _Alignof is not: compile for 'aosp_cf_x86_phone' +_Static_assert(sizeof(unsigned long long) == 8, "sizeof unsigned long long != 8"); +_Static_assert(__alignof__(unsigned long long) == 8, "__alignof__ unsigned long long != 8"); +// BPF wants 8, but 32-bit x86 wants 4 +//_Static_assert(_Alignof(unsigned long long) == 8, "_Alignof unsigned long long != 8"); + +/* + * Map structure to be used by Android eBPF C programs. The Android eBPF loader + * uses this structure from eBPF object to create maps at boot time. + * + * The eBPF C program should define structure in the maps section using + * SECTION("maps") otherwise it will be ignored by the eBPF loader. + * + * For example: + * const struct bpf_map_def SECTION("maps") mymap { .type=... , .key_size=... } + * + * See 'bpf_helpers.h' for helpful macros for eBPF program use. + */ +struct bpf_map_def { + enum bpf_map_type type; + unsigned int key_size; + unsigned int value_size; + unsigned int max_entries; + unsigned int map_flags; + + // The following are not supported by the Android bpfloader: + // unsigned int inner_map_idx; + // unsigned int numa_node; + + unsigned int uid; // uid_t + unsigned int gid; // gid_t + unsigned int mode; // mode_t + + // The following fields were added in version 0.1 + unsigned int bpfloader_min_ver; // if missing, defaults to 0, ie. v0.0 + unsigned int bpfloader_max_ver; // if missing, defaults to 0x10000, ie. v1.0 + + // The following fields were added in version 0.2 + // kernelVersion() must be >= min_kver and < max_kver + unsigned int min_kver; + unsigned int max_kver; +}; + +// This needs to be updated whenever the above structure definition is expanded. +_Static_assert(sizeof(struct bpf_map_def) == 48, "sizeof struct bpf_map_def != 48"); +_Static_assert(__alignof__(struct bpf_map_def) == 4, "__alignof__ struct bpf_map_def != 4"); +_Static_assert(_Alignof(struct bpf_map_def) == 4, "_Alignof struct bpf_map_def != 4"); + +struct bpf_prog_def { + unsigned int uid; + unsigned int gid; + + // kernelVersion() must be >= min_kver and < max_kver + unsigned int min_kver; + unsigned int max_kver; + + bool optional; // program section (ie. function) may fail to load, continue onto next func. + char pad0[3]; + + // The following fields were added in version 0.1 + unsigned int bpfloader_min_ver; // if missing, defaults to 0, ie. v0.0 + unsigned int bpfloader_max_ver; // if missing, defaults to 0x10000, ie. v1.0 + + // No new fields in version 0.2 +}; + +// This needs to be updated whenever the above structure definition is expanded. +_Static_assert(sizeof(struct bpf_prog_def) == 28, "sizeof struct bpf_prog_def != 28"); +_Static_assert(__alignof__(struct bpf_prog_def) == 4, "__alignof__ struct bpf_prog_def != 4"); +_Static_assert(_Alignof(struct bpf_prog_def) == 4, "_Alignof struct bpf_prog_def != 4"); From a6492c710fe3660bd17dfd6069b3c28527be69df Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 23 Dec 2021 05:31:53 +0000 Subject: [PATCH 327/777] Add hasFlag method in NetdUtils. Since ethernet-service related files are going to be moved into Connectivity module. To deal with InterfaceConfiguration dependency in EthernetTracker, use InterfaceConfigurationParcel instead, which returns from NetdUtils API directly. Adding a new method hasFlag in NetdUtils to replace the original InterfaceConfiguration.hasFlag, that's invisible to the Connectivity module. Bug: 210586283 Test: atest NetdStaticLibTests --iterations Change-Id: I16fcbfb8f36c8632a8267ce55cdcbd78ea6edd1a --- .../android/net/module/util/NetdUtils.java | 16 ++++++ .../net/module/util/NetdUtilsTest.java | 55 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java b/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java index e78e3367e7..3818d1f806 100644 --- a/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java +++ b/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java @@ -37,7 +37,10 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * Collection of utilities for netd. @@ -69,6 +72,19 @@ public class NetdUtils { } } + /** + * Check whether the InterfaceConfigurationParcel contains the target flag or not. + * + * @param config The InterfaceConfigurationParcel instance. + * @param flag Target flag string to be checked. + */ + public static boolean hasFlag(@NonNull final InterfaceConfigurationParcel config, + @NonNull final String flag) { + validateFlag(flag); + final Set flagList = new HashSet(Arrays.asList(config.flags)); + return flagList.contains(flag); + } + @VisibleForTesting protected static String[] removeAndAddFlags(@NonNull String[] flags, @NonNull String remove, @NonNull String add) { diff --git a/staticlibs/client-libs/tests/unit/src/com/android/net/module/util/NetdUtilsTest.java b/staticlibs/client-libs/tests/unit/src/com/android/net/module/util/NetdUtilsTest.java index dedda7ecfc..506967223d 100644 --- a/staticlibs/client-libs/tests/unit/src/com/android/net/module/util/NetdUtilsTest.java +++ b/staticlibs/client-libs/tests/unit/src/com/android/net/module/util/NetdUtilsTest.java @@ -22,6 +22,8 @@ import static android.system.OsConstants.EBUSY; import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -48,6 +50,7 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -218,4 +221,56 @@ public class NetdUtilsTest { // Test throwing RemoteException after 3 tries. runTetherInterfaceWithRemoteException(3); } + + @Test + public void testNetdUtilsHasFlag() throws Exception { + final String[] flags = new String[] {"up", "broadcast", "running", "multicast"}; + setupFlagsForInterfaceConfiguration(flags); + + // Set interface up. + NetdUtils.setInterfaceUp(mNetd, IFACE); + final ArgumentCaptor arg = + ArgumentCaptor.forClass(InterfaceConfigurationParcel.class); + verify(mNetd, times(1)).interfaceSetCfg(arg.capture()); + + final InterfaceConfigurationParcel p = arg.getValue(); + assertTrue(NetdUtils.hasFlag(p, "up")); + assertTrue(NetdUtils.hasFlag(p, "running")); + assertTrue(NetdUtils.hasFlag(p, "broadcast")); + assertTrue(NetdUtils.hasFlag(p, "multicast")); + assertFalse(NetdUtils.hasFlag(p, "down")); + } + + @Test + public void testNetdUtilsHasFlag_flagContainsSpace() throws Exception { + final String[] flags = new String[] {"up", "broadcast", "running", "multicast"}; + setupFlagsForInterfaceConfiguration(flags); + + // Set interface up. + NetdUtils.setInterfaceUp(mNetd, IFACE); + final ArgumentCaptor arg = + ArgumentCaptor.forClass(InterfaceConfigurationParcel.class); + verify(mNetd, times(1)).interfaceSetCfg(arg.capture()); + + final InterfaceConfigurationParcel p = arg.getValue(); + assertThrows(IllegalArgumentException.class, () -> NetdUtils.hasFlag(p, "up ")); + } + + @Test + public void testNetdUtilsHasFlag_UppercaseString() throws Exception { + final String[] flags = new String[] {"up", "broadcast", "running", "multicast"}; + setupFlagsForInterfaceConfiguration(flags); + + // Set interface up. + NetdUtils.setInterfaceUp(mNetd, IFACE); + final ArgumentCaptor arg = + ArgumentCaptor.forClass(InterfaceConfigurationParcel.class); + verify(mNetd, times(1)).interfaceSetCfg(arg.capture()); + + final InterfaceConfigurationParcel p = arg.getValue(); + assertFalse(NetdUtils.hasFlag(p, "UP")); + assertFalse(NetdUtils.hasFlag(p, "BROADCAST")); + assertFalse(NetdUtils.hasFlag(p, "RUNNING")); + assertFalse(NetdUtils.hasFlag(p, "MULTICAST")); + } } From c5f0e2c80ab17a5dd834d0f9d3bbaa32e60c3e24 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 27 Dec 2021 08:43:40 +0000 Subject: [PATCH 328/777] [MS19.2] Add constrain and total into utils Test: atest FrameworksNetTests NetworkStaticLibTests Bug: 204830222 Change-Id: Ib98a5d3acdec2988cebd5d184982e8b968b67b17 --- .../net/module/util/CollectionUtils.java | 13 ++++++++++ .../net/module/util/NetworkStatsUtils.java | 16 +++++++++++++ .../net/module/util/CollectionUtilsTest.kt | 9 +++++++ .../net/module/util/NetworkStatsUtilsTest.kt | 24 +++++++++++++++---- 4 files changed, 58 insertions(+), 4 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index 6e1af557f1..312ca4839e 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -180,4 +180,17 @@ public final class CollectionUtils { } return matches; } + + /** + * Return sum of the given long array. + */ + public static long total(@Nullable long[] array) { + long total = 0; + if (array != null) { + for (long value : array) { + total += value; + } + } + return total; + } } diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java index 7ea40a145d..d4ad1f23fe 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java @@ -66,4 +66,20 @@ public class NetworkStatsUtils { * @hide */ public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1; + + /** + * Return the constrained value by given the lower and upper bounds. + */ + public static int constrain(int amount, int low, int high) { + if (low > high) throw new IllegalArgumentException("low(" + low + ") > high(" + high + ")"); + return amount < low ? low : (amount > high ? high : amount); + } + + /** + * Return the constrained value by given the lower and upper bounds. + */ + public static long constrain(long amount, long low, long high) { + if (low > high) throw new IllegalArgumentException("low(" + low + ") > high(" + high + ")"); + return amount < low ? low : (amount > high ? high : amount); + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt index 96648a59c0..911483a821 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt @@ -77,4 +77,13 @@ class CollectionUtilsTest { assertFalse(CollectionUtils.contains(arrayOf("A", "B", "C"), "D")) assertFalse(CollectionUtils.contains(null, "A")) } + + @Test + fun testTotal() { + assertEquals(10, CollectionUtils.total(longArrayOf(3, 6, 1))) + assertEquals(10, CollectionUtils.total(longArrayOf(6, 1, 3))) + assertEquals(10, CollectionUtils.total(longArrayOf(1, 3, 6))) + assertEquals(3, CollectionUtils.total(longArrayOf(1, 1, 1))) + assertEquals(0, CollectionUtils.total(null)) + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkStatsUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkStatsUtilsTest.kt index 820eb9b5fd..ff839fe8fb 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkStatsUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkStatsUtilsTest.kt @@ -18,10 +18,10 @@ package com.android.net.module.util import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 -import com.android.testutils.assertThrows import org.junit.Test import org.junit.runner.RunWith import kotlin.test.assertEquals +import kotlin.test.assertFailsWith @RunWith(AndroidJUnit4::class) @SmallTest @@ -37,10 +37,10 @@ class NetworkStatsUtilsTest { assertEquals(0 * 0 / 1, NetworkStatsUtils.multiplySafeByRational(0, 0, 1)) assertEquals(0, NetworkStatsUtils.multiplySafeByRational(0, Long.MAX_VALUE, Long.MAX_VALUE)) assertEquals(0, NetworkStatsUtils.multiplySafeByRational(Long.MAX_VALUE, 0, Long.MAX_VALUE)) - assertThrows(ArithmeticException::class.java) { + assertFailsWith { NetworkStatsUtils.multiplySafeByRational(7, 3, 0) } - assertThrows(ArithmeticException::class.java) { + assertFailsWith { NetworkStatsUtils.multiplySafeByRational(0, 0, 0) } @@ -51,8 +51,24 @@ class NetworkStatsUtilsTest { Long.MAX_VALUE, 721, Long.MAX_VALUE)) assertEquals(Long.MAX_VALUE, NetworkStatsUtils.multiplySafeByRational( Long.MAX_VALUE, Long.MAX_VALUE, Long.MAX_VALUE)) - assertThrows(ArithmeticException::class.java) { + assertFailsWith { NetworkStatsUtils.multiplySafeByRational(Long.MAX_VALUE, Long.MAX_VALUE, 0) } } + + @Test + fun testConstrain() { + assertFailsWith { + NetworkStatsUtils.constrain(5, 6, 3) // low > high + } + assertEquals(3, NetworkStatsUtils.constrain(5, 1, 3)) + assertEquals(3, NetworkStatsUtils.constrain(3, 1, 3)) + assertEquals(2, NetworkStatsUtils.constrain(2, 1, 3)) + assertEquals(1, NetworkStatsUtils.constrain(1, 1, 3)) + assertEquals(1, NetworkStatsUtils.constrain(0, 1, 3)) + + assertEquals(11, NetworkStatsUtils.constrain(15, 11, 11)) + assertEquals(11, NetworkStatsUtils.constrain(11, 11, 11)) + assertEquals(11, NetworkStatsUtils.constrain(1, 11, 11)) + } } \ No newline at end of file From aa4d8483de13a6586e84c9a16904d8edfcb1fca5 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Thu, 16 Dec 2021 17:29:01 +0800 Subject: [PATCH 329/777] Add apex_available and min_sdk_version to libip_checksum Prepare to package libclat library and clatd binary into tethering apex. This library is required. Bug: 212345928 Test: build Change-Id: I768c6358d9f4f15b37f73b3cfe2ff54a095a1bca --- staticlibs/native/ip_checksum/Android.bp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/staticlibs/native/ip_checksum/Android.bp b/staticlibs/native/ip_checksum/Android.bp index d7e195d376..9878d73771 100644 --- a/staticlibs/native/ip_checksum/Android.bp +++ b/staticlibs/native/ip_checksum/Android.bp @@ -37,4 +37,10 @@ cc_library_static { // // TODO: delete libnetutils from the VNDK in T, and remove this. vendor_available: true, + + min_sdk_version: "30", + apex_available: [ + "com.android.tethering", + "//apex_available:platform", + ], } From 15d8ebee4159b0eb867b1f296ec789484da0c26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 23 Dec 2021 22:41:21 -0800 Subject: [PATCH 330/777] bpf_connectivity_headers -> bpf_headers -> bpf_syscall_wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Idf158fa33670522b43e34c67a77087648b8b97a4 --- staticlibs/native/bpf_headers/Android.bp | 6 +++++- staticlibs/native/bpf_syscall_wrappers/Android.bp | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/staticlibs/native/bpf_headers/Android.bp b/staticlibs/native/bpf_headers/Android.bp index 4ec4d581e9..06ba1b05aa 100644 --- a/staticlibs/native/bpf_headers/Android.bp +++ b/staticlibs/native/bpf_headers/Android.bp @@ -18,14 +18,17 @@ package { cc_library_headers { name: "bpf_headers", - vendor_available: true, + vendor_available: false, host_supported: true, native_bridge_supported: true, + header_libs: ["bpf_syscall_wrappers"], + export_header_lib_headers: ["bpf_syscall_wrappers"], export_include_dirs: ["include"], cflags: [ "-Wall", "-Werror", ], + sdk_version: "30", min_sdk_version: "30", apex_available: [ "//apex_available:platform", @@ -40,6 +43,7 @@ cc_library_headers { "//frameworks/native/services/gpuservice/gpumem", "//frameworks/native/services/gpuservice/tests/unittests", "//frameworks/native/services/gpuservice/tracing", + "//packages/modules/Connectivity/bpf_progs", "//packages/modules/Connectivity/netd", "//packages/modules/Connectivity/tests/unit/jni", "//packages/modules/DnsResolver/tests", diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index 037e10d8d8..1a1b53c6eb 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -19,7 +19,7 @@ package { cc_library_headers { name: "bpf_syscall_wrappers", vendor_available: false, - host_supported: false, + host_supported: true, native_bridge_supported: true, export_include_dirs: ["include"], cflags: [ @@ -34,6 +34,7 @@ cc_library_headers { "com.android.tethering", ], visibility: [ + "//frameworks/libs/net/common/native/bpf_headers", "//frameworks/libs/net/common/native/bpfmapjni", "//packages/modules/Connectivity/netd", "//packages/modules/Connectivity/service", From 0042853ccff5af023afb0c9e808f014d7f178305 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 30 Dec 2021 07:03:24 +0000 Subject: [PATCH 331/777] [MS28.2] Add checkDumpPermission Test: atest FrameworksNetTests NetworkStaticLibTests Bug: 204830222 Change-Id: I105c45d89628b47a989e2113c26e1ea3351c559a --- .../net/module/util/PermissionUtils.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java index 10eda57632..3ab207062c 100644 --- a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java @@ -22,7 +22,9 @@ import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import android.annotation.NonNull; import android.content.Context; +import android.os.Binder; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; @@ -80,4 +82,19 @@ public final class PermissionUtils { permissions.add(PERMISSION_MAINLINE_NETWORK_STACK); enforceAnyPermissionOf(context, permissions.toArray(new String[0])); } + + /** + * Return true if the context has DUMP permission. + */ + public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) { + if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump " + tag + " from from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + + " due to missing android.permission.DUMP permission"); + return false; + } else { + return true; + } + } } From 4e2be816f6a6fc9210d925c92fe39d75d3f0b87b Mon Sep 17 00:00:00 2001 From: James Mattis Date: Sun, 26 Dec 2021 12:45:18 -0800 Subject: [PATCH 332/777] PermissionUtils update to validate system feature Update to PermissionUtils adding method for validating availability of a system feature. Bug: 210485380 Test: atest NetworkStaticLibTests: com.android.net.moduletests.util.PermissionUtilsTest Change-Id: Ic994af205da2ecf12ce7df4608d6c0ae29382ba7 --- .../net/module/util/PermissionUtils.java | 21 +++++++++++ .../net/module/util/PermissionUtilsTest.kt | 36 ++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java index 3ab207062c..606c811c68 100644 --- a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java @@ -21,6 +21,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.os.Binder; @@ -97,4 +98,24 @@ public final class PermissionUtils { return true; } } + + /** + * Enforce that a given feature is available and if not, throw an + * {@link UnsupportedOperationException}. + * + * @param context {@link android.content.Context} for the process. + * @param feature the feature name to enforce. + * @param errorMessage an optional error message to include. + */ + public static void enforceSystemFeature(final @NonNull Context context, + final @NonNull String feature, final @Nullable String errorMessage) { + final boolean hasSystemFeature = + context.getPackageManager().hasSystemFeature(feature); + if (!hasSystemFeature) { + if (null == errorMessage) { + throw new UnsupportedOperationException(); + } + throw new UnsupportedOperationException(errorMessage); + } + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt index 6da5e7d018..1b6cbcb0dc 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt @@ -18,22 +18,28 @@ package com.android.net.module.util import android.Manifest.permission.NETWORK_STACK import android.content.Context +import android.content.pm.PackageManager import android.content.pm.PackageManager.PERMISSION_DENIED import android.content.pm.PackageManager.PERMISSION_GRANTED import android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import com.android.net.module.util.PermissionUtils.checkAnyPermissionOf +import com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf import com.android.net.module.util.PermissionUtils.enforceNetworkStackPermission import com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr -import com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf +import com.android.net.module.util.PermissionUtils.enforceSystemFeature +import org.junit.Assert import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers import org.mockito.ArgumentMatchers.any import org.mockito.Mockito.doReturn import org.mockito.Mockito.mock +import kotlin.test.assertEquals import kotlin.test.assertFailsWith /** Tests for PermissionUtils */ @@ -43,6 +49,12 @@ class PermissionUtilsTest { private val TEST_PERMISSION1 = "android.permission.TEST_PERMISSION1" private val TEST_PERMISSION2 = "android.permission.TEST_PERMISSION2" private val context = mock(Context::class.java) + private val packageManager = mock(PackageManager::class.java) + + @Before + fun setup() { + doReturn(packageManager).`when`(context).packageManager + } @Test fun testEnforceAnyPermissionOf() { @@ -90,4 +102,26 @@ class PermissionUtilsTest { assertFailsWith("Expect fail but permission granted.") { enforceNetworkStackPermissionOr(context, TEST_PERMISSION2) } } + + private fun mockHasSystemFeature(featureName: String, hasFeature: Boolean) { + doReturn(hasFeature).`when`(packageManager) + .hasSystemFeature(ArgumentMatchers.eq(featureName)) + } + + @Test + fun testEnforceSystemFeature() { + val systemFeature = "test.system.feature" + val exceptionMessage = "test exception message" + mockHasSystemFeature(featureName = systemFeature, hasFeature = false) + val e = assertFailsWith("Should fail without feature") { + enforceSystemFeature(context, systemFeature, exceptionMessage) } + assertEquals(exceptionMessage, e.message) + + mockHasSystemFeature(featureName = systemFeature, hasFeature = true) + try { + enforceSystemFeature(context, systemFeature, "") + } catch (e: UnsupportedOperationException) { + Assert.fail("Exception should have not been thrown with system feature enabled") + } + } } From 757159adca0931d6ba15af8a538d2069e8985642 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Tue, 28 Dec 2021 18:27:25 -0800 Subject: [PATCH 333/777] Moving reusable code for common net permissions. Moving reusable code into PermissionUtils for commonly used permission checks similar to what is already being done today for NETWORK_STACK. Should be a no-op. Bug: 210485380 Test: make, flash and boot Change-Id: I3af10cf7f22f8efaa79d3c5d93119acf3ad14bac --- .../net/module/util/PermissionUtils.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java index 606c811c68..0f3dc1562e 100644 --- a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java @@ -16,6 +16,8 @@ package com.android.net.module.util; +import static android.Manifest.permission.ACCESS_NETWORK_STATE; +import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; import static android.Manifest.permission.NETWORK_STACK; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; @@ -84,6 +86,30 @@ public final class PermissionUtils { enforceAnyPermissionOf(context, permissions.toArray(new String[0])); } + /** + * If the CONNECTIVITY_USE_RESTRICTED_NETWORKS is not allowed for a particular process, throw a + * {@link SecurityException}. + * + * @param context {@link android.content.Context} for the process. + * @param message A message to include in the exception if it is thrown. + */ + public static void enforceRestrictedNetworkPermission( + final @NonNull Context context, final @Nullable String message) { + context.enforceCallingOrSelfPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, message); + } + + /** + * If the ACCESS_NETWORK_STATE is not allowed for a particular process, throw a + * {@link SecurityException}. + * + * @param context {@link android.content.Context} for the process. + * @param message A message to include in the exception if it is thrown. + */ + public static void enforceAccessNetworkStatePermission( + final @NonNull Context context, final @Nullable String message) { + context.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, message); + } + /** * Return true if the context has DUMP permission. */ From 8a0d90cf2b28cbf66a622c698c6623f548685c9e Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 5 Jan 2022 08:14:06 +0000 Subject: [PATCH 334/777] [MS40.2] Remove Clock dependencies from NetworkStatsService This includes: 1. Re-implement the BestClock in the static library. 2. Expose SystemClock#currentNetworkTimeClock as public Api Test: TH Bug: 204830222 Change-Id: I518e2f14250b100f677adbe5a17bac4048c8e65b --- .../android/net/module/util/BestClock.java | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 staticlibs/framework/com/android/net/module/util/BestClock.java diff --git a/staticlibs/framework/com/android/net/module/util/BestClock.java b/staticlibs/framework/com/android/net/module/util/BestClock.java new file mode 100644 index 0000000000..35391add01 --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/BestClock.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2021 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 com.android.net.module.util; + +import android.util.Log; + +import java.time.Clock; +import java.time.DateTimeException; +import java.time.Instant; +import java.time.ZoneId; +import java.util.Arrays; + +/** + * Single {@link Clock} that will return the best available time from a set of + * prioritized {@link Clock} instances. + *

+ * For example, when {@link SystemClock#currentNetworkTimeClock()} isn't able to + * provide the time, this class could use {@link Clock#systemUTC()} instead. + * + * Note that this is re-implemented based on {@code android.os.BestClock} to be used inside + * the mainline module. And the class does NOT support serialization. + * + * @hide + */ +final public class BestClock extends Clock { + private static final String TAG = "BestClock"; + private final ZoneId mZone; + private final Clock[] mClocks; + + public BestClock(ZoneId zone, Clock... clocks) { + super(); + this.mZone = zone; + this.mClocks = clocks; + } + + @Override + public long millis() { + for (Clock clock : mClocks) { + try { + return clock.millis(); + } catch (DateTimeException e) { + // Ignore and attempt the next clock + Log.w(TAG, e.toString()); + } + } + throw new DateTimeException( + "No clocks in " + Arrays.toString(mClocks) + " were able to provide time"); + } + + @Override + public ZoneId getZone() { + return mZone; + } + + @Override + public Clock withZone(ZoneId zone) { + return new BestClock(zone, mClocks); + } + + @Override + public Instant instant() { + return Instant.ofEpochMilli(millis()); + } +} From b91c5a3a9cb6c2fc595833a3253f4789b1ea1259 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 7 Jan 2022 20:13:57 +0900 Subject: [PATCH 335/777] Fix blocked status error message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit assertEquals syntax is (expected, actual) and not the other way around Error message before : java.lang.AssertionError: Unexpected blocked status 32 expected:<32> but was:<0> Error message after : java.lang.AssertionError: Unexpected blocked status 32 expected:<0> but was:<32> Test: FrameworksNetTests Change-Id: I27f912db9a83fe418b659553829580a2802c20db --- .../com/android/testutils/TestableNetworkCallback.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index 7d851f114a..c2b5a5c897 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -330,13 +330,13 @@ open class TestableNetworkCallback private constructor( fun expectBlockedStatusCallback(blocked: Boolean, net: Network, tmt: Long = defaultTimeoutMs) { expectCallback(net, tmt).also { - assertEquals(it.blocked, blocked, "Unexpected blocked status ${it.blocked}") + assertEquals(blocked, it.blocked, "Unexpected blocked status ${it.blocked}") } } fun expectBlockedStatusCallback(blocked: Int, net: Network, tmt: Long = defaultTimeoutMs) { expectCallback(net, tmt).also { - assertEquals(it.blocked, blocked, "Unexpected blocked status ${it.blocked}") + assertEquals(blocked, it.blocked, "Unexpected blocked status ${it.blocked}") } } From 18862e57c84bc2a06e6cbc48ae5c58776bbe3fad Mon Sep 17 00:00:00 2001 From: lifr Date: Wed, 5 Jan 2022 01:59:13 +0800 Subject: [PATCH 336/777] [DU01]Remove INetworkManagementService from NetworkStatsService NetworkStatsService is using INetworkManagementService APIs, which cannot be accessed after moving into the mainline module. So, replace and remove those hidden API usages. The commit adds the public NetworkStatsUtils.LIMIT_GLOBAL_ALERT to Replace the usage of NetworkManagementService.LIMIT_GLOBAL_ALERT in NetworkStatsService. Bug: 209738761 Test: atest NetworkStatsServiceTest Change-Id: Ie4d4f9f0931958262367febecb4ca1a7824bba38 --- .../com/android/net/module/util/NetworkStatsUtils.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java index d4ad1f23fe..28ff77052c 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java @@ -67,6 +67,12 @@ public class NetworkStatsUtils { */ public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1; + /** + * Name representing {@link #bandwidthSetGlobalAlert(long)} limit when delivered to + * {@link AlertObserver#onQuotaLimitReached(String, String)}. + */ + public static final String LIMIT_GLOBAL_ALERT = "globalAlert"; + /** * Return the constrained value by given the lower and upper bounds. */ From 11ded0617338e51c348c282495d0e533a09ca418 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 22 Dec 2021 20:17:41 +0900 Subject: [PATCH 337/777] Fix int overflow in shift Thankfully this is not actually a security vulnerability, because the sign bit just gets set, and the conversion to long performs sign extension. Still, it would break when adding one with 32. To avoid repeats of this same mistake, convert the creation of masks to using a function in a way that makes it impossible. Test: new test for this in NetworkCapabilitiesUtilsTest Change-Id: Iadbbca6b09b02d98e45a43984f7749e1a795ce02 --- .../module/util/NetworkCapabilitiesUtils.java | 67 ++++++++++++------- .../util/NetworkCapabilitiesUtilsTest.kt | 16 +++++ 2 files changed, 60 insertions(+), 23 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index d6222a7fc1..71a0c96611 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -27,6 +27,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_MCX; import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_MMTEL; import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE; import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS; @@ -84,40 +85,41 @@ public final class NetworkCapabilitiesUtils { * and {@code FORCE_RESTRICTED_CAPABILITIES}. */ @VisibleForTesting - static final long RESTRICTED_CAPABILITIES = - (1 << NET_CAPABILITY_BIP) - | (1 << NET_CAPABILITY_CBS) - | (1 << NET_CAPABILITY_DUN) - | (1 << NET_CAPABILITY_EIMS) - | (1 << NET_CAPABILITY_ENTERPRISE) - | (1 << NET_CAPABILITY_FOTA) - | (1 << NET_CAPABILITY_IA) - | (1 << NET_CAPABILITY_IMS) - | (1 << NET_CAPABILITY_MCX) - | (1 << NET_CAPABILITY_RCS) - | (1 << NET_CAPABILITY_VEHICLE_INTERNAL) - | (1 << NET_CAPABILITY_VSIM) - | (1 << NET_CAPABILITY_XCAP); + static final long RESTRICTED_CAPABILITIES = packBitList( + NET_CAPABILITY_BIP, + NET_CAPABILITY_CBS, + NET_CAPABILITY_DUN, + NET_CAPABILITY_EIMS, + NET_CAPABILITY_ENTERPRISE, + NET_CAPABILITY_FOTA, + NET_CAPABILITY_IA, + NET_CAPABILITY_IMS, + NET_CAPABILITY_MCX, + NET_CAPABILITY_RCS, + NET_CAPABILITY_VEHICLE_INTERNAL, + NET_CAPABILITY_VSIM, + NET_CAPABILITY_XCAP, + NET_CAPABILITY_MMTEL); /** * Capabilities that force network to be restricted. * See {@code NetworkCapabilities#maybeMarkCapabilitiesRestricted}. */ - private static final long FORCE_RESTRICTED_CAPABILITIES = - (1 << NET_CAPABILITY_ENTERPRISE) - | (1 << NET_CAPABILITY_OEM_PAID) - | (1 << NET_CAPABILITY_OEM_PRIVATE); + private static final long FORCE_RESTRICTED_CAPABILITIES = packBitList( + NET_CAPABILITY_ENTERPRISE, + NET_CAPABILITY_OEM_PAID, + NET_CAPABILITY_OEM_PRIVATE); /** * Capabilities that suggest that a network is unrestricted. * See {@code NetworkCapabilities#maybeMarkCapabilitiesRestricted}. */ @VisibleForTesting - static final long UNRESTRICTED_CAPABILITIES = - (1 << NET_CAPABILITY_INTERNET) - | (1 << NET_CAPABILITY_MMS) - | (1 << NET_CAPABILITY_SUPL) - | (1 << NET_CAPABILITY_WIFI_P2P); + static final long UNRESTRICTED_CAPABILITIES = packBitList( + NET_CAPABILITY_INTERNET, + NET_CAPABILITY_MMS, + NET_CAPABILITY_SUPL, + NET_CAPABILITY_WIFI_P2P); /** * Get a transport that can be used to classify a network when displaying its info to users. @@ -195,8 +197,27 @@ public final class NetworkCapabilitiesUtils { return result; } + /** + * Packs a list of ints in the same way as packBits() + * + * Each passed int is the rank of a bit that should be set in the returned long. + * Example : passing (1,3) will return in 0b00001010 and passing (5,6,0) will return 0b01100001 + * + * @param bits bits to pack + * @return a long with the specified bits set. + */ + public static long packBitList(int... bits) { + return packBits(bits); + } + /** * Packs array of bits into a long value. + * + * Each passed int is the rank of a bit that should be set in the returned long. + * Example : passing [1,3] will return in 0b00001010 and passing [5,6,0] will return 0b01100001 + * + * @param bits bits to pack + * @return a long with the specified bits set. */ public static long packBits(int[] bits) { long packed = 0; diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt index f78c74e607..256ea1e8a6 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt @@ -18,6 +18,7 @@ package com.android.net.module.util import android.annotation.TargetApi import android.net.NetworkCapabilities +import android.net.NetworkCapabilities.NET_CAPABILITY_BIP import android.net.NetworkCapabilities.NET_CAPABILITY_CBS import android.net.NetworkCapabilities.NET_CAPABILITY_EIMS import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET @@ -33,6 +34,7 @@ import android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE import android.os.Build import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 +import com.android.modules.utils.build.SdkLevel import com.android.net.module.util.NetworkCapabilitiesUtils.RESTRICTED_CAPABILITIES import com.android.net.module.util.NetworkCapabilitiesUtils.UNRESTRICTED_CAPABILITIES import com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport @@ -110,6 +112,12 @@ class NetworkCapabilitiesUtilsTest { // as restricted when there is no any unrestricted capability. nc.removeCapability(NET_CAPABILITY_INTERNET) assertTrue(NetworkCapabilitiesUtils.inferRestrictedCapability(nc)) + if (!SdkLevel.isAtLeastS()) return + // BIP deserves its specific test because it's the first capability over 30, meaning the + // shift will overflow + nc.removeCapability(NET_CAPABILITY_CBS) + nc.addCapability(NET_CAPABILITY_BIP) + assertTrue(NetworkCapabilitiesUtils.inferRestrictedCapability(nc)) } @Test @@ -122,9 +130,17 @@ class NetworkCapabilitiesUtilsTest { assertEquals((1 shl NET_CAPABILITY_CBS).toLong() and RESTRICTED_CAPABILITIES, (1 shl NET_CAPABILITY_CBS).toLong()) + // verify BIP is also restricted + // BIP is not available in R and before, but the BIP constant is inlined so + // this test can still run on R. + assertEquals((1L shl NET_CAPABILITY_BIP) and RESTRICTED_CAPABILITIES, + (1L shl NET_CAPABILITY_BIP)) + // verify default is not restricted assertEquals((1 shl NET_CAPABILITY_INTERNET).toLong() and RESTRICTED_CAPABILITIES, 0) + assertTrue(RESTRICTED_CAPABILITIES > 0) + // just to see assertEquals(RESTRICTED_CAPABILITIES and UNRESTRICTED_CAPABILITIES, 0) } From 3faa0a0911dedf0c0a9bd85373ed466e7462d0f9 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Tue, 11 Jan 2022 21:36:45 +0800 Subject: [PATCH 338/777] Add excludeLocalRoutes in NativeNetworkConfig Add a extra field in NativeNetworkConfig to allow CS to notify netd to exclude the local traffic from the VPN network. Also freeze netd_aidl_interface as v8 and update the corresponding configuration. diff -U10 -ru -N common/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkConfig.aidl common/netd/aidl_api/netd_aidl_interface/8/android/net/NativeNetworkConfig.aidl --- common/netd/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkConfig.aidl 2021-10-29 14:52:13.069757396 +0800 +++ common/netd/aidl_api/netd_aidl_interface/8/android/net/NativeNetworkConfig.aidl 2022-01-11 21:35:55.088966333 +0800 @@ -33,11 +33,12 @@ package android.net; /* @hide */ @JavaDerive(equals=true, toString=true) @JavaOnlyImmutable parcelable NativeNetworkConfig { int netId; android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL; int permission; boolean secure; android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM; + boolean excludeLocalRoutes = false; } diff -U10 -ru -N common/netd/aidl_api/netd_aidl_interface/7/.hash common/netd/aidl_api/netd_aidl_interface/8/.hash --- common/netd/aidl_api/netd_aidl_interface/7/.hash 2021-10-29 14:52:13.069757396 +0800 +++ common/netd/aidl_api/netd_aidl_interface/8/.hash 2022-01-11 21:35:55.084966375 +0800 @@ -1 +1 @@ -850353de5d19a0dd718f8fd20791f0532e6a34c7 +e8cf8586fc5da9063818d8775e9a21c4b0addb5b Bug: 184750836 Test: atest FrameworksNetTests Change-Id: Icadca719aaba678b06f617c581e3c80a22248f26 --- staticlibs/netd/Android.bp | 7 +- .../netd/aidl_api/netd_aidl_interface/8/.hash | 1 + .../8/android/net/INetd.aidl | 200 ++++++++++++++++++ .../net/INetdUnsolicitedEventListener.aidl | 48 +++++ .../net/InterfaceConfigurationParcel.aidl | 42 ++++ .../8/android/net/MarkMaskParcel.aidl | 39 ++++ .../8/android/net/NativeNetworkConfig.aidl | 44 ++++ .../8/android/net/NativeNetworkType.aidl | 39 ++++ .../8/android/net/NativeVpnType.aidl | 41 ++++ .../8/android/net/RouteInfoParcel.aidl | 40 ++++ .../8/android/net/TetherConfigParcel.aidl | 39 ++++ .../android/net/TetherOffloadRuleParcel.aidl | 44 ++++ .../8/android/net/TetherStatsParcel.aidl | 43 ++++ .../8/android/net/UidRangeParcel.aidl | 40 ++++ .../net/netd/aidl/NativeUidRangeConfig.aidl | 41 ++++ .../android/net/NativeNetworkConfig.aidl | 1 + .../android/net/NativeNetworkConfig.aidl | 5 + 17 files changed, 711 insertions(+), 3 deletions(-) create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/8/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/NativeNetworkConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/NativeNetworkType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/NativeVpnType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/netd/aidl/NativeUidRangeConfig.aidl diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index c3f93747a2..6a12d64ed1 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -21,7 +21,7 @@ java_library { sdk_version: "system_current", min_sdk_version: "29", static_libs: [ - "netd_aidl_interface-V7-java", + "netd_aidl_interface-V8-java", ], apex_available: [ "//apex_available:platform", // used from services.net @@ -44,7 +44,7 @@ cc_library_static { cc_library_static { name: "netd_aidl_interface-lateststable-ndk", whole_static_libs: [ - "netd_aidl_interface-V7-ndk", + "netd_aidl_interface-V8-ndk", ], apex_available: [ "com.android.resolv", @@ -55,7 +55,7 @@ cc_library_static { cc_library_static { name: "netd_aidl_interface-lateststable-cpp", whole_static_libs: [ - "netd_aidl_interface-V7-cpp", + "netd_aidl_interface-V8-cpp", ], } @@ -111,6 +111,7 @@ aidl_interface { "5", "6", "7", + "8", ], } diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/8/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/8/.hash new file mode 100644 index 0000000000..093381616e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/8/.hash @@ -0,0 +1 @@ +e8cf8586fc5da9063818d8775e9a21c4b0addb5b diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/INetd.aidl new file mode 100644 index 0000000000..ec03d86b6c --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/INetd.aidl @@ -0,0 +1,200 @@ +/** + * Copyright (c) 2016, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreatePhysical(int netId, int permission); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + void networkCreate(in android.net.NativeNetworkConfig config); + void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const int DUMMY_NET_ID = 51; + const int UNREACHABLE_NET_ID = 52; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + /** + * @deprecated use FIREWALL_ALLOWLIST. + */ + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_ALLOWLIST = 0; + /** + * @deprecated use FIREWALL_DENYLIST. + */ + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_DENYLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const int FIREWALL_CHAIN_RESTRICTED = 4; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..31775dfd11 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2018, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..1869d8d49e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..8ea20d118f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/MarkMaskParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/NativeNetworkConfig.aidl new file mode 100644 index 0000000000..77d814b825 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/NativeNetworkConfig.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeNetworkConfig { + int netId; + android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL; + int permission; + boolean secure; + android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM; + boolean excludeLocalRoutes = false; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/NativeNetworkType.aidl new file mode 100644 index 0000000000..06c8979d51 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/NativeNetworkType.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeNetworkType { + PHYSICAL = 0, + VIRTUAL = 1, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/NativeVpnType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/NativeVpnType.aidl new file mode 100644 index 0000000000..8a8be83958 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/NativeVpnType.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeVpnType { + SERVICE = 1, + PLATFORM = 2, + LEGACY = 3, + OEM = 4, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5ef95e67ca --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/RouteInfoParcel.aidl @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2020, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..7b39c22e4e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/TetherConfigParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..983e9860ea --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..5f1b722690 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/TetherStatsParcel.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..72e987a2af --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/UidRangeParcel.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/netd/aidl/NativeUidRangeConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/netd/aidl/NativeUidRangeConfig.aidl new file mode 100644 index 0000000000..9bb679f1c1 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/8/android/net/netd/aidl/NativeUidRangeConfig.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.netd.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeUidRangeConfig { + int netId; + android.net.UidRangeParcel[] uidRanges; + int subPriority; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl index 76562b294a..77d814b825 100644 --- a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl @@ -40,4 +40,5 @@ parcelable NativeNetworkConfig { int permission; boolean secure; android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM; + boolean excludeLocalRoutes = false; } diff --git a/staticlibs/netd/binder/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/binder/android/net/NativeNetworkConfig.aidl index 2c4f83a4cb..e654a1f4cf 100644 --- a/staticlibs/netd/binder/android/net/NativeNetworkConfig.aidl +++ b/staticlibs/netd/binder/android/net/NativeNetworkConfig.aidl @@ -49,4 +49,9 @@ parcelable NativeNetworkConfig { /** For virtual networks. The type of VPN to create. Ignored for all other network types. */ NativeVpnType vpnType = NativeVpnType.PLATFORM; + + /** + * For virtual networks. Whether local traffic is excluded from the VPN. + */ + boolean excludeLocalRoutes = false; } From a408d3cc06135b028b08d1f98609998ea7bca972 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 12 Jan 2022 21:33:49 +0100 Subject: [PATCH 339/777] Move BpfUtils -- make BpfSyscallWrappers visible to libtcutils Bug: 202086915 Bug: 157552970 Test: atest TetheringTests Change-Id: I698f492e30e4108037d1b72c5bebc7d6ab85e410 --- staticlibs/native/bpf_syscall_wrappers/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index 1a1b53c6eb..088bcbbfbc 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -36,6 +36,7 @@ cc_library_headers { visibility: [ "//frameworks/libs/net/common/native/bpf_headers", "//frameworks/libs/net/common/native/bpfmapjni", + "//frameworks/libs/net/common/native/tcutils", "//packages/modules/Connectivity/netd", "//packages/modules/Connectivity/service", "//packages/modules/Connectivity/Tethering", From 776c40cf65d288a64f0d7dbaf79d1ba4f8db1c27 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 12 Jan 2022 21:05:26 +0100 Subject: [PATCH 340/777] Move BpfUtils -- add libtcutils This CL is copying the "generic" parts of BpfUtils to frameworks/libs/net/common. "Generic" meaning the parts that will be used by both TcUtils in frameworks/libs/net/common and netd. Bug: 202086915 Bug: 157552970 Test: atest TetheringTests Change-Id: I9e780fc22e30d046f44953a8cac7687cb6c721c7 --- staticlibs/native/tcutils/Android.bp | 43 ++ .../native/tcutils/include/tcutils/tcutils.h | 28 ++ staticlibs/native/tcutils/scopeguard.h | 74 ++++ staticlibs/native/tcutils/tcutils.cpp | 386 ++++++++++++++++++ 4 files changed, 531 insertions(+) create mode 100644 staticlibs/native/tcutils/Android.bp create mode 100644 staticlibs/native/tcutils/include/tcutils/tcutils.h create mode 100644 staticlibs/native/tcutils/scopeguard.h create mode 100644 staticlibs/native/tcutils/tcutils.cpp diff --git a/staticlibs/native/tcutils/Android.bp b/staticlibs/native/tcutils/Android.bp new file mode 100644 index 0000000000..01b24241f5 --- /dev/null +++ b/staticlibs/native/tcutils/Android.bp @@ -0,0 +1,43 @@ +// 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_library_static { + name: "libtcutils", + srcs: ["tcutils.cpp"], + export_include_dirs: ["include"], + header_libs: ["bpf_syscall_wrappers"], + shared_libs: [ + "liblog", + ], + stl: "libc++_static", + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + ], + sdk_version: "30", + min_sdk_version: "30", + apex_available: [ + "com.android.tethering", + "//apex_available:platform", + ], + visibility: [ + "//frameworks/libs/net/common/native/bpfmapjni", + "//system/netd/server", + ], +} diff --git a/staticlibs/native/tcutils/include/tcutils/tcutils.h b/staticlibs/native/tcutils/include/tcutils/tcutils.h new file mode 100644 index 0000000000..d1e1bb7639 --- /dev/null +++ b/staticlibs/native/tcutils/include/tcutils/tcutils.h @@ -0,0 +1,28 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace android { + +int isEthernet(const char *iface, bool &isEthernet); +int tcAddBpfFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto, + const char *bpfProgPath); +int tcDeleteFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto); + +} // namespace android diff --git a/staticlibs/native/tcutils/scopeguard.h b/staticlibs/native/tcutils/scopeguard.h new file mode 100644 index 0000000000..76bbb93a25 --- /dev/null +++ b/staticlibs/native/tcutils/scopeguard.h @@ -0,0 +1,74 @@ +/* + * 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. + */ + +// ----------------------------------------------------------------------------- +// TODO: figure out a way to use libbase_ndk. This is currently not working +// because of missing apex availability. For now, we can use a copy of +// ScopeGuard which is very lean compared to unique_fd. This code has been +// copied verbatim from: +// https://cs.android.com/android/platform/superproject/+/master:system/libbase/include/android-base/scopeguard.h + +#pragma once + +#include // for std::move, std::forward + +namespace android { +namespace base { + +// ScopeGuard ensures that the specified functor is executed no matter how the +// current scope exits. +template class ScopeGuard { +public: + ScopeGuard(F &&f) : f_(std::forward(f)), active_(true) {} + + ScopeGuard(ScopeGuard &&that) noexcept + : f_(std::move(that.f_)), active_(that.active_) { + that.active_ = false; + } + + template + ScopeGuard(ScopeGuard &&that) + : f_(std::move(that.f_)), active_(that.active_) { + that.active_ = false; + } + + ~ScopeGuard() { + if (active_) + f_(); + } + + ScopeGuard() = delete; + ScopeGuard(const ScopeGuard &) = delete; + void operator=(const ScopeGuard &) = delete; + void operator=(ScopeGuard &&that) = delete; + + void Disable() { active_ = false; } + + bool active() const { return active_; } + +private: + template friend class ScopeGuard; + + F f_; + bool active_; +}; + +template ScopeGuard make_scope_guard(F &&f) { + return ScopeGuard(std::forward(f)); +} + +} // namespace base +} // namespace android diff --git a/staticlibs/native/tcutils/tcutils.cpp b/staticlibs/native/tcutils/tcutils.cpp new file mode 100644 index 0000000000..ca1c63c4b7 --- /dev/null +++ b/staticlibs/native/tcutils/tcutils.cpp @@ -0,0 +1,386 @@ +/* + * 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. + */ + +#define LOG_TAG "TcUtils" + +#include "tcutils/tcutils.h" + +#include "scopeguard.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BPF_FD_JUST_USE_INT +#include +#undef BPF_FD_JUST_USE_INT + +// The maximum length of TCA_BPF_NAME. Sync from net/sched/cls_bpf.c. +#define CLS_BPF_NAME_LEN 256 + +// Classifier name. See cls_bpf_ops in net/sched/cls_bpf.c. +#define CLS_BPF_KIND_NAME "bpf" + +namespace android { +namespace { + +void logError(const char *fmt...) { + va_list args; + va_start(args, fmt); + __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, fmt, args); + va_end(args); +} + +const sockaddr_nl KERNEL_NLADDR = {AF_NETLINK, 0, 0, 0}; +const uint16_t NETLINK_REQUEST_FLAGS = NLM_F_REQUEST | NLM_F_ACK; + +int sendAndProcessNetlinkResponse(const void *req, int len) { + // TODO: use unique_fd instead of ScopeGuard + int fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); + if (fd == -1) { + int error = errno; + logError("socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE): %d", + error); + return -error; + } + auto scopeGuard = base::make_scope_guard([fd] { close(fd); }); + + static constexpr int on = 1; + if (setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &on, sizeof(on))) { + int error = errno; + logError("setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, 1): %d", error); + return -error; + } + + // this is needed to get valid strace netlink parsing, it allocates the pid + if (bind(fd, (const struct sockaddr *)&KERNEL_NLADDR, + sizeof(KERNEL_NLADDR))) { + int error = errno; + logError("bind(fd, {AF_NETLINK, 0, 0}: %d)", error); + return -error; + } + + // we do not want to receive messages from anyone besides the kernel + if (connect(fd, (const struct sockaddr *)&KERNEL_NLADDR, + sizeof(KERNEL_NLADDR))) { + int error = errno; + logError("connect(fd, {AF_NETLINK, 0, 0}): %d", error); + return -error; + } + + int rv = send(fd, req, len, 0); + + if (rv == -1) { + int error = errno; + logError("send(fd, req, len, 0) failed: %d", error); + return -error; + } + + if (rv != len) { + logError("send(fd, req, len = %d, 0) returned invalid message size %d", len, + rv); + return -EMSGSIZE; + } + + struct { + nlmsghdr h; + nlmsgerr e; + char buf[256]; + } resp = {}; + + rv = recv(fd, &resp, sizeof(resp), MSG_TRUNC); + + if (rv == -1) { + int error = errno; + logError("recv() failed: %d", error); + return -error; + } + + if (rv < (int)NLMSG_SPACE(sizeof(struct nlmsgerr))) { + logError("recv() returned short packet: %d", rv); + return -EBADMSG; + } + + if (resp.h.nlmsg_len != (unsigned)rv) { + logError("recv() returned invalid header length: %d != %d", + resp.h.nlmsg_len, rv); + return -EBADMSG; + } + + if (resp.h.nlmsg_type != NLMSG_ERROR) { + logError("recv() did not return NLMSG_ERROR message: %d", + resp.h.nlmsg_type); + return -ENOMSG; + } + + if (resp.e.error) { + logError("NLMSG_ERROR message return error: %d", resp.e.error); + } + return resp.e.error; // returns 0 on success +} + +int hardwareAddressType(const char *interface) { + int fd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (fd < 0) + return -errno; + auto scopeGuard = base::make_scope_guard([fd] { close(fd); }); + + struct ifreq ifr = {}; + // We use strncpy() instead of strlcpy() since kernel has to be able + // to handle non-zero terminated junk passed in by userspace anyway, + // and this way too long interface names (more than IFNAMSIZ-1 = 15 + // characters plus terminating NULL) will not get truncated to 15 + // characters and zero-terminated and thus potentially erroneously + // match a truncated interface if one were to exist. + strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFHWADDR, &ifr, sizeof(ifr))) { + return -errno; + } + return ifr.ifr_hwaddr.sa_family; +} + +// ----------------------------------------------------------------------------- +// TODO - just use BpfUtils.h once that is available in sc-mainline-prod and has +// kernelVersion() +// +// In the mean time copying verbatim from: +// system/bpf/libbpf_android/include/bpf/BpfUtils.h +// and +// system/bpf/libbpf_android/BpfUtils.cpp + +#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c)) + +unsigned kernelVersion() { + struct utsname buf; + int ret = uname(&buf); + if (ret) + return 0; + + unsigned kver_major; + unsigned kver_minor; + unsigned kver_sub; + char discard; + ret = sscanf(buf.release, "%u.%u.%u%c", &kver_major, &kver_minor, &kver_sub, + &discard); + // Check the device kernel version + if (ret < 3) + return 0; + + return KVER(kver_major, kver_minor, kver_sub); +} + +bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) { + return kernelVersion() >= KVER(major, minor, sub); +} +// ----------------------------------------------------------------------------- + +} // namespace + +int isEthernet(const char *iface, bool &isEthernet) { + int rv = hardwareAddressType(iface); + if (rv < 0) { + logError("Get hardware address type of interface %s failed: %s", iface, + strerror(-rv)); + return -rv; + } + + // Backwards compatibility with pre-GKI kernels that use various custom + // ARPHRD_* for their cellular interface + switch (rv) { + // ARPHRD_PUREIP on at least some Mediatek Android kernels + // example: wembley with 4.19 kernel + case 520: + // in Linux 4.14+ rmnet support was upstreamed and ARHRD_RAWIP became 519, + // but it is 530 on at least some Qualcomm Android 4.9 kernels with rmnet + // example: Pixel 3 family + case 530: + // >5.4 kernels are GKI2.0 and thus upstream compatible, however 5.10 + // shipped with Android S, so (for safety) let's limit ourselves to + // >5.10, ie. 5.11+ as a guarantee we're on Android T+ and thus no + // longer need this non-upstream compatibility logic + static bool is_pre_5_11_kernel = !isAtLeastKernelVersion(5, 11, 0); + if (is_pre_5_11_kernel) + return false; + } + + switch (rv) { + case ARPHRD_ETHER: + isEthernet = true; + return 0; + case ARPHRD_NONE: + case ARPHRD_PPP: + case ARPHRD_RAWIP: + isEthernet = false; + return 0; + default: + logError("Unknown hardware address type %d on interface %s", rv, iface); + return -ENOENT; + } +} + +// tc filter add dev .. in/egress prio 1 protocol ipv6/ip bpf object-pinned +// /sys/fs/bpf/... direct-action +int tcAddBpfFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto, + const char *bpfProgPath) { + const int bpfFd = bpf::retrieveProgram(bpfProgPath); + if (bpfFd == -1) { + logError("retrieveProgram failed: %d", errno); + return -errno; + } + auto scopeGuard = base::make_scope_guard([bpfFd] { close(bpfFd); }); + + struct { + nlmsghdr n; + tcmsg t; + struct { + nlattr attr; + // The maximum classifier name length is defined in + // tcf_proto_ops in include/net/sch_generic.h. + char str[NLMSG_ALIGN(sizeof(CLS_BPF_KIND_NAME))]; + } kind; + struct { + nlattr attr; + struct { + nlattr attr; + __u32 u32; + } fd; + struct { + nlattr attr; + char str[NLMSG_ALIGN(CLS_BPF_NAME_LEN)]; + } name; + struct { + nlattr attr; + __u32 u32; + } flags; + } options; + } req = { + .n = + { + .nlmsg_len = sizeof(req), + .nlmsg_type = RTM_NEWTFILTER, + .nlmsg_flags = NETLINK_REQUEST_FLAGS | NLM_F_EXCL | NLM_F_CREATE, + }, + .t = + { + .tcm_family = AF_UNSPEC, + .tcm_ifindex = ifIndex, + .tcm_handle = TC_H_UNSPEC, + .tcm_parent = TC_H_MAKE(TC_H_CLSACT, ingress ? TC_H_MIN_INGRESS + : TC_H_MIN_EGRESS), + .tcm_info = + static_cast<__u32>((static_cast(prio) << 16) | + htons(static_cast(proto))), + }, + .kind = + { + .attr = + { + .nla_len = sizeof(req.kind), + .nla_type = TCA_KIND, + }, + .str = CLS_BPF_KIND_NAME, + }, + .options = + { + .attr = + { + .nla_len = sizeof(req.options), + .nla_type = NLA_F_NESTED | TCA_OPTIONS, + }, + .fd = + { + .attr = + { + .nla_len = sizeof(req.options.fd), + .nla_type = TCA_BPF_FD, + }, + .u32 = static_cast<__u32>(bpfFd), + }, + .name = + { + .attr = + { + .nla_len = sizeof(req.options.name), + .nla_type = TCA_BPF_NAME, + }, + // Visible via 'tc filter show', but + // is overwritten by strncpy below + .str = "placeholder", + }, + .flags = + { + .attr = + { + .nla_len = sizeof(req.options.flags), + .nla_type = TCA_BPF_FLAGS, + }, + .u32 = TCA_BPF_FLAG_ACT_DIRECT, + }, + }, + }; + + snprintf(req.options.name.str, sizeof(req.options.name.str), "%s:[*fsobj]", + basename(bpfProgPath)); + + int error = sendAndProcessNetlinkResponse(&req, sizeof(req)); + return error; +} + +// tc filter del dev .. in/egress prio .. protocol .. +int tcDeleteFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto) { + const struct { + nlmsghdr n; + tcmsg t; + } req = { + .n = + { + .nlmsg_len = sizeof(req), + .nlmsg_type = RTM_DELTFILTER, + .nlmsg_flags = NETLINK_REQUEST_FLAGS, + }, + .t = + { + .tcm_family = AF_UNSPEC, + .tcm_ifindex = ifIndex, + .tcm_handle = TC_H_UNSPEC, + .tcm_parent = TC_H_MAKE(TC_H_CLSACT, ingress ? TC_H_MIN_INGRESS + : TC_H_MIN_EGRESS), + .tcm_info = + static_cast<__u32>((static_cast(prio) << 16) | + htons(static_cast(proto))), + }, + }; + + return sendAndProcessNetlinkResponse(&req, sizeof(req)); +} + +} // namespace android From 299a85e4f5d7b73aa07198f1691d7b788ae6a7fd Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Thu, 13 Jan 2022 22:23:01 +0100 Subject: [PATCH 341/777] Move BpfUtils -- make libtcutils visible to package/modules/Connectivity Bug: 202086915 Bug: 157552970 Test: builds Change-Id: Ie9b34bbe5263e34c592a73a2ca828d0f3f48e564 --- staticlibs/native/tcutils/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/native/tcutils/Android.bp b/staticlibs/native/tcutils/Android.bp index 01b24241f5..c26fca6663 100644 --- a/staticlibs/native/tcutils/Android.bp +++ b/staticlibs/native/tcutils/Android.bp @@ -38,6 +38,7 @@ cc_library_static { ], visibility: [ "//frameworks/libs/net/common/native/bpfmapjni", + "//packages/modules/Connectivity:__subpackages__", "//system/netd/server", ], } From f714f1b116824b3cc89e1645d6875745dfbe32fb Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 12 Jan 2022 21:06:50 +0100 Subject: [PATCH 342/777] Move BpfUtils -- add JNI wrapper for libtcutils This CL adds the copied JNI wrappers for tcutils. Bug: 202086915 Bug: 157552970 Test: atest TetheringTests Change-Id: Ib3f8b24a12a18f1ba64fd17304274c4dba37fc47 --- staticlibs/native/bpfmapjni/Android.bp | 8 +- .../com_android_net_module_util_TcUtils.cpp | 87 +++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp diff --git a/staticlibs/native/bpfmapjni/Android.bp b/staticlibs/native/bpfmapjni/Android.bp index b7af22d335..8d3c90b0a5 100644 --- a/staticlibs/native/bpfmapjni/Android.bp +++ b/staticlibs/native/bpfmapjni/Android.bp @@ -18,7 +18,10 @@ package { cc_library_static { name: "libnet_utils_device_common_bpfjni", - srcs: ["com_android_net_module_util_BpfMap.cpp"], + srcs: [ + "com_android_net_module_util_BpfMap.cpp", + "com_android_net_module_util_TcUtils.cpp", + ], header_libs: [ "bpf_syscall_wrappers", "jni_headers", @@ -27,6 +30,9 @@ cc_library_static { "liblog", "libnativehelper_compat_libc++", ], + static_libs: [ + "libtcutils", + ], cflags: [ "-Wall", "-Werror", diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp new file mode 100644 index 0000000000..e5a3668527 --- /dev/null +++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp @@ -0,0 +1,87 @@ +/* + * 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. + */ + +#include +#include +#include +#include + +namespace android { + +static void throwIOException(JNIEnv *env, const char *msg, int error) { + jniThrowExceptionFmt(env, "java/io/IOException", "%s: %s", msg, + strerror(error)); +} + +static jboolean com_android_net_module_util_TcUtils_isEthernet(JNIEnv *env, + jobject clazz, + jstring iface) { + ScopedUtfChars interface(env, iface); + bool result = false; + int error = isEthernet(interface.c_str(), result); + if (error) { + throwIOException( + env, "com_android_net_module_util_TcUtils_isEthernet error: ", error); + } + // result is not touched when error is returned; leave false. + return result; +} + +// tc filter add dev .. in/egress prio 1 protocol ipv6/ip bpf object-pinned +// /sys/fs/bpf/... direct-action +static void com_android_net_module_util_TcUtils_tcFilterAddDevBpf( + JNIEnv *env, jobject clazz, jint ifIndex, jboolean ingress, jshort prio, + jshort proto, jstring bpfProgPath) { + ScopedUtfChars pathname(env, bpfProgPath); + int error = tcAddBpfFilter(ifIndex, ingress, prio, proto, pathname.c_str()); + if (error) { + throwIOException( + env, + "com_android_net_module_util_TcUtils_tcFilterAddDevBpf error: ", error); + } +} + +// tc filter del dev .. in/egress prio .. protocol .. +static void com_android_net_module_util_TcUtils_tcFilterDelDev( + JNIEnv *env, jobject clazz, jint ifIndex, jboolean ingress, jshort prio, + jshort proto) { + int error = tcDeleteFilter(ifIndex, ingress, prio, proto); + if (error) { + throwIOException( + env, + "com_android_net_module_util_TcUtils_tcFilterDelDev error: ", error); + } +} + +/* + * JNI registration. + */ +static const JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + {"isEthernet", "(Ljava/lang/String;)Z", + (void *)com_android_net_module_util_TcUtils_isEthernet}, + {"tcFilterAddDevBpf", "(IZSSLjava/lang/String;)V", + (void *)com_android_net_module_util_TcUtils_tcFilterAddDevBpf}, + {"tcFilterDelDev", "(IZSS)V", + (void *)com_android_net_module_util_TcUtils_tcFilterDelDev}, +}; + +int register_com_android_net_module_util_TcUtils(JNIEnv *env, + char const *class_name) { + return jniRegisterNativeMethods(env, class_name, gMethods, NELEM(gMethods)); +} + +}; // namespace android From 29b0d95e1ecfbd2ac68c2e7eec91556ea98e4ff1 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 12 Jan 2022 21:42:24 +0100 Subject: [PATCH 343/777] Move BpfUtils -- add java class Adding a TcUtils java class. Bug: 202086915 Bug: 157552970 Test: atest TetheringTests Change-Id: Ifb97d822bd96de6ed1a3fed547234ef32d691ad8 --- staticlibs/Android.bp | 1 + .../com/android/net/module/util/TcUtils.java | 65 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/TcUtils.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 50cfb02b80..ea38eca46c 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -112,6 +112,7 @@ java_library { srcs: [ "device/com/android/net/module/util/BpfMap.java", "device/com/android/net/module/util/JniUtil.java", + "device/com/android/net/module/util/TcUtils.java", ], sdk_version: "system_current", min_sdk_version: "29", diff --git a/staticlibs/device/com/android/net/module/util/TcUtils.java b/staticlibs/device/com/android/net/module/util/TcUtils.java new file mode 100644 index 0000000000..14724d4628 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/TcUtils.java @@ -0,0 +1,65 @@ +/* + * 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 com.android.net.module.util; + +import java.io.IOException; + +/** + * Contains mostly tc-related functionality. + */ +public class TcUtils { + /** + * Checks if the network interface uses an ethernet L2 header. + * + * @param iface the network interface. + * @return true if the interface uses an ethernet L2 header. + * @throws IOException + */ + public static native boolean isEthernet(String iface) throws IOException; + + /** + * Attach a tc bpf filter. + * + * Equivalent to the following 'tc' command: + * tc filter add dev .. in/egress prio .. protocol ipv6/ip bpf object-pinned + * /sys/fs/bpf/... direct-action + * + * @param ifIndex the network interface index. + * @param ingress ingress or egress qdisc. + * @param prio + * @param proto + * @param bpfProgPath + * @throws IOException + */ + public static native void tcFilterAddDevBpf(int ifIndex, boolean ingress, short prio, + short proto, String bpfProgPath) throws IOException; + + /** + * Delete a tc filter. + * + * Equivalent to the following 'tc' command: + * tc filter del dev .. in/egress prio .. protocol .. + * + * @param ifIndex the network interface index. + * @param ingress ingress or egress qdisc. + * @param prio the filter preference. + * @param proto protocol. + * @throws IOException + */ + public static native void tcFilterDelDev(int ifIndex, boolean ingress, short prio, + short proto) throws IOException; +} From e7f26e2a4d8b55625afb2252edd72bcbda908e11 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 12 Jan 2022 22:13:12 +0100 Subject: [PATCH 344/777] Move BpfUtils -- move kernelVersion code to its own header Move kernelVersion and isAtLeastKernelVersion to a local kernelversion.h, since we cannot use bpf_headers' version of BpfUtils. Bug: 202086915 Bug: 157552970 Test: builds Change-Id: I83149b76cc5125991bdb52ce6160c497eb52b48b --- staticlibs/native/tcutils/kernelversion.h | 56 +++++++++++++++++++++++ staticlibs/native/tcutils/tcutils.cpp | 38 +-------------- 2 files changed, 57 insertions(+), 37 deletions(-) create mode 100644 staticlibs/native/tcutils/kernelversion.h diff --git a/staticlibs/native/tcutils/kernelversion.h b/staticlibs/native/tcutils/kernelversion.h new file mode 100644 index 0000000000..59b9e0540b --- /dev/null +++ b/staticlibs/native/tcutils/kernelversion.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +// ----------------------------------------------------------------------------- +// TODO - This should be replaced with BpfUtils in bpf_headers. +// Currently, bpf_headers contains a bunch requirements it doesn't actually provide, such as a +// non-ndk liblog version, and some version of libbase. libtcutils does not have access to either of +// these, so I think this will have to wait until we figure out a way around this. +// +// In the mean time copying verbatim from: +// frameworks/libs/net/common/native/bpf_headers + +#include +#include + +#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c)) + +namespace android { + +unsigned kernelVersion() { + struct utsname buf; + int ret = uname(&buf); + if (ret) + return 0; + + unsigned kver_major; + unsigned kver_minor; + unsigned kver_sub; + char discard; + ret = sscanf(buf.release, "%u.%u.%u%c", &kver_major, &kver_minor, &kver_sub, + &discard); + // Check the device kernel version + if (ret < 3) + return 0; + + return KVER(kver_major, kver_minor, kver_sub); +} + +bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) { + return kernelVersion() >= KVER(major, minor, sub); +} + +} diff --git a/staticlibs/native/tcutils/tcutils.cpp b/staticlibs/native/tcutils/tcutils.cpp index ca1c63c4b7..e30a5004c5 100644 --- a/staticlibs/native/tcutils/tcutils.cpp +++ b/staticlibs/native/tcutils/tcutils.cpp @@ -18,12 +18,12 @@ #include "tcutils/tcutils.h" +#include "kernelversion.h" #include "scopeguard.h" #include #include #include -#include #include #include #include @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -168,41 +167,6 @@ int hardwareAddressType(const char *interface) { return ifr.ifr_hwaddr.sa_family; } -// ----------------------------------------------------------------------------- -// TODO - just use BpfUtils.h once that is available in sc-mainline-prod and has -// kernelVersion() -// -// In the mean time copying verbatim from: -// system/bpf/libbpf_android/include/bpf/BpfUtils.h -// and -// system/bpf/libbpf_android/BpfUtils.cpp - -#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c)) - -unsigned kernelVersion() { - struct utsname buf; - int ret = uname(&buf); - if (ret) - return 0; - - unsigned kver_major; - unsigned kver_minor; - unsigned kver_sub; - char discard; - ret = sscanf(buf.release, "%u.%u.%u%c", &kver_major, &kver_minor, &kver_sub, - &discard); - // Check the device kernel version - if (ret < 3) - return 0; - - return KVER(kver_major, kver_minor, kver_sub); -} - -bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) { - return kernelVersion() >= KVER(major, minor, sub); -} -// ----------------------------------------------------------------------------- - } // namespace int isEthernet(const char *iface, bool &isEthernet) { From 67a69e73966e728a675fb1990e4090cee68edf0b Mon Sep 17 00:00:00 2001 From: Wayne Ma Date: Wed, 12 Jan 2022 11:44:27 +0800 Subject: [PATCH 345/777] [NETD-TC#12] Fix dependency on libtraffic_controller 1. Add visibility for libtraffic_control 2. Add com.android.tethering into apex_available statement Bug: 202086915 Test: m; flash; boot Change-Id: I817e22c24dd205f09ef62a2a7ff85b2a970f6d3a --- staticlibs/native/bpf_headers/Android.bp | 1 + staticlibs/native/bpf_syscall_wrappers/Android.bp | 1 + staticlibs/netd/Android.bp | 2 ++ 3 files changed, 4 insertions(+) diff --git a/staticlibs/native/bpf_headers/Android.bp b/staticlibs/native/bpf_headers/Android.bp index 06ba1b05aa..8426dce048 100644 --- a/staticlibs/native/bpf_headers/Android.bp +++ b/staticlibs/native/bpf_headers/Android.bp @@ -45,6 +45,7 @@ cc_library_headers { "//frameworks/native/services/gpuservice/tracing", "//packages/modules/Connectivity/bpf_progs", "//packages/modules/Connectivity/netd", + "//packages/modules/Connectivity/service/native", "//packages/modules/Connectivity/tests/unit/jni", "//packages/modules/DnsResolver/tests", "//system/bpf/bpfloader", diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index 1a1b53c6eb..6d6125698b 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -38,6 +38,7 @@ cc_library_headers { "//frameworks/libs/net/common/native/bpfmapjni", "//packages/modules/Connectivity/netd", "//packages/modules/Connectivity/service", + "//packages/modules/Connectivity/service/native", "//packages/modules/Connectivity/Tethering", "//packages/providers/MediaProvider/jni", "//system/bpf/libbpf_android", diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index c3f93747a2..a615ec17c3 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -48,6 +48,7 @@ cc_library_static { ], apex_available: [ "com.android.resolv", + "com.android.tethering", ], min_sdk_version: "29", } @@ -97,6 +98,7 @@ aidl_interface { ndk: { apex_available: [ "//apex_available:platform", + "com.android.tethering", ], // This is necessary for the DnsResovler tests to run in Android Q. // Soong would recognize this value and produce the Q compatible aidl library. From a973c0be7da832ec2d94461c0c9af35cecbd9f87 Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Sun, 9 Jan 2022 20:24:54 +0800 Subject: [PATCH 346/777] Add bpf_headers visibility for CtsNativeNetPlatformTestCases The CtsNativeNetPlatformTestCases uses BpfUtils.h in bpf_headers. Bug: 29761778 Bug: 202086915 Test: atest CtsNativeNetPlatformTestCases on signed user build Change-Id: Ibbb10392a283b88328ae17d9aa54322f50878e76 --- staticlibs/native/bpf_headers/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/native/bpf_headers/Android.bp b/staticlibs/native/bpf_headers/Android.bp index 8426dce048..af8ec73b49 100644 --- a/staticlibs/native/bpf_headers/Android.bp +++ b/staticlibs/native/bpf_headers/Android.bp @@ -37,6 +37,7 @@ cc_library_headers { ], visibility: [ "//bootable/libbootloader/vts", + "//cts/tests/tests/net/native", "//frameworks/base/services/core/jni", "//frameworks/native/libs/cputimeinstate", "//frameworks/native/services/gpuservice", From 37b2575137d731edd70abf2a68155e811b720abd Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Sun, 16 Jan 2022 13:35:29 +0800 Subject: [PATCH 347/777] make bpf_syscall_wrappers visible to libclat Needed because ClatdController and clatd binary are moved into apex. libclat is used for accessing BPF map. Bug: 212345928 Test: manual test 1. Connect to ipv6-only wifi. 2. Try IPv4 traffic. $ ping 8.8.8.8 Change-Id: I95a1c21927ba95f6094152e1013761d79c73e981 --- staticlibs/native/bpf_syscall_wrappers/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index c1bfd805ab..ad42622794 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -40,6 +40,7 @@ cc_library_headers { "//packages/modules/Connectivity/netd", "//packages/modules/Connectivity/service", "//packages/modules/Connectivity/service/native", + "//packages/modules/Connectivity/service/native/libs/libclat", "//packages/modules/Connectivity/Tethering", "//packages/providers/MediaProvider/jni", "//system/bpf/libbpf_android", From cd3f28f35d00866a4bb7dc2098c36c90a1e3f6a4 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Sun, 16 Jan 2022 13:38:28 +0800 Subject: [PATCH 348/777] make bpf_headers visible to libclat Needed because ClatdController and clatd binary are moved into apex. libclat is used for accessing BPF map. Bug: 212345928 Test: manual test 1. Connect to ipv6-only wifi. 2. Try IPv4 traffic. $ ping 8.8.8.8 Change-Id: If3fb00e12ef365ccf3ac782c4e6ecbfd01d2dd4c --- staticlibs/native/bpf_headers/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/native/bpf_headers/Android.bp b/staticlibs/native/bpf_headers/Android.bp index af8ec73b49..2fc056765b 100644 --- a/staticlibs/native/bpf_headers/Android.bp +++ b/staticlibs/native/bpf_headers/Android.bp @@ -47,6 +47,7 @@ cc_library_headers { "//packages/modules/Connectivity/bpf_progs", "//packages/modules/Connectivity/netd", "//packages/modules/Connectivity/service/native", + "//packages/modules/Connectivity/service/native/libs/libclat", "//packages/modules/Connectivity/tests/unit/jni", "//packages/modules/DnsResolver/tests", "//system/bpf/bpfloader", From 9f1fcb61d304f9b66a83b87472453d961a9f7a32 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 10 Jan 2022 19:52:09 +0800 Subject: [PATCH 349/777] Add a method to convert public NetworkStats to internal NetworkStats Bug: 210073043 Test: NetworkStaticLibTests Change-Id: I769e023729b5a2743e60c211e9c4aeeff1f9f172 --- .../net/module/util/NetworkStatsUtils.java | 84 +++++++++++++++++++ .../net/module/util/NetworkStatsUtilsTest.kt | 68 +++++++++++++++ 2 files changed, 152 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java index 28ff77052c..c4d415efcf 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java @@ -16,12 +16,23 @@ package com.android.net.module.util; +import android.app.usage.NetworkStats; + +import com.android.internal.annotations.VisibleForTesting; + /** * Various utilities used for NetworkStats related code. * * @hide */ public class NetworkStatsUtils { + // These constants must be synced with the definition in android.net.NetworkStats. + // TODO: update to formal APIs once all downstreams have these APIs. + private static final int SET_ALL = -1; + private static final int METERED_ALL = -1; + private static final int ROAMING_ALL = -1; + private static final int DEFAULT_NETWORK_ALL = -1; + /** * Safely multiple a value by a rational. *

@@ -88,4 +99,77 @@ public class NetworkStatsUtils { if (low > high) throw new IllegalArgumentException("low(" + low + ") > high(" + high + ")"); return amount < low ? low : (amount > high ? high : amount); } + + /** + * Convert structure from android.app.usage.NetworkStats to android.net.NetworkStats. + */ + public static android.net.NetworkStats fromPublicNetworkStats( + NetworkStats publiceNetworkStats) { + android.net.NetworkStats stats = new android.net.NetworkStats(0L, 0); + while (publiceNetworkStats.hasNextBucket()) { + NetworkStats.Bucket bucket = new NetworkStats.Bucket(); + publiceNetworkStats.getNextBucket(bucket); + final android.net.NetworkStats.Entry entry = fromBucket(bucket); + stats = stats.addEntry(entry); + } + return stats; + } + + @VisibleForTesting + static android.net.NetworkStats.Entry fromBucket(NetworkStats.Bucket bucket) { + return new android.net.NetworkStats.Entry( + null /* IFACE_ALL */, bucket.getUid(), convertBucketState(bucket.getState()), + convertBucketTag(bucket.getTag()), convertBucketMetered(bucket.getMetered()), + convertBucketRoaming(bucket.getRoaming()), + convertBucketDefaultNetworkStatus(bucket.getDefaultNetworkStatus()), + bucket.getRxBytes(), bucket.getRxPackets(), + bucket.getTxBytes(), bucket.getTxPackets(), 0 /* operations */); + } + + private static int convertBucketState(int networkStatsSet) { + switch (networkStatsSet) { + case NetworkStats.Bucket.STATE_ALL: return SET_ALL; + case NetworkStats.Bucket.STATE_DEFAULT: return android.net.NetworkStats.SET_DEFAULT; + case NetworkStats.Bucket.STATE_FOREGROUND: + return android.net.NetworkStats.SET_FOREGROUND; + } + return 0; + } + + private static int convertBucketTag(int tag) { + switch (tag) { + case NetworkStats.Bucket.TAG_NONE: return android.net.NetworkStats.TAG_NONE; + } + return tag; + } + + private static int convertBucketMetered(int metered) { + switch (metered) { + case NetworkStats.Bucket.METERED_ALL: return METERED_ALL; + case NetworkStats.Bucket.METERED_NO: return android.net.NetworkStats.METERED_NO; + case NetworkStats.Bucket.METERED_YES: return android.net.NetworkStats.METERED_YES; + } + return 0; + } + + private static int convertBucketRoaming(int roaming) { + switch (roaming) { + case NetworkStats.Bucket.ROAMING_ALL: return ROAMING_ALL; + case NetworkStats.Bucket.ROAMING_NO: return android.net.NetworkStats.ROAMING_NO; + case NetworkStats.Bucket.ROAMING_YES: return android.net.NetworkStats.ROAMING_YES; + } + return 0; + } + + private static int convertBucketDefaultNetworkStatus(int defaultNetworkStatus) { + switch (defaultNetworkStatus) { + case NetworkStats.Bucket.DEFAULT_NETWORK_ALL: + return DEFAULT_NETWORK_ALL; + case NetworkStats.Bucket.DEFAULT_NETWORK_NO: + return android.net.NetworkStats.DEFAULT_NETWORK_NO; + case NetworkStats.Bucket.DEFAULT_NETWORK_YES: + return android.net.NetworkStats.DEFAULT_NETWORK_YES; + } + return 0; + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkStatsUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkStatsUtilsTest.kt index ff839fe8fb..2785ea9029 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkStatsUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkStatsUtilsTest.kt @@ -16,12 +16,16 @@ package com.android.net.module.util +import android.net.NetworkStats +import android.text.TextUtils import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import org.junit.Test import org.junit.runner.RunWith import kotlin.test.assertEquals import kotlin.test.assertFailsWith +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.mock @RunWith(AndroidJUnit4::class) @SmallTest @@ -71,4 +75,68 @@ class NetworkStatsUtilsTest { assertEquals(11, NetworkStatsUtils.constrain(11, 11, 11)) assertEquals(11, NetworkStatsUtils.constrain(1, 11, 11)) } + + @Test + fun testBucketToEntry() { + val bucket = makeMockBucket(android.app.usage.NetworkStats.Bucket.UID_ALL, + android.app.usage.NetworkStats.Bucket.TAG_NONE, + android.app.usage.NetworkStats.Bucket.STATE_DEFAULT, + android.app.usage.NetworkStats.Bucket.METERED_YES, + android.app.usage.NetworkStats.Bucket.ROAMING_NO, + android.app.usage.NetworkStats.Bucket.DEFAULT_NETWORK_ALL, 1024, 8, 2048, 12) + val entry = NetworkStatsUtils.fromBucket(bucket) + val expectedEntry = NetworkStats.Entry(null /* IFACE_ALL */, NetworkStats.UID_ALL, + NetworkStats.SET_DEFAULT, NetworkStats.TAG_NONE, NetworkStats.METERED_YES, + NetworkStats.ROAMING_NO, NetworkStats.DEFAULT_NETWORK_ALL, 1024, 8, 2048, 12, + 0 /* operations */) + + // TODO: Use assertEquals once all downstreams accept null iface in + // NetworkStats.Entry#equals. + assertEntryEquals(expectedEntry, entry) + } + + private fun makeMockBucket( + uid: Int, + tag: Int, + state: Int, + metered: Int, + roaming: Int, + defaultNetwork: Int, + rxBytes: Long, + rxPackets: Long, + txBytes: Long, + txPackets: Long + ): android.app.usage.NetworkStats.Bucket { + val ret: android.app.usage.NetworkStats.Bucket = + mock(android.app.usage.NetworkStats.Bucket::class.java) + doReturn(uid).`when`(ret).getUid() + doReturn(tag).`when`(ret).getTag() + doReturn(state).`when`(ret).getState() + doReturn(metered).`when`(ret).getMetered() + doReturn(roaming).`when`(ret).getRoaming() + doReturn(defaultNetwork).`when`(ret).getDefaultNetworkStatus() + doReturn(rxBytes).`when`(ret).getRxBytes() + doReturn(rxPackets).`when`(ret).getRxPackets() + doReturn(txBytes).`when`(ret).getTxBytes() + doReturn(txPackets).`when`(ret).getTxPackets() + return ret + } + + /** + * Assert that the two {@link NetworkStats.Entry} are equals. + */ + private fun assertEntryEquals(left: NetworkStats.Entry, right: NetworkStats.Entry) { + TextUtils.equals(left.iface, right.iface) + assertEquals(left.uid, right.uid) + assertEquals(left.set, right.set) + assertEquals(left.tag, right.tag) + assertEquals(left.metered, right.metered) + assertEquals(left.roaming, right.roaming) + assertEquals(left.defaultNetwork, right.defaultNetwork) + assertEquals(left.rxBytes, right.rxBytes) + assertEquals(left.rxPackets, right.rxPackets) + assertEquals(left.txBytes, right.txBytes) + assertEquals(left.txPackets, right.txPackets) + assertEquals(left.operations, right.operations) + } } \ No newline at end of file From 0c34e9a0846080dc6d3814c64d3024070de0ac0b Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Mon, 17 Jan 2022 13:59:09 +0100 Subject: [PATCH 350/777] Fix kernelversion.h Add missing pragma once and static inline all functions. Bug: 202086915 Bug: 157552970 Test: builds Change-Id: I8aca683e9e60c33bf5a5ac45cc20c2e59c8eecde --- staticlibs/native/tcutils/kernelversion.h | 9 ++++++--- staticlibs/native/tcutils/tcutils.cpp | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/staticlibs/native/tcutils/kernelversion.h b/staticlibs/native/tcutils/kernelversion.h index 59b9e0540b..3be1ad293f 100644 --- a/staticlibs/native/tcutils/kernelversion.h +++ b/staticlibs/native/tcutils/kernelversion.h @@ -23,6 +23,8 @@ // In the mean time copying verbatim from: // frameworks/libs/net/common/native/bpf_headers +#pragma once + #include #include @@ -30,7 +32,7 @@ namespace android { -unsigned kernelVersion() { +static inline unsigned kernelVersion() { struct utsname buf; int ret = uname(&buf); if (ret) @@ -49,8 +51,9 @@ unsigned kernelVersion() { return KVER(kver_major, kver_minor, kver_sub); } -bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) { +static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, + unsigned sub) { return kernelVersion() >= KVER(major, minor, sub); } -} +} // namespace android diff --git a/staticlibs/native/tcutils/tcutils.cpp b/staticlibs/native/tcutils/tcutils.cpp index e30a5004c5..00f3c56e2f 100644 --- a/staticlibs/native/tcutils/tcutils.cpp +++ b/staticlibs/native/tcutils/tcutils.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include From 27846ff7a2a289dc52ffaab5087fab28aa8aea29 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Mon, 17 Jan 2022 12:22:51 +0100 Subject: [PATCH 351/777] Add tests for libtcutils Add tests for isEthernet(). Before I can add tests for the other functions, I need to move tcQdiscAddDevClsact into libtcutils. Bug: 202086915 Bug: 157552970 Test: atest LibTcUtilsTest Change-Id: Id51e87bb76bc42a055f71027c94c51fcb76be209 --- staticlibs/native/tcutils/Android.bp | 24 +++++++ staticlibs/native/tcutils/tcutils.cpp | 4 +- .../native/tcutils/tests/tcutils_test.cpp | 66 +++++++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 staticlibs/native/tcutils/tests/tcutils_test.cpp diff --git a/staticlibs/native/tcutils/Android.bp b/staticlibs/native/tcutils/Android.bp index c26fca6663..e819e4c094 100644 --- a/staticlibs/native/tcutils/Android.bp +++ b/staticlibs/native/tcutils/Android.bp @@ -42,3 +42,27 @@ cc_library_static { "//system/netd/server", ], } + +cc_test { + name: "libtcutils_test", + srcs: [ + "tests/tcutils_test.cpp", + ], + cflags: [ + "-Wall", + "-Werror", + "-Wno-error=unused-variable", + ], + header_libs: ["bpf_syscall_wrappers"], + static_libs: [ + "libgmock", + "libtcutils", + ], + shared_libs: [ + "libbase", + "liblog", + ], + min_sdk_version: "30", + require_root: true, + test_suites: ["general-tests"], +} diff --git a/staticlibs/native/tcutils/tcutils.cpp b/staticlibs/native/tcutils/tcutils.cpp index 00f3c56e2f..3f24178e01 100644 --- a/staticlibs/native/tcutils/tcutils.cpp +++ b/staticlibs/native/tcutils/tcutils.cpp @@ -175,7 +175,7 @@ int isEthernet(const char *iface, bool &isEthernet) { if (rv < 0) { logError("Get hardware address type of interface %s failed: %s", iface, strerror(-rv)); - return -rv; + return rv; } // Backwards compatibility with pre-GKI kernels that use various custom @@ -208,7 +208,7 @@ int isEthernet(const char *iface, bool &isEthernet) { return 0; default: logError("Unknown hardware address type %d on interface %s", rv, iface); - return -ENOENT; + return -EAFNOSUPPORT; } } diff --git a/staticlibs/native/tcutils/tests/tcutils_test.cpp b/staticlibs/native/tcutils/tests/tcutils_test.cpp new file mode 100644 index 0000000000..bab2d3e13b --- /dev/null +++ b/staticlibs/native/tcutils/tests/tcutils_test.cpp @@ -0,0 +1,66 @@ +/* + * Copyright 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. + * + * TcUtilsTest.cpp - unit tests for TcUtils.cpp + */ + +#include + +#include + +#include + +namespace android { + +TEST(LibTcUtilsTest, IsEthernetOfNonExistingIf) { + bool result = false; + int error = isEthernet("not_existing_if", result); + ASSERT_FALSE(result); + ASSERT_EQ(-ENODEV, error); +} + +TEST(LibTcUtilsTest, IsEthernetOfLoopback) { + bool result = false; + int error = isEthernet("lo", result); + ASSERT_FALSE(result); + ASSERT_EQ(-EAFNOSUPPORT, error); +} + +// If wireless 'wlan0' interface exists it should be Ethernet. +// See also HardwareAddressTypeOfWireless. +TEST(LibTcUtilsTest, IsEthernetOfWireless) { + bool result = false; + int error = isEthernet("wlan0", result); + if (!result && error == -ENODEV) + return; + + ASSERT_EQ(0, error); + ASSERT_TRUE(result); +} + +// If cellular 'rmnet_data0' interface exists it should +// *probably* not be Ethernet and instead be RawIp. +// See also HardwareAddressTypeOfCellular. +TEST(LibTcUtilsTest, IsEthernetOfCellular) { + bool result = false; + int error = isEthernet("rmnet_data0", result); + if (!result && error == -ENODEV) + return; + + ASSERT_EQ(0, error); + ASSERT_FALSE(result); +} + +} // namespace android From 42b58ae8365b0b3731c69b4183282d2936459bd2 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Mon, 17 Jan 2022 13:09:12 +0100 Subject: [PATCH 352/777] Add support to attach / replace / detach clsact qdisc to libtcutils Bug: 202086915 Bug: 157552970 Test: atest LibTcUtilsTest Change-Id: I2f2e2f66acb7590e8951ac6e178c5893ba635597 --- .../native/tcutils/include/tcutils/tcutils.h | 16 +++++++ staticlibs/native/tcutils/tcutils.cpp | 48 +++++++++++++++++++ .../native/tcutils/tests/tcutils_test.cpp | 12 +++++ 3 files changed, 76 insertions(+) diff --git a/staticlibs/native/tcutils/include/tcutils/tcutils.h b/staticlibs/native/tcutils/include/tcutils/tcutils.h index d1e1bb7639..0dbde347a3 100644 --- a/staticlibs/native/tcutils/include/tcutils/tcutils.h +++ b/staticlibs/native/tcutils/include/tcutils/tcutils.h @@ -17,10 +17,26 @@ #pragma once #include +#include namespace android { int isEthernet(const char *iface, bool &isEthernet); + +int doTcQdiscClsact(int ifIndex, uint16_t nlMsgType, uint16_t nlMsgFlags); + +static inline int tcAddQdiscClsact(int ifIndex) { + return doTcQdiscClsact(ifIndex, RTM_NEWQDISC, NLM_F_EXCL | NLM_F_CREATE); +} + +static inline int tcReplaceQdiscClsact(int ifIndex) { + return doTcQdiscClsact(ifIndex, RTM_NEWQDISC, NLM_F_CREATE | NLM_F_REPLACE); +} + +static inline int tcDeleteQdiscClsact(int ifIndex) { + return doTcQdiscClsact(ifIndex, RTM_DELQDISC, 0); +} + int tcAddBpfFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto, const char *bpfProgPath); int tcDeleteFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto); diff --git a/staticlibs/native/tcutils/tcutils.cpp b/staticlibs/native/tcutils/tcutils.cpp index 3f24178e01..9b8c843052 100644 --- a/staticlibs/native/tcutils/tcutils.cpp +++ b/staticlibs/native/tcutils/tcutils.cpp @@ -212,6 +212,54 @@ int isEthernet(const char *iface, bool &isEthernet) { } } +// ADD: nlMsgType=RTM_NEWQDISC nlMsgFlags=NLM_F_EXCL|NLM_F_CREATE +// REPLACE: nlMsgType=RTM_NEWQDISC nlMsgFlags=NLM_F_CREATE|NLM_F_REPLACE +// DEL: nlMsgType=RTM_DELQDISC nlMsgFlags=0 +int doTcQdiscClsact(int ifIndex, uint16_t nlMsgType, uint16_t nlMsgFlags) { + // This is the name of the qdisc we are attaching. + // Some hoop jumping to make this compile time constant with known size, + // so that the structure declaration is well defined at compile time. +#define CLSACT "clsact" + // sizeof() includes the terminating NULL + static constexpr size_t ASCIIZ_LEN_CLSACT = sizeof(CLSACT); + + const struct { + nlmsghdr n; + tcmsg t; + struct { + nlattr attr; + char str[NLMSG_ALIGN(ASCIIZ_LEN_CLSACT)]; + } kind; + } req = { + .n = + { + .nlmsg_len = sizeof(req), + .nlmsg_type = nlMsgType, + .nlmsg_flags = + static_cast<__u16>(NETLINK_REQUEST_FLAGS | nlMsgFlags), + }, + .t = + { + .tcm_family = AF_UNSPEC, + .tcm_ifindex = ifIndex, + .tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0), + .tcm_parent = TC_H_CLSACT, + }, + .kind = + { + .attr = + { + .nla_len = NLA_HDRLEN + ASCIIZ_LEN_CLSACT, + .nla_type = TCA_KIND, + }, + .str = CLSACT, + }, + }; +#undef CLSACT + + return sendAndProcessNetlinkResponse(&req, sizeof(req)); +} + // tc filter add dev .. in/egress prio 1 protocol ipv6/ip bpf object-pinned // /sys/fs/bpf/... direct-action int tcAddBpfFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto, diff --git a/staticlibs/native/tcutils/tests/tcutils_test.cpp b/staticlibs/native/tcutils/tests/tcutils_test.cpp index bab2d3e13b..6f28fbec0b 100644 --- a/staticlibs/native/tcutils/tests/tcutils_test.cpp +++ b/staticlibs/native/tcutils/tests/tcutils_test.cpp @@ -63,4 +63,16 @@ TEST(LibTcUtilsTest, IsEthernetOfCellular) { ASSERT_FALSE(result); } +// See Linux kernel source in include/net/flow.h +static constexpr int LOOPBACK_IFINDEX = 1; + +TEST(LibTcUtilsTest, AttachReplaceDetachClsactLo) { + // This attaches and detaches a configuration-less and thus no-op clsact + // qdisc to loopback interface (and it takes fractions of a second) + EXPECT_EQ(0, tcAddQdiscClsact(LOOPBACK_IFINDEX)); + EXPECT_EQ(0, tcReplaceQdiscClsact(LOOPBACK_IFINDEX)); + EXPECT_EQ(0, tcDeleteQdiscClsact(LOOPBACK_IFINDEX)); + EXPECT_EQ(-EINVAL, tcDeleteQdiscClsact(LOOPBACK_IFINDEX)); +} + } // namespace android From 1f7ba259c33c8186de0654509f626de6daf2c79a Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Mon, 17 Jan 2022 16:14:10 +0100 Subject: [PATCH 353/777] Add tests for adding / deleting bpf filter Bug: 202086915 Bug: 157552970 Test: atest LibTcUtilsTest Change-Id: I8adcb3df29e4b3e0c558714f90b2840698e40cb9 --- .../native/tcutils/tests/tcutils_test.cpp | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/staticlibs/native/tcutils/tests/tcutils_test.cpp b/staticlibs/native/tcutils/tests/tcutils_test.cpp index 6f28fbec0b..0a2be51fc2 100644 --- a/staticlibs/native/tcutils/tests/tcutils_test.cpp +++ b/staticlibs/native/tcutils/tests/tcutils_test.cpp @@ -18,9 +18,12 @@ #include +#include "kernelversion.h" #include +#include #include +#include namespace android { @@ -75,4 +78,36 @@ TEST(LibTcUtilsTest, AttachReplaceDetachClsactLo) { EXPECT_EQ(-EINVAL, tcDeleteQdiscClsact(LOOPBACK_IFINDEX)); } +TEST(LibTcUtilsTest, AddAndDeleteBpfFilter) { + // TODO: this should use bpf_shared.h rather than hardcoding the path + static constexpr char bpfProgPath[] = + "/sys/fs/bpf/tethering/prog_offload_schedcls_tether_downstream6_ether"; + const int errNOENT = isAtLeastKernelVersion(4, 19, 0) ? ENOENT : EINVAL; + + // static test values + static constexpr bool ingress = true; + static constexpr uint16_t prio = 17; + static constexpr uint16_t proto = ETH_P_ALL; + + // try to delete missing filter from missing qdisc + EXPECT_EQ(-EINVAL, tcDeleteFilter(LOOPBACK_IFINDEX, ingress, prio, proto)); + // try to attach bpf filter to missing qdisc + EXPECT_EQ(-EINVAL, tcAddBpfFilter(LOOPBACK_IFINDEX, ingress, prio, proto, + bpfProgPath)); + // add the clsact qdisc + EXPECT_EQ(0, tcAddQdiscClsact(LOOPBACK_IFINDEX)); + // try to delete missing filter when there is a qdisc attached + EXPECT_EQ(-errNOENT, tcDeleteFilter(LOOPBACK_IFINDEX, ingress, prio, proto)); + // add and delete a bpf filter + EXPECT_EQ( + 0, tcAddBpfFilter(LOOPBACK_IFINDEX, ingress, prio, proto, bpfProgPath)); + EXPECT_EQ(0, tcDeleteFilter(LOOPBACK_IFINDEX, ingress, prio, proto)); + // try to remove the same filter a second time + EXPECT_EQ(-errNOENT, tcDeleteFilter(LOOPBACK_IFINDEX, ingress, prio, proto)); + // remove the clsact qdisc + EXPECT_EQ(0, tcDeleteQdiscClsact(LOOPBACK_IFINDEX)); + // once again, try to delete missing filter from missing qdisc + EXPECT_EQ(-EINVAL, tcDeleteFilter(LOOPBACK_IFINDEX, ingress, prio, proto)); +} + } // namespace android From e815a7462f35a3aadcb85ac590e8fe97c7877e72 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Mon, 17 Jan 2022 10:37:40 +0100 Subject: [PATCH 354/777] Add functionality to attach tc-police action to ingress qdisc This is used for go/bandwidth-limiting. Bug: 157552970 Test: atest LibTcUtilsTest Change-Id: Ic8e4d8dc016b14a6d4fc8ddbb3949941e9ef95af --- .../native/tcutils/include/tcutils/tcutils.h | 3 + staticlibs/native/tcutils/tcutils.cpp | 345 ++++++++++++++++++ .../native/tcutils/tests/tcutils_test.cpp | 44 +++ 3 files changed, 392 insertions(+) diff --git a/staticlibs/native/tcutils/include/tcutils/tcutils.h b/staticlibs/native/tcutils/include/tcutils/tcutils.h index 0dbde347a3..a8ec2e87c4 100644 --- a/staticlibs/native/tcutils/include/tcutils/tcutils.h +++ b/staticlibs/native/tcutils/include/tcutils/tcutils.h @@ -39,6 +39,9 @@ static inline int tcDeleteQdiscClsact(int ifIndex) { int tcAddBpfFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto, const char *bpfProgPath); +int tcAddIngressPoliceFilter(int ifIndex, uint16_t prio, uint16_t proto, + unsigned rateInBytesPerSec, + const char *bpfProgPath); int tcDeleteFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto); } // namespace android diff --git a/staticlibs/native/tcutils/tcutils.cpp b/staticlibs/native/tcutils/tcutils.cpp index 9b8c843052..ad9d9e4ab3 100644 --- a/staticlibs/native/tcutils/tcutils.cpp +++ b/staticlibs/native/tcutils/tcutils.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,319 @@ void logError(const char *fmt...) { va_end(args); } +/** + * IngressPoliceFilterBuilder builds a nlmsg request equivalent to the following + * tc command: + * + * tc filter add dev .. ingress prio .. protocol .. matchall \ + * action police rate .. burst .. conform-exceed pipe/continue \ + * action bpf object-pinned .. \ + * drop + */ +class IngressPoliceFilterBuilder final { + // default mtu is 2047, so the cell logarithm factor (cell_log) is 3. + // 0x7FF >> 0x3FF x 2^1 >> 0x1FF x 2^2 >> 0xFF x 2^3 + static constexpr int RTAB_CELL_LOGARITHM = 3; + static constexpr size_t RTAB_SIZE = 256; + static constexpr unsigned TIME_UNITS_PER_SEC = 1000000; + + struct Request { + nlmsghdr n; + tcmsg t; + struct { + nlattr attr; + char str[NLMSG_ALIGN(sizeof("matchall"))]; + } kind; + struct { + nlattr attr; + struct { + nlattr attr; + struct { + nlattr attr; + struct { + nlattr attr; + char str[NLMSG_ALIGN(sizeof("police"))]; + } kind; + struct { + nlattr attr; + struct { + nlattr attr; + struct tc_police obj; + } police; + struct { + nlattr attr; + uint32_t u32[RTAB_SIZE]; + } rtab; + struct { + nlattr attr; + int32_t s32; + } notexceedact; + } opt; + } act1; + struct { + nlattr attr; + struct { + nlattr attr; + char str[NLMSG_ALIGN(sizeof("bpf"))]; + } kind; + struct { + nlattr attr; + struct { + nlattr attr; + uint32_t u32; + } fd; + struct { + nlattr attr; + char str[NLMSG_ALIGN(CLS_BPF_NAME_LEN)]; + } name; + struct { + nlattr attr; + struct tc_act_bpf obj; + } parms; + } opt; + } act2; + } acts; + } opt; + }; + + // class members + const unsigned mBurstInBytes; + const char *mBpfProgPath; + int mBpfFd; + Request mRequest; + + static double getTickInUsec() { + FILE *fp = fopen("/proc/net/psched", "re"); + if (!fp) { + logError("fopen(\"/proc/net/psched\"): %s", strerror(errno)); + return 0.0; + } + auto scopeGuard = base::make_scope_guard([fp] { fclose(fp); }); + + uint32_t t2us; + uint32_t us2t; + uint32_t clockRes; + const bool isError = + fscanf(fp, "%08x%08x%08x", &t2us, &us2t, &clockRes) != 3; + + if (isError) { + logError("fscanf(/proc/net/psched, \"%%08x%%08x%%08x\"): %s", + strerror(errno)); + return 0.0; + } + + const double clockFactor = + static_cast(clockRes) / TIME_UNITS_PER_SEC; + return static_cast(t2us) / static_cast(us2t) * clockFactor; + } + + static inline const double kTickInUsec = getTickInUsec(); + +public: + // clang-format off + IngressPoliceFilterBuilder(int ifIndex, uint16_t prio, uint16_t proto, unsigned rateInBytesPerSec, + unsigned burstInBytes, const char* bpfProgPath) + : mBurstInBytes(burstInBytes), + mBpfProgPath(bpfProgPath), + mBpfFd(-1), + mRequest{ + .n = { + .nlmsg_len = sizeof(mRequest), + .nlmsg_type = RTM_NEWTFILTER, + .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE, + }, + .t = { + .tcm_family = AF_UNSPEC, + .tcm_ifindex = ifIndex, + .tcm_handle = TC_H_UNSPEC, + .tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS), + .tcm_info = (static_cast(prio) << 16) + | static_cast(htons(proto)), + }, + .kind = { + .attr = { + .nla_len = sizeof(mRequest.kind), + .nla_type = TCA_KIND, + }, + .str = "matchall", + }, + .opt = { + .attr = { + .nla_len = sizeof(mRequest.opt), + .nla_type = TCA_OPTIONS, + }, + .acts = { + .attr = { + .nla_len = sizeof(mRequest.opt.acts), + .nla_type = TCA_U32_ACT, + }, + .act1 = { + .attr = { + .nla_len = sizeof(mRequest.opt.acts.act1), + .nla_type = 1, // action priority + }, + .kind = { + .attr = { + .nla_len = sizeof(mRequest.opt.acts.act1.kind), + .nla_type = TCA_ACT_KIND, + }, + .str = "police", + }, + .opt = { + .attr = { + .nla_len = sizeof(mRequest.opt.acts.act1.opt), + .nla_type = TCA_ACT_OPTIONS | NLA_F_NESTED, + }, + .police = { + .attr = { + .nla_len = sizeof(mRequest.opt.acts.act1.opt.police), + .nla_type = TCA_POLICE_TBF, + }, + .obj = { + .action = TC_ACT_PIPE, + .burst = 0, + .rate = { + .cell_log = RTAB_CELL_LOGARITHM, + .linklayer = TC_LINKLAYER_ETHERNET, + .cell_align = -1, + .rate = rateInBytesPerSec, + }, + }, + }, + .rtab = { + .attr = { + .nla_len = sizeof(mRequest.opt.acts.act1.opt.rtab), + .nla_type = TCA_POLICE_RATE, + }, + .u32 = {}, + }, + .notexceedact = { + .attr = { + .nla_len = sizeof(mRequest.opt.acts.act1.opt.notexceedact), + .nla_type = TCA_POLICE_RESULT, + }, + .s32 = TC_ACT_UNSPEC, + }, + }, + }, + .act2 = { + .attr = { + .nla_len = sizeof(mRequest.opt.acts.act2), + .nla_type = 2, // action priority + }, + .kind = { + .attr = { + .nla_len = sizeof(mRequest.opt.acts.act2.kind), + .nla_type = TCA_ACT_KIND, + }, + .str = "bpf", + }, + .opt = { + .attr = { + .nla_len = sizeof(mRequest.opt.acts.act2.opt), + .nla_type = TCA_ACT_OPTIONS | NLA_F_NESTED, + }, + .fd = { + .attr = { + .nla_len = sizeof(mRequest.opt.acts.act2.opt.fd), + .nla_type = TCA_ACT_BPF_FD, + }, + .u32 = 0, // set during build() + }, + .name = { + .attr = { + .nla_len = sizeof(mRequest.opt.acts.act2.opt.name), + .nla_type = TCA_ACT_BPF_NAME, + }, + .str = "placeholder", + }, + .parms = { + .attr = { + .nla_len = sizeof(mRequest.opt.acts.act2.opt.parms), + .nla_type = TCA_ACT_BPF_PARMS, + }, + .obj = { + // default action to be executed when bpf prog + // returns TC_ACT_UNSPEC. + .action = TC_ACT_SHOT, + }, + }, + }, + }, + }, + }, + } { + // constructor body + } + // clang-format on + + ~IngressPoliceFilterBuilder() { + // TODO: use unique_fd + if (mBpfFd != -1) { + close(mBpfFd); + } + } + + constexpr unsigned getRequestSize() const { return sizeof(Request); } + +private: + unsigned calculateXmitTime(unsigned size) { + const uint32_t rate = mRequest.opt.acts.act1.opt.police.obj.rate.rate; + return (static_cast(size) / static_cast(rate)) * + TIME_UNITS_PER_SEC * kTickInUsec; + } + + void initBurstRate() { + mRequest.opt.acts.act1.opt.police.obj.burst = + calculateXmitTime(mBurstInBytes); + } + + // Calculates a table with 256 transmission times for different packet sizes + // (all the way up to MTU). RTAB_CELL_LOGARITHM is used as a scaling factor. + // In this case, MTU size is always 2048, so RTAB_CELL_LOGARITHM is always + // 3. Therefore, this function generates the transmission times for packets + // of size 1..256 x 2^3. + void initRateTable() { + for (unsigned i = 0; i < RTAB_SIZE; ++i) { + unsigned adjustedSize = (i + 1) << RTAB_CELL_LOGARITHM; + mRequest.opt.acts.act1.opt.rtab.u32[i] = calculateXmitTime(adjustedSize); + } + } + + int initBpfFd() { + mBpfFd = bpf::retrieveProgram(mBpfProgPath); + if (mBpfFd == -1) { + int error = errno; + logError("retrieveProgram failed: %d", error); + return -error; + } + + mRequest.opt.acts.act2.opt.fd.u32 = static_cast(mBpfFd); + snprintf(mRequest.opt.acts.act2.opt.name.str, + sizeof(mRequest.opt.acts.act2.opt.name.str), "%s:[*fsobj]", + basename(mBpfProgPath)); + + return 0; + } + +public: + int build() { + if (kTickInUsec == 0.0) { + return -EINVAL; + } + + initBurstRate(); + initRateTable(); + return initBpfFd(); + } + + const Request *getRequest() const { + // Make sure to call build() before calling this function. Otherwise, the + // request will be invalid. + return &mRequest; + } +}; + const sockaddr_nl KERNEL_NLADDR = {AF_NETLINK, 0, 0, 0}; const uint16_t NETLINK_REQUEST_FLAGS = NLM_F_REQUEST | NLM_F_ACK; @@ -368,6 +682,37 @@ int tcAddBpfFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto, return error; } +// tc filter add dev .. ingress prio .. protocol .. matchall \ +// action police rate .. burst .. conform-exceed pipe/continue \ +// action bpf object-pinned .. \ +// drop +// +// TODO: tc-police does not do ECN marking, so in the future, we should consider +// adding a second tc-police filter at a lower priority that rate limits traffic +// at something like 0.8 times the global rate limit and ecn marks exceeding +// packets inside a bpf program (but does not drop them). +int tcAddIngressPoliceFilter(int ifIndex, uint16_t prio, uint16_t proto, + unsigned rateInBytesPerSec, + const char *bpfProgPath) { + // TODO: this value needs to be validated. + // TCP IW10 (initial congestion window) means servers will send 10 mtus worth + // of data on initial connect. + // If nic is LRO capable it could aggregate up to 64KiB, so again probably a + // bad idea to set burst below that, because ingress packets could get + // aggregated to 64KiB at the nic. + // I don't know, but I wonder whether we shouldn't just do 128KiB and not do + // any math. + static constexpr unsigned BURST_SIZE_IN_BYTES = 128 * 1024; // 128KiB + IngressPoliceFilterBuilder filter(ifIndex, prio, proto, rateInBytesPerSec, + BURST_SIZE_IN_BYTES, bpfProgPath); + const int error = filter.build(); + if (error) { + return error; + } + return sendAndProcessNetlinkResponse(filter.getRequest(), + filter.getRequestSize()); +} + // tc filter del dev .. in/egress prio .. protocol .. int tcDeleteFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto) { const struct { diff --git a/staticlibs/native/tcutils/tests/tcutils_test.cpp b/staticlibs/native/tcutils/tests/tcutils_test.cpp index 0a2be51fc2..32736d6b9d 100644 --- a/staticlibs/native/tcutils/tests/tcutils_test.cpp +++ b/staticlibs/native/tcutils/tests/tcutils_test.cpp @@ -110,4 +110,48 @@ TEST(LibTcUtilsTest, AddAndDeleteBpfFilter) { EXPECT_EQ(-EINVAL, tcDeleteFilter(LOOPBACK_IFINDEX, ingress, prio, proto)); } +TEST(LibTcUtilsTest, AddAndDeleteIngressPoliceFilter) { + // TODO: this should use bpf_shared.h rather than hardcoding the path + static constexpr char bpfProgPath[] = + "/sys/fs/bpf/prog_netd_schedact_ingress_account"; + int fd = bpf::retrieveProgram(bpfProgPath); + if (fd == -1) { + // ingress policing is not supported. + return; + } + close(fd); + + const int errNOENT = isAtLeastKernelVersion(4, 19, 0) ? ENOENT : EINVAL; + + // static test values + static constexpr unsigned rateInBytesPerSec = + 1024 * 1024; // 8mbit/s => 1mbyte/s => 1024*1024 bytes/s. + static constexpr uint16_t prio = 17; + static constexpr uint16_t proto = ETH_P_ALL; + + // try to delete missing filter from missing qdisc + EXPECT_EQ(-EINVAL, + tcDeleteFilter(LOOPBACK_IFINDEX, true /*ingress*/, prio, proto)); + // try to attach bpf filter to missing qdisc + EXPECT_EQ(-EINVAL, tcAddIngressPoliceFilter(LOOPBACK_IFINDEX, prio, proto, + rateInBytesPerSec, bpfProgPath)); + // add the clsact qdisc + EXPECT_EQ(0, tcAddQdiscClsact(LOOPBACK_IFINDEX)); + // try to delete missing filter when there is a qdisc attached + EXPECT_EQ(-errNOENT, + tcDeleteFilter(LOOPBACK_IFINDEX, true /*ingress*/, prio, proto)); + // add and delete a bpf filter + EXPECT_EQ(0, tcAddIngressPoliceFilter(LOOPBACK_IFINDEX, prio, proto, + rateInBytesPerSec, bpfProgPath)); + EXPECT_EQ(0, tcDeleteFilter(LOOPBACK_IFINDEX, true /*ingress*/, prio, proto)); + // try to remove the same filter a second time + EXPECT_EQ(-errNOENT, + tcDeleteFilter(LOOPBACK_IFINDEX, true /*ingress*/, prio, proto)); + // remove the clsact qdisc + EXPECT_EQ(0, tcDeleteQdiscClsact(LOOPBACK_IFINDEX)); + // once again, try to delete missing filter from missing qdisc + EXPECT_EQ(-EINVAL, + tcDeleteFilter(LOOPBACK_IFINDEX, true /*ingress*/, prio, proto)); +} + } // namespace android From eb3a8c734b6ea766398895770636ed718a507ca6 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Mon, 17 Jan 2022 17:25:04 +0100 Subject: [PATCH 355/777] Add tc police support to jni lib Bug: 157552970 Test: TreeHugger Change-Id: I63b4324bbb8d20b7d401921dad1f8e73ccc26a39 --- .../com_android_net_module_util_TcUtils.cpp | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp index e5a3668527..2307a6bbe1 100644 --- a/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp +++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp @@ -54,6 +54,24 @@ static void com_android_net_module_util_TcUtils_tcFilterAddDevBpf( } } +// tc filter add dev .. ingress prio .. protocol .. matchall \ +// action police rate .. burst .. conform-exceed pipe/continue \ +// action bpf object-pinned .. \ +// drop +static void com_android_net_module_util_TcUtils_tcFilterAddDevIngressPolice( + JNIEnv *env, jobject clazz, jint ifIndex, jshort prio, jshort proto, + jint rateInBytesPerSec, jstring bpfProgPath) { + ScopedUtfChars pathname(env, bpfProgPath); + int error = tcAddIngressPoliceFilter(ifIndex, prio, proto, rateInBytesPerSec, + pathname.c_str()); + if (error) { + throwIOException(env, + "com_android_net_module_util_TcUtils_" + "tcFilterAddDevIngressPolice error: ", + error); + } +} + // tc filter del dev .. in/egress prio .. protocol .. static void com_android_net_module_util_TcUtils_tcFilterDelDev( JNIEnv *env, jobject clazz, jint ifIndex, jboolean ingress, jshort prio, @@ -75,6 +93,8 @@ static const JNINativeMethod gMethods[] = { (void *)com_android_net_module_util_TcUtils_isEthernet}, {"tcFilterAddDevBpf", "(IZSSLjava/lang/String;)V", (void *)com_android_net_module_util_TcUtils_tcFilterAddDevBpf}, + {"tcFilterAddDevIngressPolice", "(ISSILjava/lang/String;)V", + (void *)com_android_net_module_util_TcUtils_tcFilterAddDevIngressPolice}, {"tcFilterDelDev", "(IZSS)V", (void *)com_android_net_module_util_TcUtils_tcFilterDelDev}, }; From 97a0e80f0a67a31f696a1d5535ee5a8ab0762f4f Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Mon, 17 Jan 2022 17:25:59 +0100 Subject: [PATCH 356/777] Add tc police support in TcUtils.java Bug: 157552970 Test: TreeHugger Change-Id: I60be5ea3ac361f4b5d09b8cc2290d10adb18a39f --- .../com/android/net/module/util/TcUtils.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/TcUtils.java b/staticlibs/device/com/android/net/module/util/TcUtils.java index 14724d4628..5b78bc1015 100644 --- a/staticlibs/device/com/android/net/module/util/TcUtils.java +++ b/staticlibs/device/com/android/net/module/util/TcUtils.java @@ -48,6 +48,30 @@ public class TcUtils { public static native void tcFilterAddDevBpf(int ifIndex, boolean ingress, short prio, short proto, String bpfProgPath) throws IOException; + /** + * Attach a tc police action. + * + * Attaches a matchall filter to the clsact qdisc with a tc police and tc bpf action attached. + * This causes the ingress rate to be limited and exceeding packets to be forwarded to a bpf + * program (specified in bpfProgPah) that accounts for the packets before dropping them. + * + * Equivalent to the following 'tc' command: + * tc filter add dev .. ingress prio .. protocol .. matchall \ + * action police rate .. burst .. conform-exceed pipe/continue \ + * action bpf object-pinned .. \ + * drop + * + * @param ifIndex the network interface index. + * @param prio the filter preference. + * @param proto protocol. + * @param rateInBytesPerSec rate limit in bytes/s. + * @param bpfProgPath bpg program that accounts for rate exceeding packets before they are + * dropped. + * @throws IOException + */ + public static native void tcFilterAddDevIngressPolice(int ifIndex, short prio, short proto, + int rateInBytesPerSec, String bpfProgPath) throws IOException; + /** * Delete a tc filter. * From 28c717a03ebf7d34f450cf5a5ad2212df6a1dbb8 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 19 Jan 2022 14:51:35 +0100 Subject: [PATCH 357/777] Move logging helper to own file And rename to ALOGE to be in line with liblog. Test: builds Change-Id: I6c33f78a0649b273f75ebf05ea5ba3689beabc24 --- staticlibs/native/tcutils/logging.h | 35 +++++++++++++++++++++ staticlibs/native/tcutils/tcutils.cpp | 44 +++++++++++---------------- 2 files changed, 53 insertions(+), 26 deletions(-) create mode 100644 staticlibs/native/tcutils/logging.h diff --git a/staticlibs/native/tcutils/logging.h b/staticlibs/native/tcutils/logging.h new file mode 100644 index 0000000000..70604b30af --- /dev/null +++ b/staticlibs/native/tcutils/logging.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#ifndef LOG_TAG +#define LOG_TAG "TcUtils_Undef" +#endif + +namespace android { + +static inline void ALOGE(const char *fmt...) { + va_list args; + va_start(args, fmt); + __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, fmt, args); + va_end(args); +} + +} diff --git a/staticlibs/native/tcutils/tcutils.cpp b/staticlibs/native/tcutils/tcutils.cpp index ad9d9e4ab3..0e17f67c22 100644 --- a/staticlibs/native/tcutils/tcutils.cpp +++ b/staticlibs/native/tcutils/tcutils.cpp @@ -18,10 +18,10 @@ #include "tcutils/tcutils.h" +#include "logging.h" #include "kernelversion.h" #include "scopeguard.h" -#include #include #include #include @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -53,13 +52,6 @@ namespace android { namespace { -void logError(const char *fmt...) { - va_list args; - va_start(args, fmt); - __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, fmt, args); - va_end(args); -} - /** * IngressPoliceFilterBuilder builds a nlmsg request equivalent to the following * tc command: @@ -144,7 +136,7 @@ class IngressPoliceFilterBuilder final { static double getTickInUsec() { FILE *fp = fopen("/proc/net/psched", "re"); if (!fp) { - logError("fopen(\"/proc/net/psched\"): %s", strerror(errno)); + ALOGE("fopen(\"/proc/net/psched\"): %s", strerror(errno)); return 0.0; } auto scopeGuard = base::make_scope_guard([fp] { fclose(fp); }); @@ -156,7 +148,7 @@ class IngressPoliceFilterBuilder final { fscanf(fp, "%08x%08x%08x", &t2us, &us2t, &clockRes) != 3; if (isError) { - logError("fscanf(/proc/net/psched, \"%%08x%%08x%%08x\"): %s", + ALOGE("fscanf(/proc/net/psched, \"%%08x%%08x%%08x\"): %s", strerror(errno)); return 0.0; } @@ -343,7 +335,7 @@ private: mBpfFd = bpf::retrieveProgram(mBpfProgPath); if (mBpfFd == -1) { int error = errno; - logError("retrieveProgram failed: %d", error); + ALOGE("retrieveProgram failed: %d", error); return -error; } @@ -381,7 +373,7 @@ int sendAndProcessNetlinkResponse(const void *req, int len) { int fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); if (fd == -1) { int error = errno; - logError("socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE): %d", + ALOGE("socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE): %d", error); return -error; } @@ -390,7 +382,7 @@ int sendAndProcessNetlinkResponse(const void *req, int len) { static constexpr int on = 1; if (setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &on, sizeof(on))) { int error = errno; - logError("setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, 1): %d", error); + ALOGE("setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, 1): %d", error); return -error; } @@ -398,7 +390,7 @@ int sendAndProcessNetlinkResponse(const void *req, int len) { if (bind(fd, (const struct sockaddr *)&KERNEL_NLADDR, sizeof(KERNEL_NLADDR))) { int error = errno; - logError("bind(fd, {AF_NETLINK, 0, 0}: %d)", error); + ALOGE("bind(fd, {AF_NETLINK, 0, 0}: %d)", error); return -error; } @@ -406,7 +398,7 @@ int sendAndProcessNetlinkResponse(const void *req, int len) { if (connect(fd, (const struct sockaddr *)&KERNEL_NLADDR, sizeof(KERNEL_NLADDR))) { int error = errno; - logError("connect(fd, {AF_NETLINK, 0, 0}): %d", error); + ALOGE("connect(fd, {AF_NETLINK, 0, 0}): %d", error); return -error; } @@ -414,12 +406,12 @@ int sendAndProcessNetlinkResponse(const void *req, int len) { if (rv == -1) { int error = errno; - logError("send(fd, req, len, 0) failed: %d", error); + ALOGE("send(fd, req, len, 0) failed: %d", error); return -error; } if (rv != len) { - logError("send(fd, req, len = %d, 0) returned invalid message size %d", len, + ALOGE("send(fd, req, len = %d, 0) returned invalid message size %d", len, rv); return -EMSGSIZE; } @@ -434,29 +426,29 @@ int sendAndProcessNetlinkResponse(const void *req, int len) { if (rv == -1) { int error = errno; - logError("recv() failed: %d", error); + ALOGE("recv() failed: %d", error); return -error; } if (rv < (int)NLMSG_SPACE(sizeof(struct nlmsgerr))) { - logError("recv() returned short packet: %d", rv); + ALOGE("recv() returned short packet: %d", rv); return -EBADMSG; } if (resp.h.nlmsg_len != (unsigned)rv) { - logError("recv() returned invalid header length: %d != %d", + ALOGE("recv() returned invalid header length: %d != %d", resp.h.nlmsg_len, rv); return -EBADMSG; } if (resp.h.nlmsg_type != NLMSG_ERROR) { - logError("recv() did not return NLMSG_ERROR message: %d", + ALOGE("recv() did not return NLMSG_ERROR message: %d", resp.h.nlmsg_type); return -ENOMSG; } if (resp.e.error) { - logError("NLMSG_ERROR message return error: %d", resp.e.error); + ALOGE("NLMSG_ERROR message return error: %d", resp.e.error); } return resp.e.error; // returns 0 on success } @@ -487,7 +479,7 @@ int hardwareAddressType(const char *interface) { int isEthernet(const char *iface, bool &isEthernet) { int rv = hardwareAddressType(iface); if (rv < 0) { - logError("Get hardware address type of interface %s failed: %s", iface, + ALOGE("Get hardware address type of interface %s failed: %s", iface, strerror(-rv)); return rv; } @@ -521,7 +513,7 @@ int isEthernet(const char *iface, bool &isEthernet) { isEthernet = false; return 0; default: - logError("Unknown hardware address type %d on interface %s", rv, iface); + ALOGE("Unknown hardware address type %d on interface %s", rv, iface); return -EAFNOSUPPORT; } } @@ -580,7 +572,7 @@ int tcAddBpfFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto, const char *bpfProgPath) { const int bpfFd = bpf::retrieveProgram(bpfProgPath); if (bpfFd == -1) { - logError("retrieveProgram failed: %d", errno); + ALOGE("retrieveProgram failed: %d", errno); return -errno; } auto scopeGuard = base::make_scope_guard([bpfFd] { close(bpfFd); }); From 76ee6106f50c134dd37465ef68a014070af859fd Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Sat, 15 Jan 2022 01:11:53 +0800 Subject: [PATCH 358/777] Add libnettestutils as a networking test utility The library provides a helper function that can retrieve dumpsys results from a specific service. It can also take dumpsys arguments. Bug: 29761778 Bug: 202086915 Test: test in Ib4aeb385ab80187feb39b659274a0aee20a4a5ed Change-Id: Ib2ab8b6e4136bd3cbc52b025e53a1fa0c4e91709 --- staticlibs/native/nettestutils/Android.bp | 28 +++++++++ .../native/nettestutils/DumpService.cpp | 57 +++++++++++++++++++ .../include/nettestutils/DumpService.h | 23 ++++++++ 3 files changed, 108 insertions(+) create mode 100644 staticlibs/native/nettestutils/Android.bp create mode 100644 staticlibs/native/nettestutils/DumpService.cpp create mode 100644 staticlibs/native/nettestutils/include/nettestutils/DumpService.h diff --git a/staticlibs/native/nettestutils/Android.bp b/staticlibs/native/nettestutils/Android.bp new file mode 100644 index 0000000000..4fa367d4be --- /dev/null +++ b/staticlibs/native/nettestutils/Android.bp @@ -0,0 +1,28 @@ +// 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. + +cc_library_static { + name: "libnettestutils", + export_include_dirs: ["include"], + srcs: ["DumpService.cpp"], + + shared_libs: [ + "libbinder", + "libutils", + ], + cflags: [ + "-Werror", + "-Wall", + ], +} diff --git a/staticlibs/native/nettestutils/DumpService.cpp b/staticlibs/native/nettestutils/DumpService.cpp new file mode 100644 index 0000000000..ba3d77e941 --- /dev/null +++ b/staticlibs/native/nettestutils/DumpService.cpp @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#include "nettestutils/DumpService.h" + +#include + +#include +#include + +android::status_t dumpService(const android::sp& binder, + const std::vector& args, + std::vector& outputLines) { + if (!outputLines.empty()) return -EUCLEAN; + + android::base::unique_fd localFd, remoteFd; + if (!Pipe(&localFd, &remoteFd)) return -errno; + + android::Vector str16Args; + for (const auto& arg : args) { + str16Args.push(android::String16(arg.c_str())); + } + android::status_t ret; + // dump() blocks until another thread has consumed all its output. + std::thread dumpThread = + std::thread([&ret, binder, remoteFd{std::move(remoteFd)}, str16Args]() { + ret = binder->dump(remoteFd, str16Args); + }); + + std::string dumpContent; + if (!android::base::ReadFdToString(localFd.get(), &dumpContent)) { + return -errno; + } + dumpThread.join(); + if (ret != android::OK) return ret; + + std::stringstream dumpStream(std::move(dumpContent)); + std::string line; + while (std::getline(dumpStream, line)) { + outputLines.push_back(line); + } + + return android::OK; +} diff --git a/staticlibs/native/nettestutils/include/nettestutils/DumpService.h b/staticlibs/native/nettestutils/include/nettestutils/DumpService.h new file mode 100644 index 0000000000..2a721817a3 --- /dev/null +++ b/staticlibs/native/nettestutils/include/nettestutils/DumpService.h @@ -0,0 +1,23 @@ +/* + * 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. + */ + +#include + +#include + +android::status_t dumpService(const android::sp& binder, + const std::vector& args, + std::vector& outputLines); From c9232670c2799a584836caa7e5975a417525002d Mon Sep 17 00:00:00 2001 From: Kimberly Kreider Date: Tue, 16 Nov 2021 00:22:34 +0000 Subject: [PATCH 359/777] Update net-tests-utils-host-common tag to "mts-networking" We use "mts-networking" and not "mts" so that the tests and test dependencies can be properly included in the automated MTS packaging and release (go/mts-packaging). Instead of tagging tests "mts", we should use "mts-*" where the suffix is one of https://source.corp.google.com/android/test/mts/tools/build/config.mk;l=19. Test: built locally and verified contents Bug: 203466102 Change-Id: I5f9bdaf699cfa2525b33178c0e30a6b794b9d5f5 --- staticlibs/testutils/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index 9fd30f7001..73ddd4b204 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -69,6 +69,6 @@ java_test_host { "host/**/*.kt", ], libs: ["tradefed"], - test_suites: ["device-tests", "general-tests", "cts", "mts"], + test_suites: ["device-tests", "general-tests", "cts", "mts-networking"], data: [":ConnectivityChecker"], } From 3e6dd45b85ae489101678f24cda59c43c045c4a6 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Fri, 7 Jan 2022 16:00:27 +0800 Subject: [PATCH 360/777] Update case to correctly support usage for T Update condition to correctly support the usage for T. Also update the S code since it was updated to corresponding number. Bug: 215294242 Test: test using DevSdkIgnoreRule Change-Id: Ia94cb7f5a0aaf92515e5e2b924d1ab6cc050e074 --- .../com/android/testutils/DevSdkIgnoreRule.kt | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt index 201bf2d2e8..8b58e7171c 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt @@ -18,11 +18,15 @@ package com.android.testutils import android.os.Build import com.android.modules.utils.build.SdkLevel +import kotlin.test.fail import org.junit.Assume.assumeTrue import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement +// TODO: Remove it when Build.VERSION_CODES.SC_V2 is available +const val SC_V2 = 32 + /** * Returns true if the development SDK version of the device is in the provided range. * @@ -40,8 +44,10 @@ private fun isDevSdkAfter(minExclusive: Int): Boolean { // For recent SDKs that still have development builds used for testing, use SdkLevel utilities // instead of SDK_INT. return when (minExclusive) { - // TODO: use Build.VERSION_CODES.S when it is not CURRENT_DEVELOPMENT - 31 -> SdkLevel.isAtLeastT() + // TODO: Use Build.VERSION_CODES.SC_V2 when it is available + SC_V2 -> SdkLevel.isAtLeastT() + // TODO: To use SdkLevel.isAtLeastSv2 when available + Build.VERSION_CODES.S -> fail("Do you expect to ignore the test until T? Use SC_V2 instead") Build.VERSION_CODES.R -> SdkLevel.isAtLeastS() // Development builds of SDK versions <= R are not used anymore else -> Build.VERSION.SDK_INT > minExclusive @@ -50,8 +56,11 @@ private fun isDevSdkAfter(minExclusive: Int): Boolean { private fun isDevSdkUpTo(maxInclusive: Int): Boolean { return when (maxInclusive) { - // TODO: use Build.VERSION_CODES.S when it is not CURRENT_DEVELOPMENT - 31 -> !SdkLevel.isAtLeastT() + // TODO: Use Build.VERSION_CODES.SC_V2 when it is available + SC_V2 -> !SdkLevel.isAtLeastT() + // TODO: To use SdkLevel.isAtLeastSv2 when available + Build.VERSION_CODES.S -> + fail("Do you expect to ignore the test before T? Use SC_V2 instead") Build.VERSION_CODES.R -> !SdkLevel.isAtLeastS() // Development builds of SDK versions <= R are not used anymore else -> Build.VERSION.SDK_INT <= maxInclusive From b48a1205be045c7efdce8504d3c2384aefef768f Mon Sep 17 00:00:00 2001 From: Wayne Ma Date: Tue, 18 Jan 2022 18:20:24 +0800 Subject: [PATCH 361/777] Move NetlinkListener relevant files to frameworks/libs/net NetlinkListener is used by Netd, so move it to frameworks/libs/net and then it can be used by platform code and mainline module. Bug: 209935649 Test: m; flash; boot Change-Id: I4cf0e64eee1dda1e452d76af77642416c9729d42 --- staticlibs/netd/libnetdutils/Android.bp | 1 + .../netd/libnetdutils/NetlinkListener.cpp | 152 ++++++++++++++++++ .../include/netdutils/NetlinkListener.h | 105 ++++++++++++ 3 files changed, 258 insertions(+) create mode 100644 staticlibs/netd/libnetdutils/NetlinkListener.cpp create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/NetlinkListener.h diff --git a/staticlibs/netd/libnetdutils/Android.bp b/staticlibs/netd/libnetdutils/Android.bp index 732e37d90a..08d5412158 100644 --- a/staticlibs/netd/libnetdutils/Android.bp +++ b/staticlibs/netd/libnetdutils/Android.bp @@ -11,6 +11,7 @@ cc_library { "Log.cpp", "Netfilter.cpp", "Netlink.cpp", + "NetlinkListener.cpp", "Slice.cpp", "Socket.cpp", "SocketOption.cpp", diff --git a/staticlibs/netd/libnetdutils/NetlinkListener.cpp b/staticlibs/netd/libnetdutils/NetlinkListener.cpp new file mode 100644 index 0000000000..decaa9c88b --- /dev/null +++ b/staticlibs/netd/libnetdutils/NetlinkListener.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "NetlinkListener" + +#include +#include + +#include + +#include +#include +#include +#include + +namespace android { +namespace netdutils { + +using netdutils::Fd; +using netdutils::Slice; +using netdutils::Status; +using netdutils::UniqueFd; +using netdutils::findWithDefault; +using netdutils::forEachNetlinkMessage; +using netdutils::makeSlice; +using netdutils::sSyscalls; +using netdutils::status::ok; +using netdutils::statusFromErrno; + +namespace { + +constexpr int kNetlinkMsgErrorType = (NFNL_SUBSYS_NONE << 8) | NLMSG_ERROR; + +constexpr sockaddr_nl kKernelAddr = { + .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = 0, +}; + +const NetlinkListener::DispatchFn kDefaultDispatchFn = [](const nlmsghdr& nlmsg, const Slice) { + std::stringstream ss; + ss << nlmsg; + ALOGE("unhandled netlink message: %s", ss.str().c_str()); +}; + +} // namespace + +NetlinkListener::NetlinkListener(UniqueFd event, UniqueFd sock, const std::string& name) + : mEvent(std::move(event)), mSock(std::move(sock)), mThreadName(name) { + const auto rxErrorHandler = [](const nlmsghdr& nlmsg, const Slice msg) { + std::stringstream ss; + ss << nlmsg << " " << msg << " " << netdutils::toHex(msg, 32); + ALOGE("unhandled netlink message: %s", ss.str().c_str()); + }; + expectOk(NetlinkListener::subscribe(kNetlinkMsgErrorType, rxErrorHandler)); + + mErrorHandler = [& name = mThreadName](const int fd, const int err) { + ALOGE("Error on NetlinkListener(%s) fd=%d: %s", name.c_str(), fd, strerror(err)); + }; + + // Start the thread + mWorker = std::thread([this]() { run().ignoreError(); }); +} + +NetlinkListener::~NetlinkListener() { + const auto& sys = sSyscalls.get(); + const uint64_t data = 1; + // eventfd should never enter an error state unexpectedly + expectOk(sys.write(mEvent, makeSlice(data)).status()); + mWorker.join(); +} + +Status NetlinkListener::send(const Slice msg) { + const auto& sys = sSyscalls.get(); + ASSIGN_OR_RETURN(auto sent, sys.sendto(mSock, msg, 0, kKernelAddr)); + if (sent != msg.size()) { + return statusFromErrno(EMSGSIZE, "unexpect message size"); + } + return ok; +} + +Status NetlinkListener::subscribe(uint16_t type, const DispatchFn& fn) { + std::lock_guard guard(mMutex); + mDispatchMap[type] = fn; + return ok; +} + +Status NetlinkListener::unsubscribe(uint16_t type) { + std::lock_guard guard(mMutex); + mDispatchMap.erase(type); + return ok; +} + +void NetlinkListener::registerSkErrorHandler(const SkErrorHandler& handler) { + mErrorHandler = handler; +} + +Status NetlinkListener::run() { + std::vector rxbuf(4096); + + const auto rxHandler = [this](const nlmsghdr& nlmsg, const Slice& buf) { + std::lock_guard guard(mMutex); + const auto& fn = findWithDefault(mDispatchMap, nlmsg.nlmsg_type, kDefaultDispatchFn); + fn(nlmsg, buf); + }; + + if (mThreadName.length() > 0) { + int ret = pthread_setname_np(pthread_self(), mThreadName.c_str()); + if (ret) { + ALOGE("thread name set failed, name: %s, ret: %s", mThreadName.c_str(), strerror(ret)); + } + } + const auto& sys = sSyscalls.get(); + const std::array fds{{{mEvent}, {mSock}}}; + const int events = POLLIN; + const double timeout = 3600; + while (true) { + ASSIGN_OR_RETURN(auto revents, sys.ppoll(fds, events, timeout)); + // After mEvent becomes readable, we should stop servicing mSock and return + if (revents[0] & POLLIN) { + break; + } + if (revents[1] & (POLLIN|POLLERR)) { + auto rx = sys.recvfrom(mSock, makeSlice(rxbuf), 0); + int err = rx.status().code(); + if (err) { + // Ignore errors. The only error we expect to see here is ENOBUFS, and there's + // nothing we can do about that. The recvfrom above will already have cleared the + // error indication and ensured we won't get EPOLLERR again. + // TODO: Consider using NETLINK_NO_ENOBUFS. + mErrorHandler(((Fd) mSock).get(), err); + continue; + } + forEachNetlinkMessage(rx.value(), rxHandler); + } + } + return ok; +} + +} // namespace netdutils +} // namespace android diff --git a/staticlibs/netd/libnetdutils/include/netdutils/NetlinkListener.h b/staticlibs/netd/libnetdutils/include/netdutils/NetlinkListener.h new file mode 100644 index 0000000000..97f7bb2357 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/NetlinkListener.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef NETLINK_LISTENER_H +#define NETLINK_LISTENER_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace android { +namespace netdutils { + +class NetlinkListenerInterface { + public: + using DispatchFn = std::function; + + using SkErrorHandler = std::function; + + virtual ~NetlinkListenerInterface() = default; + + // Send message to the kernel using the underlying netlink socket + virtual netdutils::Status send(const netdutils::Slice msg) = 0; + + // Deliver future messages with nlmsghdr.nlmsg_type == type to fn. + // + // Threadsafe. + // All dispatch functions invoked on a single service thread. + // subscribe() and join() must not be called from the stack of fn(). + virtual netdutils::Status subscribe(uint16_t type, const DispatchFn& fn) = 0; + + // Halt delivery of future messages with nlmsghdr.nlmsg_type == type. + // Threadsafe. + virtual netdutils::Status unsubscribe(uint16_t type) = 0; + + virtual void registerSkErrorHandler(const SkErrorHandler& handler) = 0; +}; + +// NetlinkListener manages a netlink socket and associated blocking +// service thread. +// +// This class is written in a generic way to allow multiple different +// netlink subsystems to share this common infrastructure. If multiple +// subsystems share the same message delivery requirements (drops ok, +// no drops) they may share a single listener by calling subscribe() +// with multiple types. +// +// This class is suitable for moderate performance message +// processing. In particular it avoids extra copies of received +// message data and allows client code to control which message +// attributes are processed. +// +// Note that NetlinkListener is capable of processing multiple batched +// netlink messages in a single system call. This is useful to +// netfilter extensions that allow batching of events like NFLOG. +class NetlinkListener : public NetlinkListenerInterface { + public: + NetlinkListener(netdutils::UniqueFd event, netdutils::UniqueFd sock, const std::string& name); + + ~NetlinkListener() override; + + netdutils::Status send(const netdutils::Slice msg) override; + + netdutils::Status subscribe(uint16_t type, const DispatchFn& fn) override EXCLUDES(mMutex); + + netdutils::Status unsubscribe(uint16_t type) override EXCLUDES(mMutex); + + void registerSkErrorHandler(const SkErrorHandler& handler) override; + + private: + netdutils::Status run(); + + const netdutils::UniqueFd mEvent; + const netdutils::UniqueFd mSock; + const std::string mThreadName; + std::mutex mMutex; + std::map mDispatchMap GUARDED_BY(mMutex); + std::thread mWorker; + SkErrorHandler mErrorHandler; +}; + +} // namespace netdutils +} // namespace android + +#endif /* NETLINK_LISTENER_H */ From 3e5e525165e4782d58027372cd1702125ea69667 Mon Sep 17 00:00:00 2001 From: Tyler Wear Date: Thu, 20 Jan 2022 09:04:56 -0800 Subject: [PATCH 362/777] Add U32 S64 subclasses to Struct BPF maps require classes to extend struct. Adding U32 and S64 classes to be used in QoS and BpfBitmaps. Bug: 202871011 Change-Id: Idc0660240fafba0b199772b100ff69c362599403 --- .../com/android/net/module/util/Struct.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/Struct.java b/staticlibs/device/com/android/net/module/util/Struct.java index b43e2c458e..f4d4163589 100644 --- a/staticlibs/device/com/android/net/module/util/Struct.java +++ b/staticlibs/device/com/android/net/module/util/Struct.java @@ -730,4 +730,22 @@ public class Struct { } return sb.toString(); } + + public static class U32 extends Struct { + @Struct.Field(order = 0, type = Struct.Type.U32) + public final long val; + + public U32(final long val) { + this.val = val; + } + } + + public static class S64 extends Struct { + @Struct.Field(order = 0, type = Struct.Type.S64) + public final long val; + + public S64(final long val) { + this.val = val; + } + } } From ee9f5afef5793ae06529e947becf83a09fa76834 Mon Sep 17 00:00:00 2001 From: Tyler Wear Date: Wed, 12 Jan 2022 16:19:23 -0800 Subject: [PATCH 363/777] Add DSCP Status Callback to TestableNetworkAgent Add new callback for Dscp status's. Test: atest DscpPolicyTest Change-Id: Ib47c246e3f92045ca32b681b380315dfdfedc182 --- .../com/android/testutils/TestableNetworkAgent.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkAgent.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkAgent.kt index 40fb773338..a96f78b26c 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkAgent.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkAgent.kt @@ -30,6 +30,7 @@ import com.android.net.module.util.ArrayTrackRecord import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnAddKeepalivePacketFilter import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnAutomaticReconnectDisabled import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnBandwidthUpdateRequested +import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnDscpPolicyStatusUpdated import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkCreated import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkDestroyed import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkUnwanted @@ -89,6 +90,7 @@ public open class TestableNetworkAgent( data class OnSignalStrengthThresholdsUpdated(val thresholds: IntArray) : CallbackEntry() object OnNetworkCreated : CallbackEntry() object OnNetworkDestroyed : CallbackEntry() + data class OnDscpPolicyStatusUpdated(val policyId: Int, val status: Int) : CallbackEntry() data class OnRegisterQosCallback( val callbackId: Int, val filter: QosFilter @@ -162,6 +164,10 @@ public open class TestableNetworkAgent( history.add(OnNetworkDestroyed) } + fun onDscpPolicyStatusUpdated(policyId: Int, status: Int) { + history.add(OnDscpPolicyStatusUpdated(policyId, status)) + } + // Expects the initial validation event that always occurs immediately after registering // a NetworkAgent whose network does not require validation (which test networks do // not, since they lack the INTERNET capability). It always contains the default argument From 56875455c258f8b0ff95258233038517233440f7 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Tue, 18 Jan 2022 21:27:50 -0800 Subject: [PATCH 364/777] Add BPF_ANNOTATE_KV_PAIR to BPF map definition macros BPF_ANNOTATE_KV_PAIR is used by libbpf to associate each map with its BTF information. This is ignored for programs compiled without BTF information. Bug: 203823368 Test: build & boot; confirm all bpf progs load successfully Test: compile time_in_state.o with -g; confirm BTF is loaded Signed-off-by: Connor O'Brien Change-Id: I45f294945d48106d39d1d105ac4f49311459a19d --- .../native/bpf_headers/include/bpf/bpf_helpers.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 878bb103a0..ac9f9bcb18 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -116,6 +116,15 @@ static int (*bpf_map_update_elem_unsafe)(const struct bpf_map_def* map, const vo static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, const void* key) = (void*)BPF_FUNC_map_delete_elem; +#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val) \ + struct ____btf_map_##name { \ + type_key key; \ + type_val value; \ + }; \ + struct ____btf_map_##name \ + __attribute__ ((section(".maps." #name), used)) \ + ____btf_map_##name = { } + /* type safe macro to declare a map and related accessor functions */ #define DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, usr, grp, md) \ const struct bpf_map_def SECTION("maps") the_map = { \ @@ -132,6 +141,7 @@ static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, .min_kver = KVER_NONE, \ .max_kver = KVER_INF, \ }; \ + BPF_ANNOTATE_KV_PAIR(the_map, TypeOfKey, TypeOfValue); \ \ static inline __always_inline __unused TypeOfValue* bpf_##the_map##_lookup_elem( \ const TypeOfKey* k) { \ From 2e5fece3bf53f5a4244d65aef2221216f55accf3 Mon Sep 17 00:00:00 2001 From: markchien Date: Fri, 21 Jan 2022 10:16:54 +0800 Subject: [PATCH 365/777] Add IBpfMap for injection in testing To avoid load jni library in some testing (BpfMap load jni library statically), add IBpfMap for injection. Bug: 215095957 Test: atest FrameworkNetTests Change-Id: I71e67f9cdc19a856fe5dce5940be702e866b87c4 --- staticlibs/Android.bp | 1 + .../com/android/net/module/util/BpfMap.java | 14 +++- .../com/android/net/module/util/IBpfMap.java | 74 +++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 staticlibs/device/com/android/net/module/util/IBpfMap.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index ea38eca46c..16fede80f7 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -111,6 +111,7 @@ java_library { name: "net-utils-device-common-bpf", srcs: [ "device/com/android/net/module/util/BpfMap.java", + "device/com/android/net/module/util/IBpfMap.java", "device/com/android/net/module/util/JniUtil.java", "device/com/android/net/module/util/TcUtils.java", ], diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java index 5f05c7c90b..b42c388523 100644 --- a/staticlibs/device/com/android/net/module/util/BpfMap.java +++ b/staticlibs/device/com/android/net/module/util/BpfMap.java @@ -40,7 +40,7 @@ import java.util.function.BiConsumer; * @param the key of the map. * @param the value of the map. */ -public class BpfMap implements AutoCloseable { +public class BpfMap implements IBpfMap, AutoCloseable { static { System.loadLibrary(JniUtil.getJniLibraryName(BpfMap.class.getPackage())); } @@ -100,6 +100,7 @@ public class BpfMap implements AutoCloseable * Update an existing or create a new key -> value entry in an eBbpf map. * (use insertOrReplaceEntry() if you need to know whether insert or replace happened) */ + @Override public void updateEntry(K key, V value) throws ErrnoException { writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_ANY); } @@ -108,6 +109,7 @@ public class BpfMap implements AutoCloseable * If the key does not exist in the map, insert key -> value entry into eBpf map. * Otherwise IllegalStateException will be thrown. */ + @Override public void insertEntry(K key, V value) throws ErrnoException, IllegalStateException { try { @@ -123,6 +125,7 @@ public class BpfMap implements AutoCloseable * If the key already exists in the map, replace its value. Otherwise NoSuchElementException * will be thrown. */ + @Override public void replaceEntry(K key, V value) throws ErrnoException, NoSuchElementException { try { @@ -140,6 +143,7 @@ public class BpfMap implements AutoCloseable * (use updateEntry() if you don't care whether insert or replace happened) * Note: see inline comment below if running concurrently with delete operations. */ + @Override public boolean insertOrReplaceEntry(K key, V value) throws ErrnoException { try { @@ -164,11 +168,13 @@ public class BpfMap implements AutoCloseable } /** Remove existing key from eBpf map. Return false if map was not modified. */ + @Override public boolean deleteEntry(K key) throws ErrnoException { return deleteMapEntry(mMapFd, key.writeToBytes()); } /** Returns {@code true} if this map contains no elements. */ + @Override public boolean isEmpty() throws ErrnoException { return getFirstKey() == null; } @@ -189,6 +195,7 @@ public class BpfMap implements AutoCloseable * * TODO: consider allowing null passed-in key. */ + @Override public K getNextKey(@NonNull K key) throws ErrnoException { Objects.requireNonNull(key); return getNextKeyInternal(key); @@ -202,11 +209,13 @@ public class BpfMap implements AutoCloseable } /** Get the first key of eBpf map. */ + @Override public K getFirstKey() throws ErrnoException { return getNextKeyInternal(null); } /** Check whether a key exists in the map. */ + @Override public boolean containsKey(@NonNull K key) throws ErrnoException { Objects.requireNonNull(key); @@ -215,6 +224,7 @@ public class BpfMap implements AutoCloseable } /** Retrieve a value from the map. Return null if there is no such key. */ + @Override public V getValue(@NonNull K key) throws ErrnoException { Objects.requireNonNull(key); final byte[] rawValue = getRawValue(key.writeToBytes()); @@ -239,6 +249,7 @@ public class BpfMap implements AutoCloseable * other structural modifications to the map, such as adding entries or deleting other entries. * Otherwise, iteration will result in undefined behaviour. */ + @Override public void forEach(BiConsumer action) throws ErrnoException { @Nullable K nextKey = getFirstKey(); @@ -262,6 +273,7 @@ public class BpfMap implements AutoCloseable * @throws ErrnoException if the map is already closed, if an error occurred during iteration, * or if a non-ENOENT error occurred when deleting a key. */ + @Override public void clear() throws ErrnoException { K key = getFirstKey(); while (key != null) { diff --git a/staticlibs/device/com/android/net/module/util/IBpfMap.java b/staticlibs/device/com/android/net/module/util/IBpfMap.java new file mode 100644 index 0000000000..708cf61a80 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/IBpfMap.java @@ -0,0 +1,74 @@ +/* + * 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 com.android.net.module.util; + +import android.system.ErrnoException; + +import androidx.annotation.NonNull; + +import java.util.NoSuchElementException; +import java.util.function.BiConsumer; + +/** + * The interface of BpfMap. This could be used to inject for testing. + * So the testing code won't load the JNI and update the entries to kernel. + * + * @param the key of the map. + * @param the value of the map. + */ +public interface IBpfMap { + /** Update an existing or create a new key -> value entry in an eBbpf map. */ + void updateEntry(K key, V value) throws ErrnoException; + + /** If the key does not exist in the map, insert key -> value entry into eBpf map. */ + void insertEntry(K key, V value) throws ErrnoException, IllegalStateException; + + /** If the key already exists in the map, replace its value. */ + void replaceEntry(K key, V value) throws ErrnoException, NoSuchElementException; + + /** + * Update an existing or create a new key -> value entry in an eBbpf map. Returns true if + * inserted, false if replaced. (use updateEntry() if you don't care whether insert or replace + * happened). + */ + boolean insertOrReplaceEntry(K key, V value) throws ErrnoException; + + /** Remove existing key from eBpf map. Return true if something was deleted. */ + boolean deleteEntry(K key) throws ErrnoException; + + /** Returns {@code true} if this map contains no elements. */ + boolean isEmpty() throws ErrnoException; + + /** Get the key after the passed-in key. */ + K getNextKey(@NonNull K key) throws ErrnoException; + + /** Get the first key of the eBpf map. */ + K getFirstKey() throws ErrnoException; + + /** Check whether a key exists in the map. */ + boolean containsKey(@NonNull K key) throws ErrnoException; + + /** Retrieve a value from the map. */ + V getValue(@NonNull K key) throws ErrnoException; + + /** + * Iterate through the map and handle each key -> value retrieved base on the given BiConsumer. + */ + void forEach(BiConsumer action) throws ErrnoException; + + /** Clears the map. */ + void clear() throws ErrnoException; +} From 32a6e9cbde86afba574f8b00e27c177a88f6da0c Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 20 Jan 2022 14:34:15 +0800 Subject: [PATCH 366/777] Add visibility for use bpfmap by BpfInterfaceMapUpdater Bug: 215095957 Test: m Change-Id: Idbb8e3cbf520a29444ccdfd2d1c42553c886a7f0 --- staticlibs/Android.bp | 2 ++ staticlibs/native/bpfmapjni/Android.bp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 16fede80f7..f1dbbcd4c0 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -122,6 +122,7 @@ java_library { "//frameworks/libs/net/common/testutils:__subpackages__", "//packages/modules/Connectivity:__subpackages__", "//packages/modules/NetworkStack:__subpackages__", + "//frameworks/base/services/core", ], static_libs: [ "net-utils-device-common-struct", @@ -279,6 +280,7 @@ java_library { "framework-connectivity", ], visibility: [ + // TODO: remove after NetworkStatsService moves to the module. "//frameworks/base/services/net", "//packages/modules/Connectivity/tests:__subpackages__", ], diff --git a/staticlibs/native/bpfmapjni/Android.bp b/staticlibs/native/bpfmapjni/Android.bp index 8d3c90b0a5..e4d337a4e1 100644 --- a/staticlibs/native/bpfmapjni/Android.bp +++ b/staticlibs/native/bpfmapjni/Android.bp @@ -46,5 +46,7 @@ cc_library_static { ], visibility: [ "//packages/modules/Connectivity:__subpackages__", + // TODO: remove after NetworkStatsService moves to the module. + "//frameworks/base/packages/ConnectivityT/service", ], } From 580cabf981f2fc4da85ff828e2b94f8b9bee840b Mon Sep 17 00:00:00 2001 From: Tyler Wear Date: Fri, 21 Jan 2022 11:32:35 -0800 Subject: [PATCH 367/777] Add Override for onDscpPolicyStatusUpdated Add override to allow for DscpPolicyTest to use updated NetworkAgent callbacks. Bug: 202871011 Change-Id: I2082f6553e56ff941a309e031184d6e0dfb88514 --- .../devicetests/com/android/testutils/TestableNetworkAgent.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkAgent.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkAgent.kt index a96f78b26c..8dc1bc45f9 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkAgent.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkAgent.kt @@ -164,7 +164,7 @@ public open class TestableNetworkAgent( history.add(OnNetworkDestroyed) } - fun onDscpPolicyStatusUpdated(policyId: Int, status: Int) { + override fun onDscpPolicyStatusUpdated(policyId: Int, status: Int) { history.add(OnDscpPolicyStatusUpdated(policyId, status)) } @@ -203,4 +203,4 @@ public open class TestableNetworkAgent( "Handler didn't became idle after ${DEFAULT_TIMEOUT_MS}ms") assertNull(history.peek()) } -} \ No newline at end of file +} From 945c8b263846e5523f98fab87429bbac823e9178 Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Sun, 23 Jan 2022 15:31:08 +0800 Subject: [PATCH 368/777] Clean up bpf_headers visibility The bpf_headers no need to explicitly specify visibility for system/netd/libnetdbpf. The libnetdbpf depends on bpf_connectivity_headers, which exports bpf_headers already. Bug: 202086915 Test: m Change-Id: I09a073b14dc74511ba9dc09a89ae6e89dff51f4d --- staticlibs/native/bpf_headers/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/staticlibs/native/bpf_headers/Android.bp b/staticlibs/native/bpf_headers/Android.bp index af8ec73b49..a9f69842ac 100644 --- a/staticlibs/native/bpf_headers/Android.bp +++ b/staticlibs/native/bpf_headers/Android.bp @@ -52,7 +52,6 @@ cc_library_headers { "//system/bpf/bpfloader", "//system/bpf/libbpf_android", "//system/memory/libmeminfo", - "//system/netd/libnetdbpf", "//system/netd/server", "//system/netd/tests", "//system/netd/tests/benchmarks", From d79ffcf3ceb6ca4dda7fd5995566c494e61af17b Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 10 Jan 2022 10:31:11 +0000 Subject: [PATCH 369/777] [MS48.3] Allow Settings package to build with network static libs Settings app used NetworkStatsHistory#getValues to fetch rational bytes of the history. However, this functionality will not be available after mainling NetworkStats. Thus, allow Settings to build with NetworkStatsUtils for implementing alternative solution. Test: atest clockwork-settings-robotests make RunSettingsRoboTests -j40 make RunSettingsLibRoboTests ROBOTEST_FILTER=DataUsageControllerTest make RunSettingsLibRoboTests ROBOTEST_FILTER=NetworkCycleChartDataLoaderTest make RunSettingsLibRoboTests ROBOTEST_FILTER=NetworkCycleDataForUidLoaderTest make RunSettingsLibRoboTests ROBOTEST_FILTER=NetworkCycleDataLoaderTest make RunSettingsLibRoboTests ROBOTEST_FILTER=DataUsageUtilsTest Bug: 204830222 Ignore-AOSP-First: Related API conflict, need master first. Change-Id: I8f8b6160fdc78ee91e4ce84c07faef3a0408e489 --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index ea38eca46c..bd828e929a 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -247,6 +247,7 @@ java_library { "//frameworks/libs/net/common/tests:__subpackages__", "//frameworks/libs/net/common/device", "//packages/modules/Wifi/framework/tests:__subpackages__", + "//packages/apps/Settings", ], lint: { strict_updatability_linting: true }, } From be96036a63e6b7adc80253d8cb4174c8e56fb0e2 Mon Sep 17 00:00:00 2001 From: markchien Date: Sat, 22 Jan 2022 15:10:26 +0800 Subject: [PATCH 370/777] Decouple "net-utils-framework-common" from "net-utils-device-common-bpf" Currently "net-utils-device-common-bpf" statically link whole "net-utils-device-common-struct" which would also pull in "net-utils-framework-common". Since the classes in net-utils-framework-common would be loaded into bootclass path, it would cause sytem server service which located in platform code (the class in /system/framework/service.jar) not able to use net-utils-device-common-bpf library. There is a cts to protect this: StrictJavaPackagesTest#testBootClasspathAndSystemServerClasspath_nonDuplicateClasses Bug: 215095957 Test: atest FrameworkNetTests Change-Id: I232bd21c666dd44f7d0b8cc84610e8cd37dc383c --- staticlibs/Android.bp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index f1dbbcd4c0..ba545eae40 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -111,8 +111,10 @@ java_library { name: "net-utils-device-common-bpf", srcs: [ "device/com/android/net/module/util/BpfMap.java", + "device/com/android/net/module/util/HexDump.java", "device/com/android/net/module/util/IBpfMap.java", "device/com/android/net/module/util/JniUtil.java", + "device/com/android/net/module/util/Struct.java", "device/com/android/net/module/util/TcUtils.java", ], sdk_version: "system_current", @@ -124,9 +126,6 @@ java_library { "//packages/modules/NetworkStack:__subpackages__", "//frameworks/base/services/core", ], - static_libs: [ - "net-utils-device-common-struct", - ], libs: [ "androidx.annotation_annotation", ], From 375241c99b496a34cd3aa324a4f4381198d2b6d9 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 11 Jan 2022 10:30:07 +0900 Subject: [PATCH 371/777] Add a DumpTestUtils class to do service dumps in tests. This allows tests to run dumpsys without worrying too much about the nitty-gritty of finding the service, piping the output back, etc. Test: simple test added in other CL in topic Change-Id: I0628c55ad199e4c888e4947e11bdb0a3b8150767 --- staticlibs/testutils/Android.bp | 1 + .../com/android/testutils/DumpTestUtils.java | 129 ++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/DumpTestUtils.java diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index 133c9833fc..2dda269d73 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -31,6 +31,7 @@ java_library { ], static_libs: [ "androidx.test.ext.junit", + "compatibility-device-util-axt", "kotlin-reflect", "libnanohttpd", "net-tests-utils-host-device-common", diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DumpTestUtils.java b/staticlibs/testutils/devicetests/com/android/testutils/DumpTestUtils.java new file mode 100644 index 0000000000..f2ad1e27e5 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/DumpTestUtils.java @@ -0,0 +1,129 @@ +/* + * 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 com.android.testutils; + +import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.system.ErrnoException; +import android.system.Os; + +import libcore.io.IoUtils; +import libcore.io.Streams; + +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Utilities for testing output of service dumps. + */ +public class DumpTestUtils { + + private static String dumpService(String serviceName, boolean adoptPermission, String... args) + throws RemoteException, InterruptedException, ErrnoException { + final IBinder ib = ServiceManager.getService(serviceName); + FileDescriptor[] pipe = Os.pipe(); + + // Start a thread to read the dump output, or dump might block if it fills the pipe. + final CountDownLatch latch = new CountDownLatch(1); + AtomicReference output = new AtomicReference<>(); + // Used to send exceptions back to the main thread to ensure that the test fails cleanly. + AtomicReference exception = new AtomicReference<>(); + new Thread(() -> { + try { + output.set(Streams.readFully( + new InputStreamReader(new FileInputStream(pipe[0]), + StandardCharsets.UTF_8))); + latch.countDown(); + } catch (Exception e) { + exception.set(e); + latch.countDown(); + } + }).start(); + + final int timeoutMs = 5_000; + final String what = "service '" + serviceName + "' with args: " + Arrays.toString(args); + try { + if (adoptPermission) { + runWithShellPermissionIdentity(() -> ib.dump(pipe[1], args), + android.Manifest.permission.DUMP); + } else { + ib.dump(pipe[1], args); + } + IoUtils.closeQuietly(pipe[1]); + assertTrue("Dump of " + what + " timed out after " + timeoutMs + "ms", + latch.await(timeoutMs, TimeUnit.MILLISECONDS)); + } finally { + // Closing the fds will terminate the thread if it's blocked on read. + IoUtils.closeQuietly(pipe[0]); + if (pipe[1].valid()) IoUtils.closeQuietly(pipe[1]); + } + if (exception.get() != null) { + fail("Exception dumping " + what + ": " + exception.get()); + } + return output.get(); + } + + /** + * Dumps the specified service and returns a string. Sends a dump IPC to the given service + * with the specified args and a pipe, then reads from the pipe in a separate thread. + * The current process must already have the DUMP permission. + * + * @param serviceName the service to dump. + * @param args the arguments to pass to the dump function. + * @return The dump text. + * @throws RemoteException dumping the service failed. + * @throws InterruptedException the dump timed out. + * @throws ErrnoException opening or closing the pipe for the dump failed. + */ + public static String dumpService(String serviceName, String... args) + throws RemoteException, InterruptedException, ErrnoException { + return dumpService(serviceName, false, args); + } + + /** + * Dumps the specified service and returns a string. Sends a dump IPC to the given service + * with the specified args and a pipe, then reads from the pipe in a separate thread. + * Adopts the {@code DUMP} permission via {@code adoptShellPermissionIdentity} and then releases + * it. This method should not be used if the caller already has the shell permission identity. + * TODO: when Q and R are no longer supported, use + * {@link android.app.UiAutomation#getAdoptedShellPermissions} to automatically acquire the + * shell permission if the caller does not already have it. + * + * @param serviceName the service to dump. + * @param args the arguments to pass to the dump function. + * @return The dump text. + * @throws RemoteException dumping the service failed. + * @throws InterruptedException the dump timed out. + * @throws ErrnoException opening or closing the pipe for the dump failed. + */ + public static String dumpServiceWithShellPermission(String serviceName, String... args) + throws RemoteException, InterruptedException, ErrnoException { + return dumpService(serviceName, true, args); + } +} From 7f0d0e3865fabb51f957e1a186aeec9cdf9431ea Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 25 Jan 2022 19:08:12 +0900 Subject: [PATCH 372/777] Use module API in common libraries Update libraries that still use system_current to module_current. This is necessary for usage in some modules, as a dependency on system_current libraries could cause circular dependencies. system_current includes the API surface of all modules, so module API jars cannot depend on it transitively. Also remove framework-annotations from net-utils-framework-common sources. This is a long overdue cleanup, and without it module API jars would include unintended API classes when including net-utils-framework-common. Bug: 204830222 Test: m Change-Id: I8f15a95a5951a644b080f5f655ffb846b900193c --- staticlibs/Android.bp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index ea38eca46c..62274819b1 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -114,7 +114,7 @@ java_library { "device/com/android/net/module/util/JniUtil.java", "device/com/android/net/module/util/TcUtils.java", ], - sdk_version: "system_current", + sdk_version: "module_current", min_sdk_version: "29", visibility: [ "//frameworks/libs/net/common/tests:__subpackages__", @@ -127,6 +127,7 @@ java_library { ], libs: [ "androidx.annotation_annotation", + "framework-connectivity.stubs.module_lib", ], apex_available: [ "com.android.tethering", @@ -144,7 +145,7 @@ java_library { "device/com/android/net/module/util/Struct.java", "device/com/android/net/module/util/structs/*.java", ], - sdk_version: "system_current", + sdk_version: "module_current", min_sdk_version: "29", visibility: [ "//frameworks/libs/net/common/testutils:__subpackages__", @@ -156,6 +157,7 @@ java_library { ], libs: [ "androidx.annotation_annotation", + "framework-connectivity.stubs.module_lib", ], apex_available: [ "com.android.tethering", @@ -169,7 +171,7 @@ java_library { srcs: [ "device/com/android/net/module/util/netlink/*.java", ], - sdk_version: "system_current", + sdk_version: "module_current", min_sdk_version: "29", visibility: [ "//frameworks/libs/net/common/testutils:__subpackages__", @@ -181,6 +183,7 @@ java_library { ], libs: [ "androidx.annotation_annotation", + "framework-connectivity.stubs.module_lib", ], apex_available: [ "com.android.tethering", @@ -224,11 +227,12 @@ java_library { name: "net-utils-framework-common", srcs: [ ":net-utils-framework-common-srcs", - // TODO: avoid including all framework annotations as they end up in library users jars - // and need jarjaring - ":framework-annotations", ], - sdk_version: "system_current", + sdk_version: "module_current", + libs: [ + "framework-annotations-lib", + "framework-connectivity.stubs.module_lib", + ], jarjar_rules: "jarjar-rules-shared.txt", visibility: [ "//cts/tests/tests/net", From 51fecf19e2b612261840f5b48c06a6998eac3615 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Tue, 25 Jan 2022 20:08:43 +0800 Subject: [PATCH 373/777] libclat: Use space indentation instead of tab Correct the indentation style of libclat in the follows bpf_headers/Android.bp bpf_syscall_wrappers/Android.bp Test: build Change-Id: I7cdd354141124fa8f7b4a864ddd937bef4676302 --- staticlibs/native/bpf_headers/Android.bp | 2 +- staticlibs/native/bpf_syscall_wrappers/Android.bp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/native/bpf_headers/Android.bp b/staticlibs/native/bpf_headers/Android.bp index 6df5dcb53d..ebb5678b70 100644 --- a/staticlibs/native/bpf_headers/Android.bp +++ b/staticlibs/native/bpf_headers/Android.bp @@ -47,7 +47,7 @@ cc_library_headers { "//packages/modules/Connectivity/bpf_progs", "//packages/modules/Connectivity/netd", "//packages/modules/Connectivity/service/native", - "//packages/modules/Connectivity/service/native/libs/libclat", + "//packages/modules/Connectivity/service/native/libs/libclat", "//packages/modules/Connectivity/tests/unit/jni", "//packages/modules/DnsResolver/tests", "//system/bpf/bpfloader", diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index ad42622794..26f311b9c1 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -40,7 +40,7 @@ cc_library_headers { "//packages/modules/Connectivity/netd", "//packages/modules/Connectivity/service", "//packages/modules/Connectivity/service/native", - "//packages/modules/Connectivity/service/native/libs/libclat", + "//packages/modules/Connectivity/service/native/libs/libclat", "//packages/modules/Connectivity/Tethering", "//packages/providers/MediaProvider/jni", "//system/bpf/libbpf_android", From b24df14433faa2081c6b760abd42db78f5638864 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 10 Jan 2022 10:31:11 +0000 Subject: [PATCH 374/777] [MS48.3] Allow Settings package to build with network static libs Settings app used NetworkStatsHistory#getValues to fetch rational bytes of the history. However, this functionality will not be available after mainling NetworkStats. Thus, allow Settings to build with NetworkStatsUtils for implementing alternative solution. Test: atest clockwork-settings-robotests make RunSettingsRoboTests -j40 make RunSettingsLibRoboTests ROBOTEST_FILTER=DataUsageControllerTest make RunSettingsLibRoboTests ROBOTEST_FILTER=NetworkCycleChartDataLoaderTest make RunSettingsLibRoboTests ROBOTEST_FILTER=NetworkCycleDataForUidLoaderTest make RunSettingsLibRoboTests ROBOTEST_FILTER=NetworkCycleDataLoaderTest make RunSettingsLibRoboTests ROBOTEST_FILTER=DataUsageUtilsTest Bug: 204830222 Ignore-AOSP-First: Related API conflict, need master first. (cherry-picked from ag/16681887) Change-Id: I8f8b6160fdc78ee91e4ce84c07faef3a0408e489 Merged-In: I8f8b6160fdc78ee91e4ce84c07faef3a0408e489 --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index ba545eae40..13c6cb0f34 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -248,6 +248,7 @@ java_library { "//frameworks/libs/net/common/tests:__subpackages__", "//frameworks/libs/net/common/device", "//packages/modules/Wifi/framework/tests:__subpackages__", + "//packages/apps/Settings", ], lint: { strict_updatability_linting: true }, } From 775e434078a7b8022ed19da3051437edc74cb606 Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 26 Jan 2022 16:44:21 +0800 Subject: [PATCH 375/777] Add U8 subclasses to Struct BPF maps require classes to extend struct. U8 is used as value of UidCounterSetMap. Test: m Change-Id: Ieacc6d83c9c55cbe2b4513e7e8356fbe4a7d0058 --- .../device/com/android/net/module/util/Struct.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/Struct.java b/staticlibs/device/com/android/net/module/util/Struct.java index f4d4163589..ac9dc5401b 100644 --- a/staticlibs/device/com/android/net/module/util/Struct.java +++ b/staticlibs/device/com/android/net/module/util/Struct.java @@ -731,6 +731,16 @@ public class Struct { return sb.toString(); } + /** A simple Struct which only contains a u8 field. */ + public static class U8 extends Struct { + @Struct.Field(order = 0, type = Struct.Type.U8) + public final short val; + + public U8(final short val) { + this.val = val; + } + } + public static class U32 extends Struct { @Struct.Field(order = 0, type = Struct.Type.U32) public final long val; From 836bd6b5ae94afb34adf0b08fa6cb0ddbe62153a Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Thu, 27 Jan 2022 05:31:39 +0100 Subject: [PATCH 376/777] Fix add missing loadLibrary to TcUtils This has been working so far because BpfMap loads the .so for the Tethering APK (as they both are part of the same library). Test: device boots Change-Id: I21feecd1b6121e24bb8e98255940aae661ff6270 --- staticlibs/device/com/android/net/module/util/TcUtils.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/TcUtils.java b/staticlibs/device/com/android/net/module/util/TcUtils.java index 5b78bc1015..cf01490b5c 100644 --- a/staticlibs/device/com/android/net/module/util/TcUtils.java +++ b/staticlibs/device/com/android/net/module/util/TcUtils.java @@ -22,6 +22,10 @@ import java.io.IOException; * Contains mostly tc-related functionality. */ public class TcUtils { + static { + System.loadLibrary(JniUtil.getJniLibraryName(TcUtils.class.getPackage())); + } + /** * Checks if the network interface uses an ethernet L2 header. * From ae85125761766dbfacbd26a7e22f70ca8924fef3 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Thu, 27 Jan 2022 10:46:23 -0800 Subject: [PATCH 377/777] [LSC] Add LOCAL_LICENSE_KINDS to frameworks/libs/net Added SPDX-license-identifier-Apache-2.0 to: common/native/nettestutils/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Change-Id: If5fcd4735fe82f336227626a443bba1d74201722 --- staticlibs/native/nettestutils/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/staticlibs/native/nettestutils/Android.bp b/staticlibs/native/nettestutils/Android.bp index 4fa367d4be..42df8e0a86 100644 --- a/staticlibs/native/nettestutils/Android.bp +++ b/staticlibs/native/nettestutils/Android.bp @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + cc_library_static { name: "libnettestutils", export_include_dirs: ["include"], From 5c080dc85b09856310befbb216740a34e8100721 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 31 Jan 2022 21:55:43 +0900 Subject: [PATCH 378/777] Mark VisibleForTesting members as public Package-private members are not visible across jars; with the latest refactoring of build and jarjar rules for connectivity, tests fail as the utils are picked up from the on-device module rather than the test package, and such members could not be found. Bug: 204830222 Test: atest ConnectivityCoverageTests Change-Id: Ia62b01e2e3123a2d8a432c061e3c576c86356df5 --- .../com/android/net/module/util/NetworkCapabilitiesUtils.java | 4 ++-- .../com/android/net/module/util/NetworkStatsUtils.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 71a0c96611..26c24f8daa 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -85,7 +85,7 @@ public final class NetworkCapabilitiesUtils { * and {@code FORCE_RESTRICTED_CAPABILITIES}. */ @VisibleForTesting - static final long RESTRICTED_CAPABILITIES = packBitList( + public static final long RESTRICTED_CAPABILITIES = packBitList( NET_CAPABILITY_BIP, NET_CAPABILITY_CBS, NET_CAPABILITY_DUN, @@ -115,7 +115,7 @@ public final class NetworkCapabilitiesUtils { * See {@code NetworkCapabilities#maybeMarkCapabilitiesRestricted}. */ @VisibleForTesting - static final long UNRESTRICTED_CAPABILITIES = packBitList( + public static final long UNRESTRICTED_CAPABILITIES = packBitList( NET_CAPABILITY_INTERNET, NET_CAPABILITY_MMS, NET_CAPABILITY_SUPL, diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java index c4d415efcf..41a9428a00 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStatsUtils.java @@ -116,7 +116,7 @@ public class NetworkStatsUtils { } @VisibleForTesting - static android.net.NetworkStats.Entry fromBucket(NetworkStats.Bucket bucket) { + public static android.net.NetworkStats.Entry fromBucket(NetworkStats.Bucket bucket) { return new android.net.NetworkStats.Entry( null /* IFACE_ALL */, bucket.getUid(), convertBucketState(bucket.getState()), convertBucketTag(bucket.getTag()), convertBucketMetered(bucket.getMetered()), From 23077d5a49483b1844e2d0005774df8712e80a30 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Thu, 27 Jan 2022 06:56:49 +0100 Subject: [PATCH 379/777] Include libtcutils inside libnet_utils_device_common_bpfjni This way, users of libnet_utils_device_common_bpfjni do not also have to separately list the required libtcutils. Test: build, boots Change-Id: Id40863de83b6c40b79f38d638299626f7e025810 --- staticlibs/native/bpfmapjni/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/native/bpfmapjni/Android.bp b/staticlibs/native/bpfmapjni/Android.bp index e4d337a4e1..cd254d4c73 100644 --- a/staticlibs/native/bpfmapjni/Android.bp +++ b/staticlibs/native/bpfmapjni/Android.bp @@ -30,7 +30,7 @@ cc_library_static { "liblog", "libnativehelper_compat_libc++", ], - static_libs: [ + whole_static_libs: [ "libtcutils", ], cflags: [ From f17790f661305bdbb96cb5f0356da2e28762a3ad Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 2 Feb 2022 09:24:05 +0900 Subject: [PATCH 380/777] Make the struct "not a subclass of Struct" error message clearer. Test: treehugger Change-Id: Ia281e186db258af3629c10b260971201380f33f4 --- staticlibs/device/com/android/net/module/util/Struct.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/staticlibs/device/com/android/net/module/util/Struct.java b/staticlibs/device/com/android/net/module/util/Struct.java index ac9dc5401b..d717bc708a 100644 --- a/staticlibs/device/com/android/net/module/util/Struct.java +++ b/staticlibs/device/com/android/net/module/util/Struct.java @@ -518,7 +518,8 @@ public class Struct { private static FieldInfo[] getClassFieldInfo(final Class clazz) { if (!isStructSubclass(clazz)) { throw new IllegalArgumentException(clazz.getName() + " is not a subclass of " - + Struct.class.getName()); + + Struct.class.getName() + ", its superclass is " + + clazz.getSuperclass().getName()); } final FieldInfo[] cachedAnnotationFields = sFieldCache.get(clazz); From 167102daaba55fe88d1d7faf7544e37f5b3f501b Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 2 Feb 2022 02:18:38 +0900 Subject: [PATCH 381/777] Turn TestBpfMap into a common utility class. - Move it to frameworks/libs/net/common/testutils. - Inherit from BpfMap, so the class can be used anywhere that uses a real BpfMap. For example, BpfCoordinatorTest uses BpfMap, not IBpfMap. Test: atest BpfCoordinatorTest Change-Id: I7ee65e47fa46ac6aafc831f5b1823b44267ba2a6 --- staticlibs/testutils/Android.bp | 1 + .../com/android/testutils/TestBpfMap.java | 136 ++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index 2dda269d73..1a1328f50f 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -28,6 +28,7 @@ java_library { ], libs: [ "androidx.annotation_annotation", + "net-utils-device-common-bpf", // TestBpfMap extends IBpfMap. ], static_libs: [ "androidx.test.ext.junit", diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java b/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java new file mode 100644 index 0000000000..5614a99aa4 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java @@ -0,0 +1,136 @@ +/* + * 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 com.android.testutils; + +import android.system.ErrnoException; + +import androidx.annotation.NonNull; + +import com.android.net.module.util.BpfMap; +import com.android.net.module.util.Struct; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * + * Fake BPF map class for tests that have no no privilege to access real BPF maps. All member + * functions which eventually call JNI to access the real native BPF map are overridden. + * + * Inherits from BpfMap instead of implementing IBpfMap so that any class using a BpfMap can use + * this class in its tests. + * + * @param the key type + * @param the value type + */ +public class TestBpfMap extends BpfMap { + private final HashMap mMap = new HashMap(); + + public TestBpfMap(final Class key, final Class value) { + super(key, value); + } + + @Override + public void forEach(BiConsumer action) throws ErrnoException { + // TODO: consider using mocked #getFirstKey and #getNextKey to iterate. It helps to + // implement the entry deletion in the iteration if required. + for (Map.Entry entry : mMap.entrySet()) { + action.accept(entry.getKey(), entry.getValue()); + } + } + + @Override + public void updateEntry(K key, V value) throws ErrnoException { + mMap.put(key, value); + } + + @Override + public void insertEntry(K key, V value) throws ErrnoException, + IllegalArgumentException { + // The entry is created if and only if it doesn't exist. See BpfMap#insertEntry. + if (mMap.get(key) != null) { + throw new IllegalArgumentException(key + " already exist"); + } + mMap.put(key, value); + } + + @Override + public void replaceEntry(K key, V value) throws ErrnoException, NoSuchElementException { + if (!mMap.containsKey(key)) throw new NoSuchElementException(); + mMap.put(key, value); + } + + @Override + public boolean insertOrReplaceEntry(K key, V value) throws ErrnoException { + // Returns true if inserted, false if replaced. + boolean ret = !mMap.containsKey(key); + mMap.put(key, value); + return ret; + } + + @Override + public boolean deleteEntry(Struct key) throws ErrnoException { + return mMap.remove(key) != null; + } + + @Override + public boolean isEmpty() throws ErrnoException { + return mMap.isEmpty(); + } + + @Override + public K getNextKey(@NonNull K key) { + // Expensive, but since this is only for tests... + Iterator it = mMap.keySet().iterator(); + while (it.hasNext()) { + if (Objects.equals(it.next(), key)) { + return it.hasNext() ? it.next() : null; + } + } + return null; + } + + @Override + public K getFirstKey() { + for (K key : mMap.keySet()) { + return key; + } + return null; + } + + @Override + public boolean containsKey(@NonNull K key) throws ErrnoException { + return mMap.containsKey(key); + } + + @Override + public V getValue(@NonNull K key) throws ErrnoException { + // Return value for a given key. Otherwise, return null without an error ENOENT. + // BpfMap#getValue treats that the entry is not found as no error. + return mMap.get(key); + } + + @Override + public void clear() throws ErrnoException { + // TODO: consider using mocked #getFirstKey and #deleteEntry to implement. + mMap.clear(); + } +} From d5c0d816e2000c7127e7275e7930c2fba08bf281 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 2 Feb 2022 13:34:48 +0900 Subject: [PATCH 382/777] Add framework-connectivity-t to net-utils The dependency is necessary as it builds against module_current and uses APIs moved there. Ignore-AOSP-First: Avoiding conflicts, cherry-pick will follow Bug: 197717846 Test: m Change-Id: I150adbdcc6ba48e0fade9f43242ef5d2f8d7cea0 --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 940f1d6cd0..2b786f179d 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -233,6 +233,7 @@ java_library { libs: [ "framework-annotations-lib", "framework-connectivity.stubs.module_lib", + "framework-connectivity-tiramisu.stubs.module_lib", ], jarjar_rules: "jarjar-rules-shared.txt", visibility: [ From 98fa3bfdacea364986697efe3b2524a51bcadb57 Mon Sep 17 00:00:00 2001 From: Roopa Sattiraju Date: Thu, 3 Feb 2022 18:53:23 -0800 Subject: [PATCH 383/777] Adding bt apex Bug: 206121418 Test: Compile Change-Id: Ia117cc35a885ba74c98a67b061a648f96dd78228 --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 940f1d6cd0..047d51ee68 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -287,6 +287,7 @@ java_library { // TODO: remove after NetworkStatsService moves to the module. "//frameworks/base/services/net", "//packages/modules/Connectivity/tests:__subpackages__", + "//packages/modules/Bluetooth/android/app", ], lint: { strict_updatability_linting: true }, } From 8c19182bcf3acc633d89947975377245d0c605ce Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 2 Feb 2022 13:34:48 +0900 Subject: [PATCH 384/777] Add framework-connectivity-t to net-utils The dependency is necessary as it builds against module_current and uses APIs moved there. Ignore-AOSP-First: Avoiding conflicts, cherry-pick will follow Bug: 197717846 Test: m (cherry-picked from ag/16770415) Change-Id: I150adbdcc6ba48e0fade9f43242ef5d2f8d7cea0 Merged-In: I150adbdcc6ba48e0fade9f43242ef5d2f8d7cea0 --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 047d51ee68..b031d2a58a 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -233,6 +233,7 @@ java_library { libs: [ "framework-annotations-lib", "framework-connectivity.stubs.module_lib", + "framework-connectivity-tiramisu.stubs.module_lib", ], jarjar_rules: "jarjar-rules-shared.txt", visibility: [ From 1a21b9a9db957aff796cdf7c6ee7abfae1c0865c Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 7 Feb 2022 11:05:14 +0900 Subject: [PATCH 385/777] Add support for unknown Network to expectCallback This patch allows not passing a network to expectCallback to allow receiving a callback when the network isn't known. This is supported in other expect* methods but somehow was missed in this one. Test: Ikev2VpnRunnerTest, which uses this ability Change-Id: Ifd20dd8789ff8b277bac3a73ddd23e2fe9febbca --- .../com/android/testutils/TestableNetworkCallback.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index c2b5a5c897..66c6eb9d5c 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -41,6 +41,7 @@ import kotlin.test.fail object NULL_NETWORK : Network(-1) object ANY_NETWORK : Network(-2) +fun anyNetwork() = ANY_NETWORK private val Int.capabilityName get() = NetworkCapabilities.capabilityNameOf(this) @@ -385,7 +386,7 @@ open class TestableNetworkCallback private constructor( val network = n ?: NULL_NETWORK // TODO : remove this .java access if the tests ever use kotlin-reflect. At the time of // this writing this would be the only use of this library in the tests. - assertTrue(type.java.isInstance(it) && it.network == network, + assertTrue(type.java.isInstance(it) && (ANY_NETWORK === n || it.network == network), "Unexpected callback : $it, expected ${type.java} with Network[$network]") } as T From b0df1895d55e94c0090255c68961c3a828e820c8 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Tue, 8 Feb 2022 00:11:14 +0000 Subject: [PATCH 386/777] bpf_headers for vendor. For waitForProgsLoaded. Bug: 162057235 Test: build, load bpf program from vendor Change-Id: Ib670aada0a98249fed21beb72879326286b2f4c2 --- staticlibs/native/bpf_headers/Android.bp | 2 +- staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h | 2 +- staticlibs/native/bpf_syscall_wrappers/Android.bp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/staticlibs/native/bpf_headers/Android.bp b/staticlibs/native/bpf_headers/Android.bp index ebb5678b70..834ef02b49 100644 --- a/staticlibs/native/bpf_headers/Android.bp +++ b/staticlibs/native/bpf_headers/Android.bp @@ -18,7 +18,7 @@ package { cc_library_headers { name: "bpf_headers", - vendor_available: false, + vendor_available: true, host_supported: true, native_bridge_supported: true, header_libs: ["bpf_syscall_wrappers"], diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h index 02b2096d9a..13716681c3 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h @@ -23,7 +23,7 @@ #include // Pull in AID_* constants from //system/core/libcutils/include/private/android_filesystem_config.h -#include +#include /****************************************************************************** * * diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index 26f311b9c1..a20eed3ad9 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -18,7 +18,7 @@ package { cc_library_headers { name: "bpf_syscall_wrappers", - vendor_available: false, + vendor_available: true, host_supported: true, native_bridge_supported: true, export_include_dirs: ["include"], From f4302ece8f13465ed2282e81692f29539386c0bc Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Sat, 18 Dec 2021 19:41:38 +0800 Subject: [PATCH 387/777] Move Tether4Key and Tether4Value to common libs EthernetTetheringTest needs to parse BPF map content for IPv4 forwarding rule tests. Move the struct class files to common libs. Compare Tether4{Key, Value}.java between frameworks/libs/net/common and packages/modules/Connectivity/Tethering. There is only the package name change as expected. $ diff packages/modules/Connectivity/Tethering/src/com/android/networkstack/tethering/Tether4Key.java frameworks/libs/net/common/device/com/android/net/module/util/bpf/Tether4Key.java 17c17 < package com.android.networkstack.tethering; --- > package com.android.net.module.util.bpf; $ diff packages/modules/Connectivity/Tethering/src/com/android/networkstack/tethering/Tether4Value.java frameworks/libs/net/common/device/com/android/net/module/util/bpf/Tether4Value.java 17c17 < package com.android.networkstack.tethering; --- > package com.android.net.module.util.bpf; Test: atest TetheringCoverageTests Change-Id: I77142c784e20fd74d4aa5dd34858159e232abbe3 --- staticlibs/Android.bp | 1 + .../net/module/util/bpf/Tether4Key.java | 81 ++++++++++++++++ .../net/module/util/bpf/Tether4Value.java | 97 +++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/bpf/Tether4Key.java create mode 100644 staticlibs/device/com/android/net/module/util/bpf/Tether4Value.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 047d51ee68..513b2017d5 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -116,6 +116,7 @@ java_library { "device/com/android/net/module/util/JniUtil.java", "device/com/android/net/module/util/Struct.java", "device/com/android/net/module/util/TcUtils.java", + "device/com/android/net/module/util/bpf/*.java", ], sdk_version: "module_current", min_sdk_version: "29", diff --git a/staticlibs/device/com/android/net/module/util/bpf/Tether4Key.java b/staticlibs/device/com/android/net/module/util/bpf/Tether4Key.java new file mode 100644 index 0000000000..638576f026 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/bpf/Tether4Key.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util.bpf; + +import android.net.MacAddress; + +import androidx.annotation.NonNull; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.Inet4Address; +import java.net.UnknownHostException; +import java.util.Objects; + +/** Key type for downstream & upstream IPv4 forwarding maps. */ +public class Tether4Key extends Struct { + @Field(order = 0, type = Type.U32) + public final long iif; + + @Field(order = 1, type = Type.EUI48) + public final MacAddress dstMac; + + @Field(order = 2, type = Type.U8, padding = 1) + public final short l4proto; + + @Field(order = 3, type = Type.ByteArray, arraysize = 4) + public final byte[] src4; + + @Field(order = 4, type = Type.ByteArray, arraysize = 4) + public final byte[] dst4; + + @Field(order = 5, type = Type.UBE16) + public final int srcPort; + + @Field(order = 6, type = Type.UBE16) + public final int dstPort; + + public Tether4Key(final long iif, @NonNull final MacAddress dstMac, final short l4proto, + final byte[] src4, final byte[] dst4, final int srcPort, + final int dstPort) { + Objects.requireNonNull(dstMac); + + this.iif = iif; + this.dstMac = dstMac; + this.l4proto = l4proto; + this.src4 = src4; + this.dst4 = dst4; + this.srcPort = srcPort; + this.dstPort = dstPort; + } + + @Override + public String toString() { + try { + return String.format( + "iif: %d, dstMac: %s, l4proto: %d, src4: %s, dst4: %s, " + + "srcPort: %d, dstPort: %d", + iif, dstMac, l4proto, + Inet4Address.getByAddress(src4), Inet4Address.getByAddress(dst4), + Short.toUnsignedInt((short) srcPort), Short.toUnsignedInt((short) dstPort)); + } catch (UnknownHostException | IllegalArgumentException e) { + return String.format("Invalid IP address", e); + } + } +} diff --git a/staticlibs/device/com/android/net/module/util/bpf/Tether4Value.java b/staticlibs/device/com/android/net/module/util/bpf/Tether4Value.java new file mode 100644 index 0000000000..de98766ee3 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/bpf/Tether4Value.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util.bpf; + +import android.net.MacAddress; + +import androidx.annotation.NonNull; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Objects; + +/** Value type for downstream & upstream IPv4 forwarding maps. */ +public class Tether4Value extends Struct { + @Field(order = 0, type = Type.U32) + public final long oif; + + // The ethhdr struct which is defined in uapi/linux/if_ether.h + @Field(order = 1, type = Type.EUI48) + public final MacAddress ethDstMac; + @Field(order = 2, type = Type.EUI48) + public final MacAddress ethSrcMac; + @Field(order = 3, type = Type.UBE16) + public final int ethProto; // Packet type ID field. + + @Field(order = 4, type = Type.U16) + public final int pmtu; + + @Field(order = 5, type = Type.ByteArray, arraysize = 16) + public final byte[] src46; + + @Field(order = 6, type = Type.ByteArray, arraysize = 16) + public final byte[] dst46; + + @Field(order = 7, type = Type.UBE16) + public final int srcPort; + + @Field(order = 8, type = Type.UBE16) + public final int dstPort; + + // TODO: consider using U64. + @Field(order = 9, type = Type.U63) + public final long lastUsed; + + public Tether4Value(final long oif, @NonNull final MacAddress ethDstMac, + @NonNull final MacAddress ethSrcMac, final int ethProto, final int pmtu, + final byte[] src46, final byte[] dst46, final int srcPort, + final int dstPort, final long lastUsed) { + Objects.requireNonNull(ethDstMac); + Objects.requireNonNull(ethSrcMac); + + this.oif = oif; + this.ethDstMac = ethDstMac; + this.ethSrcMac = ethSrcMac; + this.ethProto = ethProto; + this.pmtu = pmtu; + this.src46 = src46; + this.dst46 = dst46; + this.srcPort = srcPort; + this.dstPort = dstPort; + this.lastUsed = lastUsed; + } + + @Override + public String toString() { + try { + return String.format( + "oif: %d, ethDstMac: %s, ethSrcMac: %s, ethProto: %d, pmtu: %d, " + + "src46: %s, dst46: %s, srcPort: %d, dstPort: %d, " + + "lastUsed: %d", + oif, ethDstMac, ethSrcMac, ethProto, pmtu, + InetAddress.getByAddress(src46), InetAddress.getByAddress(dst46), + Short.toUnsignedInt((short) srcPort), Short.toUnsignedInt((short) dstPort), + lastUsed); + } catch (UnknownHostException | IllegalArgumentException e) { + return String.format("Invalid IP address", e); + } + } +} From cfe2f2a1c90b518eaf42d88bca7425a30b2220de Mon Sep 17 00:00:00 2001 From: KaiWen Zheng Date: Tue, 8 Feb 2022 09:38:50 +0800 Subject: [PATCH 388/777] Add attach bpf with flags and detach single bpf Attach bpf program to cgroup with flags, support 'BPF_F_ALLOW_OVERRIDE' and 'BPF_F_ALLOW_MULTI'; corresponding to detach a single bpf program in a cgroup. Test: m Signed-off-by: KaiWen Zheng Change-Id: I9a4d2dcb249c6c628e3f1287d7d5d1879b722bd6 --- .../include/BpfSyscallWrappers.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h index 72eebf3cb2..abf83daa29 100644 --- a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h +++ b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h @@ -125,11 +125,12 @@ inline int retrieveProgram(const char* pathname) { } inline int attachProgram(bpf_attach_type type, const BPF_FD_TYPE prog_fd, - const BPF_FD_TYPE cg_fd) { + const BPF_FD_TYPE cg_fd, uint32_t flags = 0) { return bpf(BPF_PROG_ATTACH, { .target_fd = BPF_FD_TO_U32(cg_fd), .attach_bpf_fd = BPF_FD_TO_U32(prog_fd), .attach_type = type, + .attach_flags = flags, }); } @@ -140,6 +141,15 @@ inline int detachProgram(bpf_attach_type type, const BPF_FD_TYPE cg_fd) { }); } +inline int detachSingleProgram(bpf_attach_type type, const BPF_FD_TYPE prog_fd, + const BPF_FD_TYPE cg_fd) { + return bpf(BPF_PROG_DETACH, { + .target_fd = BPF_FD_TO_U32(cg_fd), + .attach_bpf_fd = BPF_FD_TO_U32(prog_fd), + .attach_type = type, + }); +} + } // namespace bpf } // namespace android From 6b1d684059154d54e9e60b8610d9004bb5d47cf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 9 Feb 2022 17:19:16 -0800 Subject: [PATCH 389/777] bpf_headers/bpf_syscall_wrappers - remove visibility restrictions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this doesn't appear to make sense now that it's available to vendors Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: If2d24fa8eccfb5c12832fb191a8560b024751db7 --- staticlibs/native/bpf_headers/Android.bp | 23 ------------------- .../native/bpf_syscall_wrappers/Android.bp | 13 ----------- 2 files changed, 36 deletions(-) diff --git a/staticlibs/native/bpf_headers/Android.bp b/staticlibs/native/bpf_headers/Android.bp index 834ef02b49..9924c6c11b 100644 --- a/staticlibs/native/bpf_headers/Android.bp +++ b/staticlibs/native/bpf_headers/Android.bp @@ -35,29 +35,6 @@ cc_library_headers { "com.android.tethering", "com.android.art.debug", ], - visibility: [ - "//bootable/libbootloader/vts", - "//cts/tests/tests/net/native", - "//frameworks/base/services/core/jni", - "//frameworks/native/libs/cputimeinstate", - "//frameworks/native/services/gpuservice", - "//frameworks/native/services/gpuservice/gpumem", - "//frameworks/native/services/gpuservice/tests/unittests", - "//frameworks/native/services/gpuservice/tracing", - "//packages/modules/Connectivity/bpf_progs", - "//packages/modules/Connectivity/netd", - "//packages/modules/Connectivity/service/native", - "//packages/modules/Connectivity/service/native/libs/libclat", - "//packages/modules/Connectivity/tests/unit/jni", - "//packages/modules/DnsResolver/tests", - "//system/bpf/bpfloader", - "//system/bpf/libbpf_android", - "//system/memory/libmeminfo", - "//system/netd/server", - "//system/netd/tests", - "//system/netd/tests/benchmarks", - "//test/vts-testcase/kernel/api/bpf_native_test", - ], } diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index a20eed3ad9..2d7277fed3 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -33,17 +33,4 @@ cc_library_headers { "com.android.mediaprovider", "com.android.tethering", ], - visibility: [ - "//frameworks/libs/net/common/native/bpf_headers", - "//frameworks/libs/net/common/native/bpfmapjni", - "//frameworks/libs/net/common/native/tcutils", - "//packages/modules/Connectivity/netd", - "//packages/modules/Connectivity/service", - "//packages/modules/Connectivity/service/native", - "//packages/modules/Connectivity/service/native/libs/libclat", - "//packages/modules/Connectivity/Tethering", - "//packages/providers/MediaProvider/jni", - "//system/bpf/libbpf_android", - "//system/memory/lmkd", - ], } From c805004f6d3d5214f5ca2dd31f79148a52361305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 9 Feb 2022 19:05:53 -0800 Subject: [PATCH 390/777] switch from libbpf_android to bpf_headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger, atest libbpf_android_test Signed-off-by: Maciej Żenczykowski Change-Id: I215ac3c5d4820bfef94a48024d511ea86012eb0f --- staticlibs/native/bpf_headers/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/native/bpf_headers/Android.bp b/staticlibs/native/bpf_headers/Android.bp index 9924c6c11b..4c8e728f05 100644 --- a/staticlibs/native/bpf_headers/Android.bp +++ b/staticlibs/native/bpf_headers/Android.bp @@ -50,9 +50,9 @@ cc_test { "-Werror", "-Wno-error=unused-variable", ], + header_libs: ["bpf_headers"], static_libs: ["libgmock"], shared_libs: [ - "libbpf_android", "libbase", "liblog", "libutils", From 310cc18cc28af73d7ea050dd9f8870eab5b223a0 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 10 Feb 2022 11:33:36 +0900 Subject: [PATCH 391/777] Utils : Collections.containsAll, containsAny, Permissions.getGrantedPermissions Introduces three new useful utilities into the static f/l/n common libraries. Test: used in ConnectivityManagerTest CTS, atest ConnectivityManagerTest Change-Id: I83aca0b105b6d697768d263db76e0c521667942e --- .../net/module/util/CollectionUtils.java | 26 +++++++++++++++++++ .../net/module/util/PermissionUtils.java | 25 ++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index 312ca4839e..a16ef337cd 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -193,4 +193,30 @@ public final class CollectionUtils { } return total; } + + /** + * Returns true if the first collection contains any of the elements of the second. + * @param haystack where to search + * @param needles what to search for + * @param type of elements + * @return true if |haystack| contains any of the |needles|, false otherwise + */ + public static boolean containsAny(Collection haystack, Collection needles) { + for (T needle : needles) { + if (haystack.contains(needle)) return true; + } + return false; + } + + /** + * Returns true if the first collection contains all of the elements of the second. + * @param haystack where to search + * @param needles what to search for + * @param type of elements + * @return true if |haystack| contains all of the |needles|, false otherwise + */ + public static boolean containsAll(Collection haystack, Collection needles) { + return haystack.containsAll(needles); + } + } diff --git a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java index 0f3dc1562e..be5b0cde75 100644 --- a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java @@ -19,17 +19,21 @@ package com.android.net.module.util; import static android.Manifest.permission.ACCESS_NETWORK_STATE; import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; import static android.Manifest.permission.NETWORK_STACK; +import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.pm.PackageInfo; import android.os.Binder; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.List; /** * Collection of permission utilities. @@ -144,4 +148,25 @@ public final class PermissionUtils { throw new UnsupportedOperationException(errorMessage); } } + + /** + * Get the list of granted permissions for a package info. + * + * PackageInfo contains the list of requested permissions, and their state (whether they + * were granted or not, in particular) as a parallel array. Most users care only about + * granted permissions. This method returns the list of them. + * + * @param packageInfo the package info for the relevant uid. + * @return the list of granted permissions. + */ + public static List getGrantedPermissions(final @NonNull PackageInfo packageInfo) { + if (null == packageInfo.requestedPermissions) return Collections.emptyList(); + final ArrayList result = new ArrayList<>(packageInfo.requestedPermissions.length); + for (int i = 0; i < packageInfo.requestedPermissions.length; ++i) { + if (0 != (REQUESTED_PERMISSION_GRANTED & packageInfo.requestedPermissionsFlags[i])) { + result.add(packageInfo.requestedPermissions[i]); + } + } + return result; + } } From a11e698749657e99ffb24d982aff5cc24ac6762c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 9 Feb 2022 22:21:41 -0800 Subject: [PATCH 392/777] expose bpf_syscall_wrappers to art apex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The art apex already has access to bpf_headers which includes bpf_syscall_wrappers, but this extra line is needed to switch it away from needlessly linking libbpf_android. Since these are header files only, this annotation is kind of pointless, but it does turn out to be needed... Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I9e4d3373cea488080304e31ed7c8708aec988933 --- staticlibs/native/bpf_syscall_wrappers/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index 2d7277fed3..f41a2446fe 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -30,6 +30,7 @@ cc_library_headers { min_sdk_version: "30", apex_available: [ "//apex_available:platform", + "com.android.art.debug", "com.android.mediaprovider", "com.android.tethering", ], From 20dcaf5f7044517512a38885f64244b7f24c4a18 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Fri, 11 Feb 2022 13:14:45 +0100 Subject: [PATCH 393/777] Fix wrong nla_type for matchall TCA_U32_ACT was missed when converting from the u32 filter to matchall. Interestingly, cls_matchall does not seem to validate this type as the kernel happily accepted this configuration (which absolutely should not happen as TCA_U32_ACT is greater than __TCA_MATCHALL_MAX). Bug: 218840346 Test: atest CtsNetTestCases:RateLimitTest Change-Id: Ia24683cbd5fbd10084163db6e6a4415ec03f6f3f --- staticlibs/native/tcutils/tcutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/native/tcutils/tcutils.cpp b/staticlibs/native/tcutils/tcutils.cpp index 0e17f67c22..144a4c940a 100644 --- a/staticlibs/native/tcutils/tcutils.cpp +++ b/staticlibs/native/tcutils/tcutils.cpp @@ -196,7 +196,7 @@ public: .acts = { .attr = { .nla_len = sizeof(mRequest.opt.acts), - .nla_type = TCA_U32_ACT, + .nla_type = TCA_MATCHALL_ACT, }, .act1 = { .attr = { From 8e377130c9b9eed8dc06a48cd4abc617d27e37bd Mon Sep 17 00:00:00 2001 From: Tyler Wear Date: Tue, 15 Feb 2022 15:15:24 -0800 Subject: [PATCH 394/777] Add ThrowingBiConsumer to IBpfMap Converting BiConsumer to ThrowingBiconsumer allows an exception to correctly be thrown from the BiConsumer action in forEach() from BpfMap. Change-Id: I34363c5aa8b07c4cbd703e899381a95062d2b75b --- staticlibs/device/com/android/net/module/util/BpfMap.java | 2 +- staticlibs/device/com/android/net/module/util/IBpfMap.java | 6 +++++- .../devicetests/com/android/testutils/TestBpfMap.java | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java index b42c388523..d171b1126d 100644 --- a/staticlibs/device/com/android/net/module/util/BpfMap.java +++ b/staticlibs/device/com/android/net/module/util/BpfMap.java @@ -250,7 +250,7 @@ public class BpfMap implements IBpfMap * Otherwise, iteration will result in undefined behaviour. */ @Override - public void forEach(BiConsumer action) throws ErrnoException { + public void forEach(ThrowingBiConsumer action) throws ErrnoException { @Nullable K nextKey = getFirstKey(); while (nextKey != null) { diff --git a/staticlibs/device/com/android/net/module/util/IBpfMap.java b/staticlibs/device/com/android/net/module/util/IBpfMap.java index 708cf61a80..d43b22c619 100644 --- a/staticlibs/device/com/android/net/module/util/IBpfMap.java +++ b/staticlibs/device/com/android/net/module/util/IBpfMap.java @@ -64,10 +64,14 @@ public interface IBpfMap { /** Retrieve a value from the map. */ V getValue(@NonNull K key) throws ErrnoException; + public interface ThrowingBiConsumer { + void accept(T t, U u) throws ErrnoException; + } + /** * Iterate through the map and handle each key -> value retrieved base on the given BiConsumer. */ - void forEach(BiConsumer action) throws ErrnoException; + void forEach(ThrowingBiConsumer action) throws ErrnoException; /** Clears the map. */ void clear() throws ErrnoException; diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java b/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java index 5614a99aa4..73bc3a9caf 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java @@ -21,6 +21,7 @@ import android.system.ErrnoException; import androidx.annotation.NonNull; import com.android.net.module.util.BpfMap; +import com.android.net.module.util.IBpfMap.ThrowingBiConsumer; import com.android.net.module.util.Struct; import java.util.HashMap; @@ -28,7 +29,6 @@ import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; -import java.util.function.BiConsumer; /** * @@ -49,7 +49,7 @@ public class TestBpfMap extends BpfMap } @Override - public void forEach(BiConsumer action) throws ErrnoException { + public void forEach(ThrowingBiConsumer action) throws ErrnoException { // TODO: consider using mocked #getFirstKey and #getNextKey to iterate. It helps to // implement the entry deletion in the iteration if required. for (Map.Entry entry : mMap.entrySet()) { From 675cdf6d998a20f4905d0bc8172dc2ba99688ac4 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 16 Feb 2022 18:52:32 +0900 Subject: [PATCH 395/777] Remove dependency on compatibility-device-util-axt The library pulls a lot of dependencies, which end up in code coverage reports, because code coverage looks at code inside the test package unless excluded. Just use the existing TestPermissionUtil in the same library instead, avoiding the need to exclude many test utilities and making the test smaller. Test: atest android.net.cts.ConnectivityManagerTest#testDump Change-Id: I3ba2121ef034872acf077578644ac9e8aa92c7ef --- staticlibs/testutils/Android.bp | 1 - .../devicetests/com/android/testutils/DumpTestUtils.java | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index 1a1328f50f..642544ad87 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -32,7 +32,6 @@ java_library { ], static_libs: [ "androidx.test.ext.junit", - "compatibility-device-util-axt", "kotlin-reflect", "libnanohttpd", "net-tests-utils-host-device-common", diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DumpTestUtils.java b/staticlibs/testutils/devicetests/com/android/testutils/DumpTestUtils.java index f2ad1e27e5..d103748850 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DumpTestUtils.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/DumpTestUtils.java @@ -16,7 +16,7 @@ package com.android.testutils; -import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; +import static com.android.testutils.TestPermissionUtil.runAsShell; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -70,8 +70,7 @@ public class DumpTestUtils { final String what = "service '" + serviceName + "' with args: " + Arrays.toString(args); try { if (adoptPermission) { - runWithShellPermissionIdentity(() -> ib.dump(pipe[1], args), - android.Manifest.permission.DUMP); + runAsShell(android.Manifest.permission.DUMP, () -> ib.dump(pipe[1], args)); } else { ib.dump(pipe[1], args); } From 92f3c24e9002443dfb55baae8cf16a8ceecc77e5 Mon Sep 17 00:00:00 2001 From: Tyler Wear Date: Tue, 15 Feb 2022 15:21:43 -0800 Subject: [PATCH 396/777] Add BpfBitmap Class Generic bitmap class for use with bpf programs. Internally uses bpfMap with key/value. Test: atest BpfBitmapTest Change-Id: Ica912b080849b50614e30ee168992c9ada74068c --- staticlibs/Android.bp | 1 + .../android/net/module/util/BpfBitmap.java | 126 ++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/BpfBitmap.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index ef80170038..a311eb577f 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -110,6 +110,7 @@ filegroup { java_library { name: "net-utils-device-common-bpf", srcs: [ + "device/com/android/net/module/util/BpfBitmap.java", "device/com/android/net/module/util/BpfMap.java", "device/com/android/net/module/util/HexDump.java", "device/com/android/net/module/util/IBpfMap.java", diff --git a/staticlibs/device/com/android/net/module/util/BpfBitmap.java b/staticlibs/device/com/android/net/module/util/BpfBitmap.java new file mode 100644 index 0000000000..0c8bb37ee1 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/BpfBitmap.java @@ -0,0 +1,126 @@ +/* + * 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 com.android.net.module.util; + +import android.system.ErrnoException; + +import androidx.annotation.NonNull; + + /** + * + * Generic bitmap class for use with BPF programs. Corresponds to a BpfMap + * array type with key->int and value->uint64_t defined in the bpf program. + * + */ +public class BpfBitmap { + private BpfMap mBpfMap; + + /** + * Create a BpfBitmap map wrapper with "path" of filesystem. + * + * @param path The path of the BPF map. + */ + public BpfBitmap(@NonNull String path) throws ErrnoException { + mBpfMap = new BpfMap(path, BpfMap.BPF_F_RDWR, + Struct.U32.class, Struct.S64.class); + } + + /** + * Retrieves the value from BpfMap for the given key. + * + * @param key The key in the map corresponding to the value to return. + */ + private long getBpfMapValue(Struct.U32 key) throws ErrnoException { + Struct.S64 curVal = mBpfMap.getValue(key); + if (curVal != null) { + return curVal.val; + } else { + return 0; + } + } + + /** + * Retrieves the bit for the given index in the bitmap. + * + * @param index Position in bitmap. + */ + public boolean get(int index) throws ErrnoException { + if (index < 0) return false; + + Struct.U32 key = new Struct.U32(index >> 6); + return ((getBpfMapValue(key) >>> (index & 63)) & 1L) != 0; + } + + /** + * Set the specified index in the bitmap. + * + * @param index Position to set in bitmap. + */ + public void set(int index) throws ErrnoException { + set(index, true); + } + + /** + * Unset the specified index in the bitmap. + * + * @param index Position to unset in bitmap. + */ + public void unset(int index) throws ErrnoException { + set(index, false); + } + + /** + * Change the specified index in the bitmap to set value. + * + * @param index Position to unset in bitmap. + * @param set Boolean indicating to set or unset index. + */ + public void set(int index, boolean set) throws ErrnoException { + if (index < 0) throw new IllegalArgumentException("Index out of bounds."); + + Struct.U32 key = new Struct.U32(index >> 6); + long mask = (1L << (index & 63)); + long val = getBpfMapValue(key); + if (set) val |= mask; else val &= ~mask; + mBpfMap.updateEntry(key, new Struct.S64(val)); + } + + /** + * Clears the map. The map may already be empty. + * + * @throws ErrnoException if updating entry to 0 fails. + */ + public void clear() throws ErrnoException { + mBpfMap.forEach((key, value) -> { + mBpfMap.updateEntry(key, new Struct.S64(0)); + }); + } + + /** + * Checks if all bitmap values are 0. + */ + public boolean isEmpty() throws ErrnoException { + Struct.U32 key = mBpfMap.getFirstKey(); + while (key != null) { + if (getBpfMapValue(key) != 0) { + return false; + } + key = mBpfMap.getNextKey(key); + } + return true; + } +} From 5fec18b980dc9fd1e76ca075ff44d5f03ab2518d Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 17 Feb 2022 17:44:03 +0900 Subject: [PATCH 397/777] Allow of expectAvailableCallbacks when validation state is unknown. Currently, expectAvailableCallbacks requires that the caller know in advance what the validation state is. This CL allows the caller to pass in validated = null to indicate that it does not matter whether the network is validated or not. Test: modified CTS test in other CL in topic Test: atest CtsNetTestCases:android.net.cts.ConnectivityManagerTest Change-Id: Ie54806a4a1d907de630819e11f9e34602cc55ef4 --- .../com/android/testutils/TestableNetworkCallback.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index c2b5a5c897..acbb22713b 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -287,7 +287,7 @@ open class TestableNetworkCallback private constructor( fun expectAvailableCallbacks( net: Network, suspended: Boolean = false, - validated: Boolean = true, + validated: Boolean? = true, blocked: Boolean = false, tmt: Long = defaultTimeoutMs ) { @@ -309,14 +309,18 @@ open class TestableNetworkCallback private constructor( private fun expectAvailableCallbacksCommon( net: Network, suspended: Boolean, - validated: Boolean, + validated: Boolean?, tmt: Long ) { expectCallback(net, tmt) if (suspended) { expectCallback(net, tmt) } - expectCapabilitiesThat(net, tmt) { validated == it.hasCapability(NET_CAPABILITY_VALIDATED) } + expectCapabilitiesThat(net, tmt) { + validated == null || validated == it.hasCapability( + NET_CAPABILITY_VALIDATED + ) + } expectCallback(net, tmt) } From aeff1238bb081749e9d5babfdf5b2b1a1600e97d Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Mon, 7 Feb 2022 11:37:34 +0100 Subject: [PATCH 398/777] Change TestBpfMap to use ConcurrentHashMap IBpfMap#forEach allows concurrent map access (deleting from the map while iterating), so we should allow this in TestBpfMap as well. Test: builds Change-Id: I89dc7e4daf1d0cfc1aac57cad4ea7f1e50f5f20c --- .../devicetests/com/android/testutils/TestBpfMap.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java b/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java index 73bc3a9caf..3883511388 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java @@ -24,11 +24,11 @@ import com.android.net.module.util.BpfMap; import com.android.net.module.util.IBpfMap.ThrowingBiConsumer; import com.android.net.module.util.Struct; -import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; /** * @@ -42,7 +42,7 @@ import java.util.Objects; * @param the value type */ public class TestBpfMap extends BpfMap { - private final HashMap mMap = new HashMap(); + private final ConcurrentHashMap mMap = new ConcurrentHashMap<>(); public TestBpfMap(final Class key, final Class value) { super(key, value); From 74112b549d69e961ce49a630e07d9c55f0322828 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Fri, 18 Feb 2022 12:14:00 +0100 Subject: [PATCH 399/777] remove unused import from BpfMap Test: m Change-Id: Iebdb14ad2ae917c5f1e2e23ea2619106fb092caf --- staticlibs/device/com/android/net/module/util/BpfMap.java | 1 - 1 file changed, 1 deletion(-) diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java index d171b1126d..d4ce83b48e 100644 --- a/staticlibs/device/com/android/net/module/util/BpfMap.java +++ b/staticlibs/device/com/android/net/module/util/BpfMap.java @@ -30,7 +30,6 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.NoSuchElementException; import java.util.Objects; -import java.util.function.BiConsumer; /** * BpfMap is a key -> value mapping structure that is designed to maintained the bpf map entries. From 14653bb6e9ccc30668ed23c9057480de6a204791 Mon Sep 17 00:00:00 2001 From: paulhu Date: Mon, 14 Feb 2022 15:28:50 +0800 Subject: [PATCH 400/777] Rename framework-connectivity-tiramisu to framework-connectivity-t Bug: 215434166 Ignore-AOSP-First: Merge conflict. Will cherry-pick to AOSP afterwards. Test: build, flash, device boot to home. Merged-In: Ie4c0ae97435457ea46b7c41be86a896b552d9bd8 Change-Id: Ie4c0ae97435457ea46b7c41be86a896b552d9bd8 --- staticlibs/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index a311eb577f..b7fadda65c 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -235,7 +235,7 @@ java_library { libs: [ "framework-annotations-lib", "framework-connectivity.stubs.module_lib", - "framework-connectivity-tiramisu.stubs.module_lib", + "framework-connectivity-t.stubs.module_lib", ], jarjar_rules: "jarjar-rules-shared.txt", visibility: [ From cdb069ed437d0706ed81765a2efb6a23f18111d6 Mon Sep 17 00:00:00 2001 From: paulhu Date: Mon, 14 Feb 2022 15:28:50 +0800 Subject: [PATCH 401/777] Rename framework-connectivity-tiramisu to framework-connectivity-t Bug: 215434166 Test: build, flash, device boot to home. Merged-In: Ie4c0ae97435457ea46b7c41be86a896b552d9bd8 Change-Id: Ie4c0ae97435457ea46b7c41be86a896b552d9bd8 --- staticlibs/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index ef80170038..735fc87b36 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -234,7 +234,7 @@ java_library { libs: [ "framework-annotations-lib", "framework-connectivity.stubs.module_lib", - "framework-connectivity-tiramisu.stubs.module_lib", + "framework-connectivity-t.stubs.module_lib", ], jarjar_rules: "jarjar-rules-shared.txt", visibility: [ From 0d22922375693a3a59ef78881d4822e054af8e03 Mon Sep 17 00:00:00 2001 From: paulhu Date: Mon, 14 Feb 2022 15:28:50 +0800 Subject: [PATCH 402/777] Rename framework-connectivity-tiramisu to framework-connectivity-t Bug: 215434166 Ignore-AOSP-First: Merge conflict. Will cherry-pick to AOSP afterwards. Test: build, flash, device boot to home. Merged-In: Ie4c0ae97435457ea46b7c41be86a896b552d9bd8 Change-Id: Ie4c0ae97435457ea46b7c41be86a896b552d9bd8 (cherry picked from commit 6b2819b4779e6a7b15e8088a7ae45e585ed97658) --- staticlibs/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index a311eb577f..b7fadda65c 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -235,7 +235,7 @@ java_library { libs: [ "framework-annotations-lib", "framework-connectivity.stubs.module_lib", - "framework-connectivity-tiramisu.stubs.module_lib", + "framework-connectivity-t.stubs.module_lib", ], jarjar_rules: "jarjar-rules-shared.txt", visibility: [ From e48ee4a864f28dee959392e3f22c3b2f02c780ae Mon Sep 17 00:00:00 2001 From: Tyler Wear Date: Tue, 15 Feb 2022 15:30:50 -0800 Subject: [PATCH 403/777] Bpf Util Lib in Common Location Add bpf lib to load and attach BPF programs in commonly accesible location. Bug: 179733303 Change-Id: I17b68abb14e816e7210bc603ffda44e10fb73d2f --- staticlibs/Android.bp | 1 + .../com/android/net/module/util/BpfUtils.java | 69 +++++++++ staticlibs/native/bpfutiljni/Android.bp | 44 ++++++ .../com_android_net_module_util_BpfUtils.cpp | 132 ++++++++++++++++++ 4 files changed, 246 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/BpfUtils.java create mode 100644 staticlibs/native/bpfutiljni/Android.bp create mode 100644 staticlibs/native/bpfutiljni/com_android_net_module_util_BpfUtils.cpp diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index a311eb577f..d8c91e3387 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -112,6 +112,7 @@ java_library { srcs: [ "device/com/android/net/module/util/BpfBitmap.java", "device/com/android/net/module/util/BpfMap.java", + "device/com/android/net/module/util/BpfUtils.java", "device/com/android/net/module/util/HexDump.java", "device/com/android/net/module/util/IBpfMap.java", "device/com/android/net/module/util/JniUtil.java", diff --git a/staticlibs/device/com/android/net/module/util/BpfUtils.java b/staticlibs/device/com/android/net/module/util/BpfUtils.java new file mode 100644 index 0000000000..94af11b347 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/BpfUtils.java @@ -0,0 +1,69 @@ +/* + * 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 com.android.net.module.util; + +import androidx.annotation.NonNull; + +import java.io.IOException; + +/** + * The classes and the methods for BPF utilization. + * + * {@hide} + */ +public class BpfUtils { + static { + System.loadLibrary(JniUtil.getJniLibraryName(BpfUtils.class.getPackage())); + } + + // Defined in include/uapi/linux/bpf.h. Only adding the CGROUPS currently being used for now. + public static final int BPF_CGROUP_INET_INGRESS = 0; + public static final int BPF_CGROUP_INET_EGRESS = 1; + public static final int BPF_CGROUP_INET4_BIND = 8; + public static final int BPF_CGROUP_INET6_BIND = 9; + + + /** + * Attach BPF program to CGROUP + */ + public static void attachProgram(int type, @NonNull String programPath, + @NonNull String cgroupPath, int flags) throws IOException { + native_attachProgramToCgroup(type, programPath, cgroupPath, flags); + } + + /** + * Detach BPF program from CGROUP + */ + public static void detachProgram(int type, @NonNull String cgroupPath) + throws IOException { + native_detachProgramFromCgroup(type, cgroupPath); + } + + /** + * Detach single BPF program from CGROUP + */ + public static void detachSingleProgram(int type, @NonNull String programPath, + @NonNull String cgroupPath) throws IOException { + native_detachSingleProgramFromCgroup(type, programPath, cgroupPath); + } + + private static native boolean native_attachProgramToCgroup(int type, String programPath, + String cgroupPath, int flags) throws IOException; + private static native boolean native_detachProgramFromCgroup(int type, String cgroupPath) + throws IOException; + private static native boolean native_detachSingleProgramFromCgroup(int type, + String programPath, String cgroupPath) throws IOException; +} diff --git a/staticlibs/native/bpfutiljni/Android.bp b/staticlibs/native/bpfutiljni/Android.bp new file mode 100644 index 0000000000..39a2795086 --- /dev/null +++ b/staticlibs/native/bpfutiljni/Android.bp @@ -0,0 +1,44 @@ +// 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_library_static { + name: "libnet_utils_device_common_bpfutils", + srcs: ["com_android_net_module_util_BpfUtils.cpp"], + header_libs: [ + "bpf_syscall_wrappers", + "jni_headers", + ], + shared_libs: [ + "libbase", + "liblog", + "libnativehelper_compat_libc++", + ], + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + ], + min_sdk_version: "30", + apex_available: [ + "com.android.tethering", + "//apex_available:platform", + ], + visibility: [ + "//packages/modules/Connectivity/service", + ], +} diff --git a/staticlibs/native/bpfutiljni/com_android_net_module_util_BpfUtils.cpp b/staticlibs/native/bpfutiljni/com_android_net_module_util_BpfUtils.cpp new file mode 100644 index 0000000000..0f2ebbd49a --- /dev/null +++ b/staticlibs/native/bpfutiljni/com_android_net_module_util_BpfUtils.cpp @@ -0,0 +1,132 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "BpfSyscallWrappers.h" + +namespace android { + +using base::unique_fd; + +// If attach fails throw error and return false. +static jboolean com_android_net_module_util_BpfUtil_attachProgramToCgroup(JNIEnv *env, + jobject clazz, jint type, jstring bpfProgPath, jstring cgroupPath, jint flags) { + + ScopedUtfChars dirPath(env, cgroupPath); + unique_fd cg_fd(open(dirPath.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC)); + if (cg_fd == -1) { + jniThrowExceptionFmt(env, "java/io/IOException", + "Failed to open the cgroup directory %s: %s", + dirPath.c_str(), strerror(errno)); + return false; + } + + ScopedUtfChars bpfProg(env, bpfProgPath); + unique_fd bpf_fd(bpf::retrieveProgram(bpfProg.c_str())); + if (bpf_fd == -1) { + jniThrowExceptionFmt(env, "java/io/IOException", + "Failed to retrieve bpf program from %s: %s", + bpfProg.c_str(), strerror(errno)); + return false; + } + if (bpf::attachProgram((bpf_attach_type) type, bpf_fd, cg_fd, flags)) { + jniThrowExceptionFmt(env, "java/io/IOException", + "Failed to attach bpf program %s to %s: %s", + bpfProg.c_str(), dirPath.c_str(), strerror(errno)); + return false; + } + return true; +} + +// If detach fails throw error and return false. +static jboolean com_android_net_module_util_BpfUtil_detachProgramFromCgroup(JNIEnv *env, + jobject clazz, jint type, jstring cgroupPath) { + + ScopedUtfChars dirPath(env, cgroupPath); + unique_fd cg_fd(open(dirPath.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC)); + if (cg_fd == -1) { + jniThrowExceptionFmt(env, "java/io/IOException", + "Failed to open the cgroup directory %s: %s", + dirPath.c_str(), strerror(errno)); + return false; + } + + if (bpf::detachProgram((bpf_attach_type) type, cg_fd)) { + jniThrowExceptionFmt(env, "Failed to detach bpf program from %s: %s", + dirPath.c_str(), strerror(errno)); + return false; + } + return true; +} + +// If detach single program fails throw error and return false. +static jboolean com_android_net_module_util_BpfUtil_detachSingleProgramFromCgroup(JNIEnv *env, + jobject clazz, jint type, jstring bpfProgPath, jstring cgroupPath) { + + ScopedUtfChars dirPath(env, cgroupPath); + unique_fd cg_fd(open(dirPath.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC)); + if (cg_fd == -1) { + jniThrowExceptionFmt(env, "java/io/IOException", + "Failed to open the cgroup directory %s: %s", + dirPath.c_str(), strerror(errno)); + return false; + } + + ScopedUtfChars bpfProg(env, bpfProgPath); + unique_fd bpf_fd(bpf::retrieveProgram(bpfProg.c_str())); + if (bpf_fd == -1) { + jniThrowExceptionFmt(env, "java/io/IOException", + "Failed to retrieve bpf program from %s: %s", + bpfProg.c_str(), strerror(errno)); + return false; + } + if (bpf::detachSingleProgram((bpf_attach_type) type, bpf_fd, cg_fd)) { + jniThrowExceptionFmt(env, "Failed to detach bpf program %s from %s: %s", + bpfProg.c_str(), dirPath.c_str(), strerror(errno)); + return false; + } + return true; +} + +/* + * JNI registration. + */ +static const JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + { "native_attachProgramToCgroup", "(ILjava/lang/String;Ljava/lang/String;I)Z", + (void*) com_android_net_module_util_BpfUtil_attachProgramToCgroup }, + { "native_detachProgramFromCgroup", "(ILjava/lang/String;)Z", + (void*) com_android_net_module_util_BpfUtil_detachProgramFromCgroup }, + { "native_detachSingleProgramFromCgroup", "(ILjava/lang/String;Ljava/lang/String;)Z", + (void*) com_android_net_module_util_BpfUtil_detachSingleProgramFromCgroup }, +}; + +int register_com_android_net_module_util_BpfUtils(JNIEnv* env, char const* class_name) { + return jniRegisterNativeMethods(env, + class_name, + gMethods, NELEM(gMethods)); +} + +}; // namespace android From 0a31b342a131c2576333f494974f464975b28ac6 Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Wed, 2 Mar 2022 11:09:53 +0800 Subject: [PATCH 404/777] BpfUtils.h - switch to GTEST_SKIP in all 4 SKIP macros patch the missing commit I3acb47a432378f257418f81b26516e18d6ff3780. Test: TreeHugger, atest libbpf_android_test netd_unit_test netd_integration_test Change-Id: I6b7114584759c0689e0d6b852387b93a799f663f --- .../native/bpf_headers/include/bpf/BpfUtils.h | 42 +++++++------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index 265d4b6300..8f1b9a28ac 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -112,38 +112,28 @@ static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsign return kernelVersion() >= KVER(major, minor, sub); } -#define SKIP_IF_BPF_SUPPORTED \ - do { \ - if (android::bpf::isAtLeastKernelVersion(4, 9, 0)) { \ - GTEST_LOG_(INFO) << "This test is skipped since bpf is supported\n"; \ - return; \ - } \ +#define SKIP_IF_BPF_SUPPORTED \ + do { \ + if (android::bpf::isAtLeastKernelVersion(4, 9, 0)) \ + GTEST_SKIP() << "Skip: bpf is supported."; \ } while (0) -#define SKIP_IF_BPF_NOT_SUPPORTED \ - do { \ - if (!android::bpf::isAtLeastKernelVersion(4, 9, 0)) { \ - GTEST_LOG_(INFO) << "This test is skipped since bpf is not supported\n"; \ - return; \ - } \ +#define SKIP_IF_BPF_NOT_SUPPORTED \ + do { \ + if (!android::bpf::isAtLeastKernelVersion(4, 9, 0)) \ + GTEST_SKIP() << "Skip: bpf is not supported."; \ } while (0) -#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED \ - do { \ - if (!android::bpf::isAtLeastKernelVersion(4, 14, 0)) { \ - GTEST_LOG_(INFO) << "This test is skipped since extended bpf feature" \ - << "not supported\n"; \ - return; \ - } \ +#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED \ + do { \ + if (!android::bpf::isAtLeastKernelVersion(4, 14, 0)) \ + GTEST_SKIP() << "Skip: extended bpf feature not supported."; \ } while (0) -#define SKIP_IF_XDP_NOT_SUPPORTED \ - do { \ - if (!android::bpf::isAtLeastKernelVersion(5, 9, 0)) { \ - GTEST_LOG_(INFO) << "This test is skipped since xdp" \ - << "not supported\n"; \ - return; \ - } \ +#define SKIP_IF_XDP_NOT_SUPPORTED \ + do { \ + if (!android::bpf::isAtLeastKernelVersion(5, 9, 0)) \ + GTEST_SKIP() << "Skip: xdp not supported."; \ } while (0) } // namespace bpf From 6230a517f3935d905d932b481196e0c74ac0c93d Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Fri, 4 Mar 2022 16:43:21 +0100 Subject: [PATCH 405/777] Move InterfaceParamsTest to frameworks/libs/net Test: atest NetworkStaticLibTests Bug: 222448728 Change-Id: I9fc547203c592ad2ade506df68511468db6a5686 --- .../net/module/util/InterfaceParamsTest.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/InterfaceParamsTest.java diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/InterfaceParamsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/InterfaceParamsTest.java new file mode 100644 index 0000000000..a1d8c10602 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/InterfaceParamsTest.java @@ -0,0 +1,54 @@ +/* + * 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 com.android.net.module.util; + +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 androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class InterfaceParamsTest { + @Test + public void testNullInterfaceReturnsNull() { + assertNull(InterfaceParams.getByName(null)); + } + + @Test + public void testNonExistentInterfaceReturnsNull() { + assertNull(InterfaceParams.getByName("doesnotexist0")); + } + + @Test + public void testLoopback() { + final InterfaceParams ifParams = InterfaceParams.getByName("lo"); + assertNotNull(ifParams); + assertEquals("lo", ifParams.name); + assertTrue(ifParams.index > 0); + assertNotNull(ifParams.macAddr); + assertFalse(ifParams.hasMacAddress); + assertTrue(ifParams.defaultMtu >= NetworkStackConstants.ETHER_MTU); + } +} From 2bbc2f79de3c052d49bc039f11be15d1c28ec12c Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Mon, 24 Jan 2022 07:58:12 +0000 Subject: [PATCH 406/777] Make net-utils-services-common visible to service-connectivity-tiramisu. Ethernet service sources are moving to Connectivity module, which has dependency on the NetworkFactory class such as EthernetNetworkFactory. Import this lib in service-connectivity-tiramisu-pre-jarjar to fix this dependency. Bug: 202086915 Test: m Change-Id: I2f92479f56af110d89c9fa95eca725af7132b66f --- staticlibs/Android.bp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index bdd0c74223..0e4dac23cb 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -287,9 +287,15 @@ java_library { "framework-annotations-lib", "framework-connectivity", ], + // TODO: remove "apex_available:platform". + apex_available: [ + "//apex_available:platform", + "com.android.tethering", + ], visibility: [ // TODO: remove after NetworkStatsService moves to the module. "//frameworks/base/services/net", + "//packages/modules/Connectivity/service", "//packages/modules/Connectivity/tests:__subpackages__", "//packages/modules/Bluetooth/android/app", ], From f0114970dcf7a63e8471539dfd945deaf0c51c93 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Tue, 8 Mar 2022 17:46:38 +0800 Subject: [PATCH 407/777] Add struct ClatEgress4Key This is a preparation for moving clat map access to java BpfMap class Test: make net-utils-device-common-bpf Change-Id: Iaa0e264708b7f8df249e4095dd3a0775f6b65e96 --- .../net/module/util/bpf/ClatEgress4Key.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/bpf/ClatEgress4Key.java diff --git a/staticlibs/device/com/android/net/module/util/bpf/ClatEgress4Key.java b/staticlibs/device/com/android/net/module/util/bpf/ClatEgress4Key.java new file mode 100644 index 0000000000..12200ec60f --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/bpf/ClatEgress4Key.java @@ -0,0 +1,37 @@ +/* + * 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 com.android.net.module.util.bpf; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.Inet4Address; + +/** Key type for clat egress IPv4 maps. */ +public class ClatEgress4Key extends Struct { + @Field(order = 0, type = Type.U32) + public final long iif; // The input interface index + + @Field(order = 1, type = Type.Ipv4Address) + public final Inet4Address local4; // The source IPv4 address + + public ClatEgress4Key(final long iif, final Inet4Address local4) { + this.iif = iif; + this.local4 = local4; + } +} From 184ff2abdbc9291e9da45284208183f07d871a5a Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Tue, 8 Mar 2022 17:51:50 +0800 Subject: [PATCH 408/777] Add struct ClatEgress4Value This is a preparation for moving clat map access to java BpfMap class Test: make net-utils-device-common-bpf Change-Id: I0260c62804ea0edf743c58f2a6d7c1d6a799c187 --- .../net/module/util/bpf/ClatEgress4Value.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/bpf/ClatEgress4Value.java diff --git a/staticlibs/device/com/android/net/module/util/bpf/ClatEgress4Value.java b/staticlibs/device/com/android/net/module/util/bpf/ClatEgress4Value.java new file mode 100644 index 0000000000..c10cb4da32 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/bpf/ClatEgress4Value.java @@ -0,0 +1,46 @@ +/* + * 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 com.android.net.module.util.bpf; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.Inet6Address; + +/** Value type for clat egress IPv4 maps. */ +public class ClatEgress4Value extends Struct { + @Field(order = 0, type = Type.U32) + public final long oif; // The output interface to redirect to + + @Field(order = 1, type = Type.Ipv6Address) + public final Inet6Address local6; // The full 128-bits of the source IPv6 address + + @Field(order = 2, type = Type.Ipv6Address) + public final Inet6Address pfx96; // The destination /96 nat64 prefix, bottom 32 bits must be 0 + + @Field(order = 3, type = Type.U8, padding = 3) + public final short oifIsEthernet; // Whether the output interface requires ethernet header + + public ClatEgress4Value(final long oif, final Inet6Address local6, final Inet6Address pfx96, + final short oifIsEthernet) { + this.oif = oif; + this.local6 = local6; + this.pfx96 = pfx96; + this.oifIsEthernet = oifIsEthernet; + } +} From 6ad2029c427b01fd0f530b1502dcccadf6066a9f Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Tue, 8 Mar 2022 17:53:05 +0800 Subject: [PATCH 409/777] Add struct ClatIngress6Key This is a preparation for moving clat map access to java BpfMap class Test: make net-utils-device-common-bpf Change-Id: I869a9afa45a5257be028dae5b9d627f891222c80 --- .../net/module/util/bpf/ClatIngress6Key.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/bpf/ClatIngress6Key.java diff --git a/staticlibs/device/com/android/net/module/util/bpf/ClatIngress6Key.java b/staticlibs/device/com/android/net/module/util/bpf/ClatIngress6Key.java new file mode 100644 index 0000000000..1e2f4e06d6 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/bpf/ClatIngress6Key.java @@ -0,0 +1,41 @@ +/* + * 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 com.android.net.module.util.bpf; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.Inet6Address; + +/** Key type for clat ingress IPv6 maps. */ +public class ClatIngress6Key extends Struct { + @Field(order = 0, type = Type.U32) + public final long iif; // The input interface index + + @Field(order = 1, type = Type.Ipv6Address) + public final Inet6Address pfx96; // The source /96 nat64 prefix, bottom 32 bits must be 0 + + @Field(order = 2, type = Type.Ipv6Address) + public final Inet6Address local6; // The full 128-bits of the destination IPv6 address + + public ClatIngress6Key(final long iif, final Inet6Address pfx96, final Inet6Address local6) { + this.iif = iif; + this.pfx96 = pfx96; + this.local6 = local6; + } +} From c9f217cde301cc79895cdd026ee9da0646ca0227 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Tue, 8 Mar 2022 17:53:52 +0800 Subject: [PATCH 410/777] Add struct ClatIngress6Value This is a preparation for moving clat map access to java BpfMap class Test: make net-utils-device-common-bpf Change-Id: I7dec8bc368fa8de7cf44656d0dc1477b2a5a647b --- .../module/util/bpf/ClatIngress6Value.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/bpf/ClatIngress6Value.java diff --git a/staticlibs/device/com/android/net/module/util/bpf/ClatIngress6Value.java b/staticlibs/device/com/android/net/module/util/bpf/ClatIngress6Value.java new file mode 100644 index 0000000000..bfec44fac2 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/bpf/ClatIngress6Value.java @@ -0,0 +1,37 @@ +/* + * 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 com.android.net.module.util.bpf; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.Inet4Address; + +/** Value type for clat ingress IPv6 maps. */ +public class ClatIngress6Value extends Struct { + @Field(order = 0, type = Type.U32) + public final long oif; // The output interface to redirect to (0 means don't redirect) + + @Field(order = 1, type = Type.Ipv4Address) + public final Inet4Address local4; // The destination IPv4 address + + public ClatIngress6Value(final long oif, final Inet4Address local4) { + this.oif = oif; + this.local4 = local4; + } +} From d12797dba4181c8f7bac5a2cf1580087eeaf7e15 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 25 Feb 2022 17:29:19 +0900 Subject: [PATCH 411/777] Add DisableConfigSyncTargetPreparer The TargetPreparer disables DeviceConfig sync before a test module, and attempts to reset it to its original state afterwards. It only supports S+ as the associated commands are not available on R-. The format of commands has also changed in some T branches , so support legacy format if the newer format is not supported by the device. Bug: 210377950 Test: atest CtsNetTestCases using the preparer, verify setting set during the test. Change-Id: Iaabaa1050b024e1378ab1cf87a394cc8ebab227b --- .../DisableConfigSyncTargetPreparer.kt | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 staticlibs/testutils/host/com/android/testutils/DisableConfigSyncTargetPreparer.kt diff --git a/staticlibs/testutils/host/com/android/testutils/DisableConfigSyncTargetPreparer.kt b/staticlibs/testutils/host/com/android/testutils/DisableConfigSyncTargetPreparer.kt new file mode 100644 index 0000000000..63f05a6cb1 --- /dev/null +++ b/staticlibs/testutils/host/com/android/testutils/DisableConfigSyncTargetPreparer.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2021 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 com.android.testutils + +import com.android.tradefed.invoker.TestInformation +import com.android.tradefed.targetprep.BaseTargetPreparer + +/** + * A target preparer that disables DeviceConfig sync while running a test. + * + * Without this preparer, tests that rely on stable values of DeviceConfig flags, for example to + * test behavior when setting the flag and resetting it afterwards, may flake as the flags may + * be synced with remote servers during the test. + */ +class DisableConfigSyncTargetPreparer : BaseTargetPreparer() { + private var syncDisabledOriginalValue = "none" + + override fun setUp(testInfo: TestInformation) { + if (isDisabled) return + syncDisabledOriginalValue = readSyncDisabledOriginalValue(testInfo) + + // The setter is the same in current and legacy S versions + testInfo.exec("cmd device_config set_sync_disabled_for_tests until_reboot") + } + + override fun tearDown(testInfo: TestInformation, e: Throwable?) { + if (isTearDownDisabled) return + // May fail harmlessly if called before S + testInfo.exec("cmd device_config set_sync_disabled_for_tests $syncDisabledOriginalValue") + } + + private fun readSyncDisabledOriginalValue(testInfo: TestInformation): String { + return when (val reply = testInfo.exec("cmd device_config get_sync_disabled_for_tests")) { + "until_reboot", "persistent", "none" -> reply + // Reply does not match known modes, try legacy commands used on S and some T builds + else -> when (testInfo.exec("cmd device_config is_sync_disabled_for_tests")) { + // The legacy command just said "true" for "until_reboot" or "persistent". There is + // no way to know which one was used, so just reset to "until_reboot" to be + // conservative. + "true" -> "until_reboot" + else -> "none" + } + } + } +} + +private fun TestInformation.exec(cmd: String) = this.device.executeShellCommand(cmd) \ No newline at end of file From 4806feb3a5e39b5baf40220c6fae87b1851964cd Mon Sep 17 00:00:00 2001 From: Stephane Lee Date: Tue, 8 Mar 2022 17:32:12 -0800 Subject: [PATCH 412/777] Allow use of shared bpf headers by recovery This will allow healthd to filter uevent packets, if needed Bug: 203462310 Test: Ensure that healthd can build if it uses bpf filters Change-Id: I97bfe9509a6934444f656508176495bba38381be --- staticlibs/native/bpf_headers/Android.bp | 1 + staticlibs/native/bpf_syscall_wrappers/Android.bp | 1 + 2 files changed, 2 insertions(+) diff --git a/staticlibs/native/bpf_headers/Android.bp b/staticlibs/native/bpf_headers/Android.bp index 4c8e728f05..98694b2b80 100644 --- a/staticlibs/native/bpf_headers/Android.bp +++ b/staticlibs/native/bpf_headers/Android.bp @@ -19,6 +19,7 @@ package { cc_library_headers { name: "bpf_headers", vendor_available: true, + recovery_available: true, host_supported: true, native_bridge_supported: true, header_libs: ["bpf_syscall_wrappers"], diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index f41a2446fe..125d631bdd 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -19,6 +19,7 @@ package { cc_library_headers { name: "bpf_syscall_wrappers", vendor_available: true, + recovery_available: true, host_supported: true, native_bridge_supported: true, export_include_dirs: ["include"], From 4e70104466f88b0fb0632f4b58f34be6dd116ad7 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 7 Mar 2022 11:17:14 +0800 Subject: [PATCH 413/777] [DU04-3]Appropriate changes to the NetworkPolicyManager API Divide the NetworkPolicyManager API notifyStatsProviderWarningOrLimitReached into the following two APIs: 1. notifyStatsProviderWarningReached() 2. notifyStatsProviderLimitReached() Bug: 216474563 Test: atest NetworkStatsServiceTest NetworkPolicyManagerTest NetworkPolicyManagerServiceTest OffloadControllerTest Change-Id: I9d399ea32b656727bf155283265693d3f0d4b9cf --- .../NetworkStatsProviderCbStubCompat.java | 7 ++++-- .../TestableNetworkStatsProviderCbBinder.kt | 24 ++++++++++++------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/NetworkStatsProviderCbStubCompat.java b/staticlibs/testutils/devicetests/com/android/testutils/NetworkStatsProviderCbStubCompat.java index e84a224f30..642da7ac9a 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/NetworkStatsProviderCbStubCompat.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/NetworkStatsProviderCbStubCompat.java @@ -32,10 +32,13 @@ public class NetworkStatsProviderCbStubCompat extends INetworkStatsProviderCallb @Override public void notifyAlertReached() throws RemoteException {} - // Removed in S. + /** Added in T. */ public void notifyLimitReached() throws RemoteException {} - // Added in S. + /** Added in T. */ + public void notifyWarningReached() throws RemoteException {} + + /** Added in S, removed in T. */ public void notifyWarningOrLimitReached() throws RemoteException {} @Override diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt index c039cad174..5547c90a48 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkStatsProviderCbBinder.kt @@ -31,8 +31,9 @@ open class TestableNetworkStatsProviderCbBinder : NetworkStatsProviderCbStubComp val ifaceStats: NetworkStats, val uidStats: NetworkStats ) : CallbackType() + object NotifyWarningReached : CallbackType() + object NotifyLimitReached : CallbackType() object NotifyWarningOrLimitReached : CallbackType() - object LegacyNotifyLimitReached : CallbackType() object NotifyAlertReached : CallbackType() object Unregister : CallbackType() } @@ -43,13 +44,17 @@ open class TestableNetworkStatsProviderCbBinder : NetworkStatsProviderCbStubComp history.add(CallbackType.NotifyStatsUpdated(token, ifaceStats, uidStats)) } - override fun notifyWarningOrLimitReached() { - history.add(CallbackType.NotifyWarningOrLimitReached) + override fun notifyWarningReached() { + history.add(CallbackType.NotifyWarningReached) } override fun notifyLimitReached() { - // Older callback renamed to notifyWarningOrLimitReached in S - history.add(CallbackType.LegacyNotifyLimitReached) + history.add(CallbackType.NotifyLimitReached) + } + + override fun notifyWarningOrLimitReached() { + // Older callback is split into notifyLimitReached and notifyWarningReached in T. + history.add(CallbackType.NotifyWarningOrLimitReached) } override fun notifyAlertReached() { @@ -75,12 +80,15 @@ open class TestableNetworkStatsProviderCbBinder : NetworkStatsProviderCbStubComp assertNetworkStatsEquals(uidStats, event.uidStats) } + fun expectNotifyWarningReached() = + assertEquals(CallbackType.NotifyWarningReached, history.poll(DEFAULT_TIMEOUT_MS)) + + fun expectNotifyLimitReached() = + assertEquals(CallbackType.NotifyLimitReached, history.poll(DEFAULT_TIMEOUT_MS)) + fun expectNotifyWarningOrLimitReached() = assertEquals(CallbackType.NotifyWarningOrLimitReached, history.poll(DEFAULT_TIMEOUT_MS)) - fun expectLegacyNotifyLimitReached() = - assertEquals(CallbackType.LegacyNotifyLimitReached, history.poll(DEFAULT_TIMEOUT_MS)) - fun expectNotifyAlertReached() = assertEquals(CallbackType.NotifyAlertReached, history.poll(DEFAULT_TIMEOUT_MS)) From 556c8010c9d34ab105f4f7f0d851190a556a20e1 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Wed, 16 Mar 2022 22:16:26 +0800 Subject: [PATCH 414/777] TcUtils: add tcQdiscAddDevClsact Support tc command: $ tc qdisc add dev .. clsact Test: TreeHugger Change-Id: I98abcb59418ab12b6e4de0f42a18ded4677ddbfc --- .../com/android/net/module/util/TcUtils.java | 11 +++++++++++ .../com_android_net_module_util_TcUtils.cpp | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/TcUtils.java b/staticlibs/device/com/android/net/module/util/TcUtils.java index cf01490b5c..9d2fb7f9d4 100644 --- a/staticlibs/device/com/android/net/module/util/TcUtils.java +++ b/staticlibs/device/com/android/net/module/util/TcUtils.java @@ -90,4 +90,15 @@ public class TcUtils { */ public static native void tcFilterDelDev(int ifIndex, boolean ingress, short prio, short proto) throws IOException; + + /** + * Add a clsact qdisc. + * + * Equivalent to the following 'tc' command: + * tc qdisc add dev .. clsact + * + * @param ifIndex the network interface index. + * @throws IOException + */ + public static native void tcQdiscAddDevClsact(int ifIndex) throws IOException; } diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp index 2307a6bbe1..073a46f1fa 100644 --- a/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp +++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp @@ -84,6 +84,18 @@ static void com_android_net_module_util_TcUtils_tcFilterDelDev( } } +// tc qdisc add dev .. clsact +static void com_android_net_module_util_TcUtils_tcQdiscAddDevClsact(JNIEnv *env, + jobject clazz, + jint ifIndex) { + int error = tcAddQdiscClsact(ifIndex); + if (error) { + throwIOException( + env, + "com_android_net_module_util_TcUtils_tcQdiscAddDevClsact error: ", error); + } +} + /* * JNI registration. */ @@ -97,6 +109,8 @@ static const JNINativeMethod gMethods[] = { (void *)com_android_net_module_util_TcUtils_tcFilterAddDevIngressPolice}, {"tcFilterDelDev", "(IZSS)V", (void *)com_android_net_module_util_TcUtils_tcFilterDelDev}, + {"tcQdiscAddDevClsact", "(I)V", + (void *)com_android_net_module_util_TcUtils_tcQdiscAddDevClsact}, }; int register_com_android_net_module_util_TcUtils(JNIEnv *env, From b80c7f9033441b192972db222da878932e9e1ca5 Mon Sep 17 00:00:00 2001 From: William Escande Date: Fri, 18 Mar 2022 18:39:18 +0100 Subject: [PATCH 415/777] Clear apex.go entries for bluetooth libs The module availability to Bluetooth is currently hard-coded in apex.go. We are in the process of cleaning the apex.go by adding the availability in each required module Test: Build + TH + boot phone & use bluetooth Bug: 216433795 Change-Id: I7b9e2a95e9fda0f25786e113d78bca81a4406abf --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 0e4dac23cb..e0b75c5c77 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -290,6 +290,7 @@ java_library { // TODO: remove "apex_available:platform". apex_available: [ "//apex_available:platform", + "com.android.bluetooth", "com.android.tethering", ], visibility: [ From 630388df2c5bc8d0663c8b30bd087e936a9f3df6 Mon Sep 17 00:00:00 2001 From: Taras Antoshchuk Date: Thu, 14 Jan 2021 21:59:02 +0100 Subject: [PATCH 416/777] Check RouteInfo type in NetUtils#selectBestRoute Change #selectBestRoute to account for non-unicast routes. Method is used to detect if the address is reachable and via which gateway. From that point of view, address being best matched by a non-unicast route is equivalent to the address not being matched by any route at all. Method's implementation is adjusted to reflect the above logic. This allows to avoid changing method's usages. Bug: 186082280 Test: atest NetworkStaticLibTests:NetUtilsTest Change-Id: I03f19d611fd8c7019cf13062bbeb1662d41402f4 --- .../com/android/net/module/util/NetUtils.java | 12 ++- .../android/net/module/util/NetUtilsTest.java | 84 ++++++++++++++----- 2 files changed, 71 insertions(+), 25 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetUtils.java b/staticlibs/framework/com/android/net/module/util/NetUtils.java index f08257ae17..ae1b9bbc89 100644 --- a/staticlibs/framework/com/android/net/module/util/NetUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetUtils.java @@ -44,7 +44,9 @@ public final class NetUtils { /** * Find the route from a Collection of routes that best matches a given address. - * May return null if no routes are applicable. + * May return null if no routes are applicable, or the best route is not a route of + * {@link RouteInfo.RTN_UNICAST} type. + * * @param routes a Collection of RouteInfos to chose from * @param dest the InetAddress your trying to get to * @return the RouteInfo from the Collection that best fits the given address @@ -55,6 +57,7 @@ public final class NetUtils { if ((routes == null) || (dest == null)) return null; RouteInfo bestRoute = null; + // pick a longest prefix match under same address type for (RouteInfo route : routes) { if (addressTypeMatches(route.getDestination().getAddress(), dest)) { @@ -66,7 +69,12 @@ public final class NetUtils { if (route.matches(dest)) bestRoute = route; } } - return bestRoute; + + if (bestRoute != null && bestRoute.getType() == RouteInfo.RTN_UNICAST) { + return bestRoute; + } else { + return null; + } } /** diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/NetUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/NetUtilsTest.java index 902c18ebe0..9e635c2124 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/NetUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetUtilsTest.java @@ -16,9 +16,12 @@ package com.android.net.module.util; +import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.net.InetAddresses; @@ -27,6 +30,10 @@ import android.net.RouteInfo; import androidx.test.runner.AndroidJUnit4; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; + +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -36,6 +43,9 @@ import java.util.List; @RunWith(AndroidJUnit4.class) public final class NetUtilsTest { + @Rule + public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(); + private static final InetAddress V4_ADDR1 = toInetAddress("75.208.7.1"); private static final InetAddress V4_ADDR2 = toInetAddress("75.208.7.2"); private static final InetAddress V6_ADDR1 = toInetAddress("2001:0db8:85a3::8a2e:0370:7334"); @@ -44,9 +54,18 @@ public final class NetUtilsTest { private static final InetAddress V4_GATEWAY = toInetAddress("75.208.8.1"); private static final InetAddress V6_GATEWAY = toInetAddress("fe80::6:0000:613"); + private static final InetAddress V4_DEST = toInetAddress("75.208.8.15"); + private static final InetAddress V6_DEST = toInetAddress("2001:db8:cafe::123"); + + private static final RouteInfo V4_EXPECTED = new RouteInfo(new IpPrefix("75.208.8.0/24"), + V4_GATEWAY, "wlan0"); + private static final RouteInfo V6_EXPECTED = new RouteInfo(new IpPrefix("2001:db8:cafe::/64"), + V6_GATEWAY, "wlan0"); + private static InetAddress toInetAddress(String addr) { return InetAddresses.parseNumericAddress(addr); } + @Test public void testAddressTypeMatches() { assertTrue(NetUtils.addressTypeMatches(V4_ADDR1, V4_ADDR2)); @@ -58,48 +77,67 @@ public final class NetUtilsTest { @Test public void testSelectBestRoute() { final List routes = new ArrayList<>(); - final InetAddress v4_dest = InetAddresses.parseNumericAddress("75.208.8.15"); - final InetAddress v6_dest = InetAddresses.parseNumericAddress("2001:db8:cafe::123"); - RouteInfo route = NetUtils.selectBestRoute(null, v4_dest); - assertEquals(null, route); + RouteInfo route = NetUtils.selectBestRoute(null, V4_DEST); + assertNull(route); route = NetUtils.selectBestRoute(routes, null); - assertEquals(null, route); + assertNull(route); - route = NetUtils.selectBestRoute(routes, v4_dest); - assertEquals(null, route); + route = NetUtils.selectBestRoute(routes, V4_DEST); + assertNull(route); - final RouteInfo v4_expected = new RouteInfo(new IpPrefix("75.208.8.0/24"), - V4_GATEWAY, "wlan0"); - routes.add(v4_expected); + routes.add(V4_EXPECTED); // "75.208.0.0/16" is not an expected result since it is not the longest prefix. routes.add(new RouteInfo(new IpPrefix("75.208.0.0/16"), V4_GATEWAY, "wlan0")); routes.add(new RouteInfo(new IpPrefix("75.208.7.0/24"), V4_GATEWAY, "wlan0")); - final RouteInfo v6_expected = new RouteInfo(new IpPrefix("2001:db8:cafe::/64"), - V6_GATEWAY, "wlan0"); - routes.add(v6_expected); + routes.add(V6_EXPECTED); // "2001:db8::/32" is not an expected result since it is not the longest prefix. routes.add(new RouteInfo(new IpPrefix("2001:db8::/32"), V6_GATEWAY, "wlan0")); routes.add(new RouteInfo(new IpPrefix("2001:db8:beef::/64"), V6_GATEWAY, "wlan0")); // Verify expected v4 route is selected - route = NetUtils.selectBestRoute(routes, v4_dest); - assertEquals(v4_expected, route); + route = NetUtils.selectBestRoute(routes, V4_DEST); + assertEquals(V4_EXPECTED, route); // Verify expected v6 route is selected - route = NetUtils.selectBestRoute(routes, v6_dest); - assertEquals(v6_expected, route); + route = NetUtils.selectBestRoute(routes, V6_DEST); + assertEquals(V6_EXPECTED, route); // Remove expected v4 route - routes.remove(v4_expected); - route = NetUtils.selectBestRoute(routes, v4_dest); - assertNotEquals(v4_expected, route); + routes.remove(V4_EXPECTED); + route = NetUtils.selectBestRoute(routes, V4_DEST); + assertNotEquals(V4_EXPECTED, route); // Remove expected v6 route - routes.remove(v6_expected); - route = NetUtils.selectBestRoute(routes, v4_dest); - assertNotEquals(v6_expected, route); + routes.remove(V6_EXPECTED); + route = NetUtils.selectBestRoute(routes, V4_DEST); + assertNotEquals(V6_EXPECTED, route); + } + + @Test @IgnoreUpTo(SC_V2) + public void testSelectBestRouteWithExcludedRoutes() { + final List routes = new ArrayList<>(); + + routes.add(V4_EXPECTED); + routes.add(new RouteInfo(new IpPrefix("75.208.0.0/16"), V4_GATEWAY, "wlan0")); + routes.add(new RouteInfo(new IpPrefix("75.208.7.0/24"), V4_GATEWAY, "wlan0")); + + routes.add(V6_EXPECTED); + routes.add(new RouteInfo(new IpPrefix("2001:db8::/32"), V6_GATEWAY, "wlan0")); + routes.add(new RouteInfo(new IpPrefix("2001:db8:beef::/64"), V6_GATEWAY, "wlan0")); + + // After adding excluded v4 route with longer prefix, expected result is null. + routes.add(new RouteInfo(new IpPrefix("75.208.8.0/28"), null /* gateway */, "wlan0", + RouteInfo.RTN_THROW)); + RouteInfo route = NetUtils.selectBestRoute(routes, V4_DEST); + assertNull(route); + + // After adding excluded v6 route with longer prefix, expected result is null. + routes.add(new RouteInfo(new IpPrefix("2001:db8:cafe::/96"), null /* gateway */, "wlan0", + RouteInfo.RTN_THROW)); + route = NetUtils.selectBestRoute(routes, V6_DEST); + assertNull(route); } } From ba48d1096975a11ed9fcae02a049984dcd6f215a Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Tue, 29 Mar 2022 19:06:31 +0200 Subject: [PATCH 417/777] Make libtcutils visible to netd tests Test: TH Change-Id: I71943cfd2fb72dca8a7ffd5d063860b89be47ca1 --- staticlibs/native/tcutils/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/native/tcutils/Android.bp b/staticlibs/native/tcutils/Android.bp index e819e4c094..88a26832b4 100644 --- a/staticlibs/native/tcutils/Android.bp +++ b/staticlibs/native/tcutils/Android.bp @@ -39,7 +39,7 @@ cc_library_static { visibility: [ "//frameworks/libs/net/common/native/bpfmapjni", "//packages/modules/Connectivity:__subpackages__", - "//system/netd/server", + "//system/netd:__subpackages__", ], } From 483b35696590ad5536be89dab2feed90a5203680 Mon Sep 17 00:00:00 2001 From: paulhu Date: Fri, 14 Jan 2022 15:30:06 +0800 Subject: [PATCH 418/777] Add MDNS aidl - Add MDNS aidl that NsdService can communicate with mdns service via binder call instead of using ndc. - Add mdns_aidl_interface to separate the mdns aidl from netd_aidl_interface. Bug: 209894875 Test: atest FrameworksNetTests CtsNetTestCases Change-Id: I7bcbd6146269bdd9ac973d651a676bd9d126ae2d --- staticlibs/netd/Android.bp | 18 +++ .../android/net/mdns/aidl/DiscoveryInfo.aidl | 45 +++++++ .../android/net/mdns/aidl/GetAddressInfo.aidl | 44 ++++++ .../current/android/net/mdns/aidl/IMDns.aidl | 46 +++++++ .../net/mdns/aidl/IMDnsEventListener.aidl | 50 +++++++ .../net/mdns/aidl/RegistrationInfo.aidl | 45 +++++++ .../android/net/mdns/aidl/ResolutionInfo.aidl | 48 +++++++ .../android/net/mdns/aidl/DiscoveryInfo.aidl | 79 +++++++++++ .../android/net/mdns/aidl/GetAddressInfo.aidl | 69 ++++++++++ .../binder/android/net/mdns/aidl/IMDns.aidl | 127 ++++++++++++++++++ .../net/mdns/aidl/IMDnsEventListener.aidl | 66 +++++++++ .../net/mdns/aidl/RegistrationInfo.aidl | 78 +++++++++++ .../android/net/mdns/aidl/ResolutionInfo.aidl | 92 +++++++++++++ 13 files changed, 807 insertions(+) create mode 100644 staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/DiscoveryInfo.aidl create mode 100644 staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/GetAddressInfo.aidl create mode 100644 staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/IMDns.aidl create mode 100644 staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/IMDnsEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/RegistrationInfo.aidl create mode 100644 staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/ResolutionInfo.aidl create mode 100644 staticlibs/netd/binder/android/net/mdns/aidl/DiscoveryInfo.aidl create mode 100644 staticlibs/netd/binder/android/net/mdns/aidl/GetAddressInfo.aidl create mode 100644 staticlibs/netd/binder/android/net/mdns/aidl/IMDns.aidl create mode 100644 staticlibs/netd/binder/android/net/mdns/aidl/IMDnsEventListener.aidl create mode 100644 staticlibs/netd/binder/android/net/mdns/aidl/RegistrationInfo.aidl create mode 100644 staticlibs/netd/binder/android/net/mdns/aidl/ResolutionInfo.aidl diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index e249e19d99..b06d708936 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -156,3 +156,21 @@ aidl_interface { }, }, } + +aidl_interface { + name: "mdns_aidl_interface", + local_include_dir: "binder", + srcs: [ + "binder/android/net/mdns/aidl/**/*.aidl", + ], + backend: { + java: { + sdk_version: "module_current", + apex_available: [ + "//apex_available:platform", + "com.android.tethering", + ], + min_sdk_version: "30", + }, + }, +} diff --git a/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/DiscoveryInfo.aidl b/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/DiscoveryInfo.aidl new file mode 100644 index 0000000000..d31a327893 --- /dev/null +++ b/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/DiscoveryInfo.aidl @@ -0,0 +1,45 @@ +/* + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.mdns.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable DiscoveryInfo { + int id; + int result; + @utf8InCpp String serviceName; + @utf8InCpp String registrationType; + @utf8InCpp String domainName; + int interfaceIdx; + int netId; +} diff --git a/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/GetAddressInfo.aidl b/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/GetAddressInfo.aidl new file mode 100644 index 0000000000..2049274454 --- /dev/null +++ b/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/GetAddressInfo.aidl @@ -0,0 +1,44 @@ +/* + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.mdns.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable GetAddressInfo { + int id; + int result; + @utf8InCpp String hostname; + @utf8InCpp String address; + int interfaceIdx; + int netId; +} diff --git a/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/IMDns.aidl b/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/IMDns.aidl new file mode 100644 index 0000000000..ecbe966dea --- /dev/null +++ b/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/IMDns.aidl @@ -0,0 +1,46 @@ +/* + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.mdns.aidl; +/* @hide */ +interface IMDns { + void startDaemon(); + void stopDaemon(); + void registerService(in android.net.mdns.aidl.RegistrationInfo info); + void discover(in android.net.mdns.aidl.DiscoveryInfo info); + void resolve(in android.net.mdns.aidl.ResolutionInfo info); + void getServiceAddress(in android.net.mdns.aidl.GetAddressInfo info); + void stopOperation(int id); + void registerEventListener(in android.net.mdns.aidl.IMDnsEventListener listener); + void unregisterEventListener(in android.net.mdns.aidl.IMDnsEventListener listener); +} diff --git a/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/IMDnsEventListener.aidl b/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/IMDnsEventListener.aidl new file mode 100644 index 0000000000..4625cac7ab --- /dev/null +++ b/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/IMDnsEventListener.aidl @@ -0,0 +1,50 @@ +/** + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.mdns.aidl; +/* @hide */ +interface IMDnsEventListener { + oneway void onServiceRegistrationStatus(in android.net.mdns.aidl.RegistrationInfo status); + oneway void onServiceDiscoveryStatus(in android.net.mdns.aidl.DiscoveryInfo status); + oneway void onServiceResolutionStatus(in android.net.mdns.aidl.ResolutionInfo status); + oneway void onGettingServiceAddressStatus(in android.net.mdns.aidl.GetAddressInfo status); + const int SERVICE_DISCOVERY_FAILED = 602; + const int SERVICE_FOUND = 603; + const int SERVICE_LOST = 604; + const int SERVICE_REGISTRATION_FAILED = 605; + const int SERVICE_REGISTERED = 606; + const int SERVICE_RESOLUTION_FAILED = 607; + const int SERVICE_RESOLVED = 608; + const int SERVICE_GET_ADDR_FAILED = 611; + const int SERVICE_GET_ADDR_SUCCESS = 612; +} diff --git a/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/RegistrationInfo.aidl b/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/RegistrationInfo.aidl new file mode 100644 index 0000000000..185111b440 --- /dev/null +++ b/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/RegistrationInfo.aidl @@ -0,0 +1,45 @@ +/* + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.mdns.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable RegistrationInfo { + int id; + int result; + @utf8InCpp String serviceName; + @utf8InCpp String registrationType; + int port; + byte[] txtRecord; + int interfaceIdx; +} diff --git a/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/ResolutionInfo.aidl b/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/ResolutionInfo.aidl new file mode 100644 index 0000000000..4aa7d79114 --- /dev/null +++ b/staticlibs/netd/aidl_api/mdns_aidl_interface/current/android/net/mdns/aidl/ResolutionInfo.aidl @@ -0,0 +1,48 @@ +/* + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.mdns.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable ResolutionInfo { + int id; + int result; + @utf8InCpp String serviceName; + @utf8InCpp String registrationType; + @utf8InCpp String domain; + @utf8InCpp String serviceFullName; + @utf8InCpp String hostname; + int port; + byte[] txtRecord; + int interfaceIdx; +} diff --git a/staticlibs/netd/binder/android/net/mdns/aidl/DiscoveryInfo.aidl b/staticlibs/netd/binder/android/net/mdns/aidl/DiscoveryInfo.aidl new file mode 100644 index 0000000000..f8273828b1 --- /dev/null +++ b/staticlibs/netd/binder/android/net/mdns/aidl/DiscoveryInfo.aidl @@ -0,0 +1,79 @@ +/* + * 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.mdns.aidl; + +/** + * Discovery service information. + * This information combine all arguments that used by both request and callback. + * Arguments are used by request: + * - id + * - registrationType + * - interfaceIdx + * + * Arguments are used by callback: + * - id + * - serviceName + * - registrationType + * - domainName + * - interfaceIdx + * - netId + * - result + * + * {@hide} + */ +@JavaOnlyImmutable +@JavaDerive(equals=true, toString=true) +parcelable DiscoveryInfo { + /** + * The operation ID. + * Must be unique among all operations (registration/discovery/resolution/getting address) and + * can't be reused. + * To stop a operation, it needs to use corresponding operation id. + */ + int id; + + /** + * The discovery result. + */ + int result; + + /** + * The discovered service name. + */ + @utf8InCpp String serviceName; + + /** + * The service type being discovered for followed by the protocol, separated by a dot + * (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp". + */ + @utf8InCpp String registrationType; + + /** + * The domain of the discovered service instance. + */ + @utf8InCpp String domainName; + + /** + * The interface index on which to discover services. 0 indicates "all interfaces". + */ + int interfaceIdx; + + /** + * The net id on which the service is advertised. + */ + int netId; +} diff --git a/staticlibs/netd/binder/android/net/mdns/aidl/GetAddressInfo.aidl b/staticlibs/netd/binder/android/net/mdns/aidl/GetAddressInfo.aidl new file mode 100644 index 0000000000..d53174a4d7 --- /dev/null +++ b/staticlibs/netd/binder/android/net/mdns/aidl/GetAddressInfo.aidl @@ -0,0 +1,69 @@ +/* + * 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.mdns.aidl; + +/** + * Get service address information. + * This information combine all arguments that used by both request and callback. + * Arguments are used by request: + * - id + * - hostname + * - interfaceIdx + * + * Arguments are used by callback: + * - id + * - hostname + * - interfaceIdx + * - netId + * - address + * - result + * + * {@hide} + */ +@JavaOnlyImmutable +@JavaDerive(equals=true, toString=true) +parcelable GetAddressInfo { + /** + * The operation ID. + */ + int id; + + /** + * The getting address result. + */ + int result; + + /** + * The fully qualified domain name of the host to be queried for. + */ + @utf8InCpp String hostname; + + /** + * The service address info, it's IPv4 or IPv6 addres. + */ + @utf8InCpp String address; + + /** + * The interface index on which to issue the query. 0 indicates "all interfaces". + */ + int interfaceIdx; + + /** + * The net id to which the answers pertain. + */ + int netId; +} diff --git a/staticlibs/netd/binder/android/net/mdns/aidl/IMDns.aidl b/staticlibs/netd/binder/android/net/mdns/aidl/IMDns.aidl new file mode 100644 index 0000000000..255d70ffea --- /dev/null +++ b/staticlibs/netd/binder/android/net/mdns/aidl/IMDns.aidl @@ -0,0 +1,127 @@ +/* + * 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.mdns.aidl; + +import android.net.mdns.aidl.DiscoveryInfo; +import android.net.mdns.aidl.GetAddressInfo; +import android.net.mdns.aidl.IMDnsEventListener; +import android.net.mdns.aidl.RegistrationInfo; +import android.net.mdns.aidl.ResolutionInfo; + +/** {@hide} */ +interface IMDns { + /** + * Start the MDNSResponder daemon. + * + * @throws ServiceSpecificException with unix errno EALREADY if daemon is already running. + */ + void startDaemon(); + + /** + * Stop the MDNSResponder daemon. + * + * @throws ServiceSpecificException with unix errno EBUSY if daemon is still in use. + */ + void stopDaemon(); + + /** + * Start registering a service. + * This operation will send a service registration request to MDNSResponder. Register a listener + * via IMDns#registerEventListener to get the registration result SERVICE_REGISTERED/ + * SERVICE_REGISTRATION_FAILED from callback IMDnsEventListener#onServiceRegistrationStatus. + * + * @param info The service information to register. + * + * @throws ServiceSpecificException with one of the following error values: + * - Unix errno EBUSY if request id is already in use. + * - kDNSServiceErr_* list in dns_sd.h if registration fail. + */ + void registerService(in RegistrationInfo info); + + /** + * Start discovering services. + * This operation will send a request to MDNSResponder to discover services. Register a listener + * via IMDns#registerEventListener to get the discovery result SERVICE_FOUND/SERVICE_LOST/ + * SERVICE_DISCOVERY_FAILED from callback IMDnsEventListener#onServiceDiscoveryStatus. + * + * @param info The service to discover. + * + * @throws ServiceSpecificException with one of the following error values: + * - Unix errno EBUSY if request id is already in use. + * - kDNSServiceErr_* list in dns_sd.h if discovery fail. + */ + void discover(in DiscoveryInfo info); + + /** + * Start resolving the target service. + * This operation will send a request to MDNSResponder to resolve the target service. Register a + * listener via IMDns#registerEventListener to get the resolution result SERVICE_RESOLVED/ + * SERVICE_RESOLUTION_FAILED from callback IMDnsEventListener#onServiceResolutionStatus. + * + * @param info The service to resolve. + * + * @throws ServiceSpecificException with one of the following error values: + * - Unix errno EBUSY if request id is already in use. + * - kDNSServiceErr_* list in dns_sd.h if resolution fail. + */ + void resolve(in ResolutionInfo info); + + /** + * Start getting the target service address. + * This operation will send a request to MDNSResponder to get the target service address. + * Register a listener via IMDns#registerEventListener to get the query result + * SERVICE_GET_ADDR_SUCCESS/SERVICE_GET_ADDR_FAILED from callback + * IMDnsEventListener#onGettingServiceAddressStatus. + * + * @param info the getting service address information. + * + * @throws ServiceSpecificException with one of the following error values: + * - Unix errno EBUSY if request id is already in use. + * - kDNSServiceErr_* list in dns_sd.h if getting address fail. + */ + void getServiceAddress(in GetAddressInfo info); + + /** + * Stop a operation which's requested before. + * + * @param id the operation id to be stopped. + * + * @throws ServiceSpecificException with unix errno ESRCH if request id is not in use. + */ + void stopOperation(int id); + + /** + * Register an event listener. + * + * @param listener The listener to be registered. + * + * @throws ServiceSpecificException with one of the following error values: + * - Unix errno EINVAL if listener is null. + * - Unix errno EEXIST if register duplicated listener. + */ + void registerEventListener(in IMDnsEventListener listener); + + /** + * Unregister an event listener. + * + * @param listener The listener to be unregistered. + * + * @throws ServiceSpecificException with unix errno EINVAL if listener is null. + */ + void unregisterEventListener(in IMDnsEventListener listener); +} + diff --git a/staticlibs/netd/binder/android/net/mdns/aidl/IMDnsEventListener.aidl b/staticlibs/netd/binder/android/net/mdns/aidl/IMDnsEventListener.aidl new file mode 100644 index 0000000000..a202a261a3 --- /dev/null +++ b/staticlibs/netd/binder/android/net/mdns/aidl/IMDnsEventListener.aidl @@ -0,0 +1,66 @@ +/** + * 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.mdns.aidl; + +import android.net.mdns.aidl.DiscoveryInfo; +import android.net.mdns.aidl.GetAddressInfo; +import android.net.mdns.aidl.RegistrationInfo; +import android.net.mdns.aidl.ResolutionInfo; + +/** + * MDNS events which are reported by the MDNSResponder. + * This one-way interface defines the asynchronous notifications sent by mdns service to any process + * that registered itself via IMDns.registerEventListener. + * + * {@hide} + */ +oneway interface IMDnsEventListener { + /** + * Types for MDNS operation result. + * These are in sync with frameworks/libs/net/common/netd/libnetdutils/include/netdutils/\ + * ResponseCode.h + */ + const int SERVICE_DISCOVERY_FAILED = 602; + const int SERVICE_FOUND = 603; + const int SERVICE_LOST = 604; + const int SERVICE_REGISTRATION_FAILED = 605; + const int SERVICE_REGISTERED = 606; + const int SERVICE_RESOLUTION_FAILED = 607; + const int SERVICE_RESOLVED = 608; + const int SERVICE_GET_ADDR_FAILED = 611; + const int SERVICE_GET_ADDR_SUCCESS = 612; + + /** + * Notify service registration status. + */ + void onServiceRegistrationStatus(in RegistrationInfo status); + + /** + * Notify service discovery status. + */ + void onServiceDiscoveryStatus(in DiscoveryInfo status); + + /** + * Notify service resolution status. + */ + void onServiceResolutionStatus(in ResolutionInfo status); + + /** + * Notify getting service address status. + */ + void onGettingServiceAddressStatus(in GetAddressInfo status); +} diff --git a/staticlibs/netd/binder/android/net/mdns/aidl/RegistrationInfo.aidl b/staticlibs/netd/binder/android/net/mdns/aidl/RegistrationInfo.aidl new file mode 100644 index 0000000000..5483559453 --- /dev/null +++ b/staticlibs/netd/binder/android/net/mdns/aidl/RegistrationInfo.aidl @@ -0,0 +1,78 @@ +/* + * 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.mdns.aidl; + +/** + * Registration service information. + * This information combine all arguments that used by both request and callback. + * Arguments are used by request: + * - id + * - serviceName + * - registrationType + * - port + * - txtRecord + * - interfaceIdx + * + * Arguments are used by callback: + * - id + * - serviceName + * - registrationType + * - result + * + * {@hide} + */ +@JavaOnlyImmutable +@JavaDerive(equals=true, toString=true) +parcelable RegistrationInfo { + /** + * The operation ID. + */ + int id; + + /** + * The registration result. + */ + int result; + + /** + * The service name to be registered. + */ + @utf8InCpp String serviceName; + + /** + * The service type followed by the protocol, separated by a dot (e.g. "_ftp._tcp"). The service + * type must be an underscore, followed by 1-15 characters, which may be letters, digits, or + * hyphens. The transport protocol must be "_tcp" or "_udp". New service types should be + * registered at . + */ + @utf8InCpp String registrationType; + + /** + * The port on which the service accepts connections. + */ + int port; + + /** + * The txt record. + */ + byte[] txtRecord; + + /** + * The interface index on which to register the service. 0 indicates "all interfaces". + */ + int interfaceIdx; +} diff --git a/staticlibs/netd/binder/android/net/mdns/aidl/ResolutionInfo.aidl b/staticlibs/netd/binder/android/net/mdns/aidl/ResolutionInfo.aidl new file mode 100644 index 0000000000..26e0cee75e --- /dev/null +++ b/staticlibs/netd/binder/android/net/mdns/aidl/ResolutionInfo.aidl @@ -0,0 +1,92 @@ +/* + * 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.mdns.aidl; + +/** + * Resolution service information. + * This information combine all arguments that used by both request and callback. + * Arguments are used by request: + * - id + * - serviceName + * - registrationType + * - domain + * - interfaceIdx + * + * Arguments are used by callback: + * - id + * - port + * - serviceFullName + * - hostname + * - txtRecord + * - interfaceIdx + * - result + * + * {@hide} + */ +@JavaOnlyImmutable +@JavaDerive(equals=true, toString=true) +parcelable ResolutionInfo { + /** + * The operation ID. + */ + int id; + + /** + * The resolution result. + */ + int result; + + /** + * The service name to be resolved. + */ + @utf8InCpp String serviceName; + + /** + * The service type to be resolved. + */ + @utf8InCpp String registrationType; + + /** + * The service domain to be resolved. + */ + @utf8InCpp String domain; + + /** + * The resolved full service domain name, in the form ... + */ + @utf8InCpp String serviceFullName; + + /** + * The target hostname of the machine providing the service. + */ + @utf8InCpp String hostname; + + /** + * The port on which connections are accepted for this service. + */ + int port; + + /** + * The service's txt record. + */ + byte[] txtRecord; + + /** + * The interface index on which to resolve the service. 0 indicates "all interfaces". + */ + int interfaceIdx; +} From 973f6f8d59c2e2f1d9eecdb0dfbb773f65e607a5 Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 31 Mar 2022 02:23:34 +0000 Subject: [PATCH 419/777] Freeze Mdns AIDL interface to V1 - Also add mdns_aidl_interface-lateststable-java lib for Connectivity module usage. Bug: 209894875 Test: m mdns_aidl_interface-freeze-api Change-Id: I58364dcf6d0377fbac7533eb95d2aacddd120092 --- staticlibs/netd/Android.bp | 14 ++++++ .../netd/aidl_api/mdns_aidl_interface/1/.hash | 1 + .../android/net/mdns/aidl/DiscoveryInfo.aidl | 45 +++++++++++++++++ .../android/net/mdns/aidl/GetAddressInfo.aidl | 44 ++++++++++++++++ .../1/android/net/mdns/aidl/IMDns.aidl | 46 +++++++++++++++++ .../net/mdns/aidl/IMDnsEventListener.aidl | 50 +++++++++++++++++++ .../net/mdns/aidl/RegistrationInfo.aidl | 45 +++++++++++++++++ .../android/net/mdns/aidl/ResolutionInfo.aidl | 48 ++++++++++++++++++ 8 files changed, 293 insertions(+) create mode 100644 staticlibs/netd/aidl_api/mdns_aidl_interface/1/.hash create mode 100644 staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/DiscoveryInfo.aidl create mode 100644 staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/GetAddressInfo.aidl create mode 100644 staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/IMDns.aidl create mode 100644 staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/IMDnsEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/RegistrationInfo.aidl create mode 100644 staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/ResolutionInfo.aidl diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index b06d708936..85a756c725 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -157,6 +157,19 @@ aidl_interface { }, } +java_library { + name: "mdns_aidl_interface-lateststable-java", + sdk_version: "module_current", + min_sdk_version: "30", + static_libs: [ + "mdns_aidl_interface-V1-java", + ], + apex_available: [ + "//apex_available:platform", + "com.android.tethering", + ], +} + aidl_interface { name: "mdns_aidl_interface", local_include_dir: "binder", @@ -173,4 +186,5 @@ aidl_interface { min_sdk_version: "30", }, }, + versions: ["1"], } diff --git a/staticlibs/netd/aidl_api/mdns_aidl_interface/1/.hash b/staticlibs/netd/aidl_api/mdns_aidl_interface/1/.hash new file mode 100644 index 0000000000..d952c59802 --- /dev/null +++ b/staticlibs/netd/aidl_api/mdns_aidl_interface/1/.hash @@ -0,0 +1 @@ +ae4cfe565d66acc7d816aabd0dfab991e64031ab diff --git a/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/DiscoveryInfo.aidl b/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/DiscoveryInfo.aidl new file mode 100644 index 0000000000..d31a327893 --- /dev/null +++ b/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/DiscoveryInfo.aidl @@ -0,0 +1,45 @@ +/* + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.mdns.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable DiscoveryInfo { + int id; + int result; + @utf8InCpp String serviceName; + @utf8InCpp String registrationType; + @utf8InCpp String domainName; + int interfaceIdx; + int netId; +} diff --git a/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/GetAddressInfo.aidl b/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/GetAddressInfo.aidl new file mode 100644 index 0000000000..2049274454 --- /dev/null +++ b/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/GetAddressInfo.aidl @@ -0,0 +1,44 @@ +/* + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.mdns.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable GetAddressInfo { + int id; + int result; + @utf8InCpp String hostname; + @utf8InCpp String address; + int interfaceIdx; + int netId; +} diff --git a/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/IMDns.aidl b/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/IMDns.aidl new file mode 100644 index 0000000000..ecbe966dea --- /dev/null +++ b/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/IMDns.aidl @@ -0,0 +1,46 @@ +/* + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.mdns.aidl; +/* @hide */ +interface IMDns { + void startDaemon(); + void stopDaemon(); + void registerService(in android.net.mdns.aidl.RegistrationInfo info); + void discover(in android.net.mdns.aidl.DiscoveryInfo info); + void resolve(in android.net.mdns.aidl.ResolutionInfo info); + void getServiceAddress(in android.net.mdns.aidl.GetAddressInfo info); + void stopOperation(int id); + void registerEventListener(in android.net.mdns.aidl.IMDnsEventListener listener); + void unregisterEventListener(in android.net.mdns.aidl.IMDnsEventListener listener); +} diff --git a/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/IMDnsEventListener.aidl b/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/IMDnsEventListener.aidl new file mode 100644 index 0000000000..4625cac7ab --- /dev/null +++ b/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/IMDnsEventListener.aidl @@ -0,0 +1,50 @@ +/** + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.mdns.aidl; +/* @hide */ +interface IMDnsEventListener { + oneway void onServiceRegistrationStatus(in android.net.mdns.aidl.RegistrationInfo status); + oneway void onServiceDiscoveryStatus(in android.net.mdns.aidl.DiscoveryInfo status); + oneway void onServiceResolutionStatus(in android.net.mdns.aidl.ResolutionInfo status); + oneway void onGettingServiceAddressStatus(in android.net.mdns.aidl.GetAddressInfo status); + const int SERVICE_DISCOVERY_FAILED = 602; + const int SERVICE_FOUND = 603; + const int SERVICE_LOST = 604; + const int SERVICE_REGISTRATION_FAILED = 605; + const int SERVICE_REGISTERED = 606; + const int SERVICE_RESOLUTION_FAILED = 607; + const int SERVICE_RESOLVED = 608; + const int SERVICE_GET_ADDR_FAILED = 611; + const int SERVICE_GET_ADDR_SUCCESS = 612; +} diff --git a/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/RegistrationInfo.aidl b/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/RegistrationInfo.aidl new file mode 100644 index 0000000000..185111b440 --- /dev/null +++ b/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/RegistrationInfo.aidl @@ -0,0 +1,45 @@ +/* + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.mdns.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable RegistrationInfo { + int id; + int result; + @utf8InCpp String serviceName; + @utf8InCpp String registrationType; + int port; + byte[] txtRecord; + int interfaceIdx; +} diff --git a/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/ResolutionInfo.aidl b/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/ResolutionInfo.aidl new file mode 100644 index 0000000000..4aa7d79114 --- /dev/null +++ b/staticlibs/netd/aidl_api/mdns_aidl_interface/1/android/net/mdns/aidl/ResolutionInfo.aidl @@ -0,0 +1,48 @@ +/* + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.mdns.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable ResolutionInfo { + int id; + int result; + @utf8InCpp String serviceName; + @utf8InCpp String registrationType; + @utf8InCpp String domain; + @utf8InCpp String serviceFullName; + @utf8InCpp String hostname; + int port; + byte[] txtRecord; + int interfaceIdx; +} From 6d4c93667bd1270d21358abbf844342bca9b9d69 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Mon, 4 Apr 2022 23:18:23 +0800 Subject: [PATCH 420/777] Move TetherStatsKey and TetherStatsValue to common libs EthernetTetheringTest needs to parse BPF map content for bpf stats tests. Move the struct class files to common libs. Compare TetherStats{Key, Value}.java between frameworks/libs/net/common and packages/modules/Connectivity/Tethering. There is only the package name change as expected. $ diff packages/modules/Connectivity/Tethering/src/com/android/networkstack/tethering/TetherStatsKey.java frameworks/libs/net/common/device/com/android/net/module/util/bpf/TetherStatsKey.java 17c17 < package com.android.networkstack.tethering; Bug: 227159997 Test: atest TetheringCoverageTests Change-Id: I6ed3b1626d8efd3920130f0af0cd9de75ee0bd7f --- .../net/module/util/bpf/TetherStatsKey.java | 53 ++++++++++++ .../net/module/util/bpf/TetherStatsValue.java | 80 +++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/bpf/TetherStatsKey.java create mode 100644 staticlibs/device/com/android/net/module/util/bpf/TetherStatsValue.java diff --git a/staticlibs/device/com/android/net/module/util/bpf/TetherStatsKey.java b/staticlibs/device/com/android/net/module/util/bpf/TetherStatsKey.java new file mode 100644 index 0000000000..c6d595be64 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/bpf/TetherStatsKey.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util.bpf; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** The key of BpfMap which is used for tethering stats. */ +public class TetherStatsKey extends Struct { + @Field(order = 0, type = Type.U32) + public final long ifindex; // upstream interface index + + public TetherStatsKey(final long ifindex) { + this.ifindex = ifindex; + } + + // TODO: remove equals, hashCode and toString once aosp/1536721 is merged. + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + + if (!(obj instanceof TetherStatsKey)) return false; + + final TetherStatsKey that = (TetherStatsKey) obj; + + return ifindex == that.ifindex; + } + + @Override + public int hashCode() { + return Long.hashCode(ifindex); + } + + @Override + public String toString() { + return String.format("ifindex: %d", ifindex); + } +} diff --git a/staticlibs/device/com/android/net/module/util/bpf/TetherStatsValue.java b/staticlibs/device/com/android/net/module/util/bpf/TetherStatsValue.java new file mode 100644 index 0000000000..028d217a93 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/bpf/TetherStatsValue.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2020 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 com.android.net.module.util.bpf; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** The key of BpfMap which is used for tethering stats. */ +public class TetherStatsValue extends Struct { + // Use the signed long variable to store the uint64 stats from stats BPF map. + // U63 is enough for each data element even at 5Gbps for ~468 years. + // 2^63 / (5 * 1000 * 1000 * 1000) * 8 / 86400 / 365 = 468. + @Field(order = 0, type = Type.U63) + public final long rxPackets; + @Field(order = 1, type = Type.U63) + public final long rxBytes; + @Field(order = 2, type = Type.U63) + public final long rxErrors; + @Field(order = 3, type = Type.U63) + public final long txPackets; + @Field(order = 4, type = Type.U63) + public final long txBytes; + @Field(order = 5, type = Type.U63) + public final long txErrors; + + public TetherStatsValue(final long rxPackets, final long rxBytes, final long rxErrors, + final long txPackets, final long txBytes, final long txErrors) { + this.rxPackets = rxPackets; + this.rxBytes = rxBytes; + this.rxErrors = rxErrors; + this.txPackets = txPackets; + this.txBytes = txBytes; + this.txErrors = txErrors; + } + + // TODO: remove equals, hashCode and toString once aosp/1536721 is merged. + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + + if (!(obj instanceof TetherStatsValue)) return false; + + final TetherStatsValue that = (TetherStatsValue) obj; + + return rxPackets == that.rxPackets + && rxBytes == that.rxBytes + && rxErrors == that.rxErrors + && txPackets == that.txPackets + && txBytes == that.txBytes + && txErrors == that.txErrors; + } + + @Override + public int hashCode() { + return Long.hashCode(rxPackets) ^ Long.hashCode(rxBytes) ^ Long.hashCode(rxErrors) + ^ Long.hashCode(txPackets) ^ Long.hashCode(txBytes) ^ Long.hashCode(txErrors); + } + + @Override + public String toString() { + return String.format("rxPackets: %s, rxBytes: %s, rxErrors: %s, txPackets: %s, " + + "txBytes: %s, txErrors: %s", rxPackets, rxBytes, rxErrors, txPackets, + txBytes, txErrors); + } +} From 86dd5872be8112f0de4dc157df05c4c1f2544411 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Mon, 4 Apr 2022 12:17:39 +0200 Subject: [PATCH 421/777] Create RouterAdvertisementResponder This is useful for tests that need a provisioned tap interface. Test: TH Change-Id: I9a2eb3d8697bbcbfdb65563da609534b929a0715 --- .../RouterAdvertisementResponder.java | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java diff --git a/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java b/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java new file mode 100644 index 0000000000..4ad93d85ce --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java @@ -0,0 +1,123 @@ +/* + * 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 com.android.testutils; + +import static android.system.OsConstants.IPPROTO_ICMPV6; + +import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN; +import static com.android.net.module.util.NetworkStackConstants.ETHER_SRC_ADDR_OFFSET; +import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION; +import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_NODES_MULTICAST; +import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST; +import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_AUTONOMOUS; +import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_ON_LINK; + +import android.net.InetAddresses; +import android.net.IpPrefix; +import android.net.LinkAddress; +import android.net.MacAddress; +import android.util.Pair; + +import com.android.net.module.util.Ipv6Utils; +import com.android.net.module.util.Struct; +import com.android.net.module.util.structs.EthernetHeader; +import com.android.net.module.util.structs.Icmpv6Header; +import com.android.net.module.util.structs.Ipv6Header; +import com.android.net.module.util.structs.PrefixInformationOption; +import com.android.net.module.util.structs.RdnssOption; + +import java.io.IOException; +import java.net.Inet6Address; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * RA responder class useful for tests that require a provisioned interface. + */ +public class RouterAdvertisementResponder extends PacketResponder { + private static final String TAG = "RouterAdvertisementResponder"; + private static final LinkAddress SLAAC_PREFIX = new LinkAddress("2001:db8::/64"); + private static final Inet6Address DNS_SERVER = + (Inet6Address) InetAddresses.parseNumericAddress("2001:4860:4860::64"); + private final TapPacketReader mPacketReader; + private final List> mRouterList = new ArrayList<>(); + + public RouterAdvertisementResponder(TapPacketReader packetReader) { + super(packetReader, RouterAdvertisementResponder::isRouterSolicitation, TAG); + mPacketReader = packetReader; + } + + private static boolean isRouterSolicitation(byte[] packet) { + final ByteBuffer buffer = ByteBuffer.wrap(packet); + final EthernetHeader ethHeader = Struct.parse(EthernetHeader.class, buffer); + if (ethHeader.etherType != ETHER_TYPE_IPV6) { + return false; + } + final Ipv6Header ipv6Header = Struct.parse(Ipv6Header.class, buffer); + if (ipv6Header.nextHeader != IPPROTO_ICMPV6 + || !ipv6Header.dstIp.equals(IPV6_ADDR_ALL_ROUTERS_MULTICAST)) { + return false; + } + final Icmpv6Header icmpv6Header = Struct.parse(Icmpv6Header.class, buffer); + return icmpv6Header.type == ICMPV6_ROUTER_SOLICITATION; + } + + /** + * Adds a new router to be advertised. + * @param mac the mac address of the router. + * @param ip the link-local address of the router. + */ + public void addRouterEntry(MacAddress mac, Inet6Address ip) { + mRouterList.add(new Pair<>(mac, ip)); + } + + private ByteBuffer buildPrefixOption() { + return PrefixInformationOption.build( + new IpPrefix(SLAAC_PREFIX.getAddress(), SLAAC_PREFIX.getPrefixLength()), + (byte) (PIO_FLAG_ON_LINK | PIO_FLAG_AUTONOMOUS), 3600/*valid lifetime*/, + 3600/*preferred lifetime*/); + } + + private ByteBuffer buildRdnssOption() { + return RdnssOption.build(3600/*lifetime, must be at least 120*/, DNS_SERVER); + } + + private ByteBuffer buildRaPacket(MacAddress srcMac, MacAddress dstMac, Inet6Address srcIp) { + return Ipv6Utils.buildRaPacket(srcMac, dstMac, srcIp, IPV6_ADDR_ALL_NODES_MULTICAST, + (byte) 0 /*M=0, O=0*/, 3600 /*lifetime*/, 0 /*reachableTime, unspecified*/, + 0/*retransTimer, unspecified*/, buildPrefixOption(), buildRdnssOption()); + } + + @Override + protected void replyToPacket(byte[] packet, TapPacketReader reader) { + final MacAddress srcMac = MacAddress.fromBytes( + Arrays.copyOfRange(packet, ETHER_SRC_ADDR_OFFSET, + ETHER_SRC_ADDR_OFFSET + ETHER_ADDR_LEN)); + + for (Pair it : mRouterList) { + final ByteBuffer raResponse = buildRaPacket(it.first, srcMac, it.second); + try { + reader.sendResponse(raResponse); + } catch (IOException e) { + throw new RuntimeException("Failed to send RA"); + } + } + } +} From ae296b2178f05754c2000583ab9bd0618607675d Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Wed, 20 Apr 2022 15:13:31 +0800 Subject: [PATCH 422/777] Add wrappers for the latest stable version of netd_aidl_interface-V*-cpp Currently, we need to update linked AILD interface in several places when we freeze a new interface version. Otherwise, it will have multiple versions of an AIDL lib and waste space/memory (b/220392885). To avoid manually update all AILD interface users every time, adds wrappers for the latest version of netd_aidl_interface-V*-cpp. The reason to use cc_default as a wrapper instead of cc_library is that it doesn't create an extra .so. Bug: 220392885 Test: TH Change-Id: I281b2e5f7d04fadfae0ede4db7565e9f222dbe95 --- staticlibs/netd/Android.bp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index 85a756c725..6bc7c01400 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -53,6 +53,7 @@ cc_library_static { min_sdk_version: "29", } +// TODO: delete this one when AOSP is no longer auto-merge to git_sc-mainline-prod. cc_library_static { name: "netd_aidl_interface-lateststable-cpp", whole_static_libs: [ @@ -60,6 +61,16 @@ cc_library_static { ], } +cc_defaults { + name: "netd_aidl_interface_lateststable_cpp_static", + static_libs: ["netd_aidl_interface-V8-cpp"], +} + +cc_defaults { + name: "netd_aidl_interface_lateststable_cpp_shared", + shared_libs: ["netd_aidl_interface-V8-cpp"], +} + aidl_interface { name: "netd_aidl_interface", local_include_dir: "binder", From 4caf33799111feafcff85d3ad6dcf34933d1c04c Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Wed, 27 Apr 2022 09:10:41 +0000 Subject: [PATCH 423/777] Add null check for mProvider mProvider is null before register is called. But toString call mProvider.getProviderId() without null check and caused NullPointerException. This commit add null check and fix this issue. Bug: 228796405 Test: m Change-Id: Ic8e23b21d11705219f1a8fddd544941fbddb183e --- staticlibs/device/android/net/NetworkFactoryImpl.java | 7 +++---- .../device/android/net/NetworkFactoryLegacyImpl.java | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/staticlibs/device/android/net/NetworkFactoryImpl.java b/staticlibs/device/android/net/NetworkFactoryImpl.java index 439ea1421a..9c1190c219 100644 --- a/staticlibs/device/android/net/NetworkFactoryImpl.java +++ b/staticlibs/device/android/net/NetworkFactoryImpl.java @@ -315,9 +315,8 @@ class NetworkFactoryImpl extends NetworkFactoryLegacyImpl { } @Override public String toString() { - return "providerId=" - + mProvider.getProviderId() + ", ScoreFilter=" - + mScore + ", Filter=" + mCapabilityFilter + ", requests=" - + mNetworkRequests.size(); + return "providerId=" + (mProvider != null ? mProvider.getProviderId() : "null") + + ", ScoreFilter=" + mScore + ", Filter=" + mCapabilityFilter + + ", requests=" + mNetworkRequests.size(); } } diff --git a/staticlibs/device/android/net/NetworkFactoryLegacyImpl.java b/staticlibs/device/android/net/NetworkFactoryLegacyImpl.java index 6dd0adb0c9..6cba625888 100644 --- a/staticlibs/device/android/net/NetworkFactoryLegacyImpl.java +++ b/staticlibs/device/android/net/NetworkFactoryLegacyImpl.java @@ -390,9 +390,8 @@ class NetworkFactoryLegacyImpl extends Handler } @Override public String toString() { - return "providerId=" - + mProvider.getProviderId() + ", ScoreFilter=" - + mScore + ", Filter=" + mCapabilityFilter + ", requests=" - + mNetworkRequests.size(); + return "providerId=" + (mProvider != null ? mProvider.getProviderId() : "null") + + ", ScoreFilter=" + mScore + ", Filter=" + mCapabilityFilter + + ", requests=" + mNetworkRequests.size(); } } From 18a814e9348fbdb00b1b6fdef8a6a3f3d43fedd0 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Wed, 27 Apr 2022 09:10:41 +0000 Subject: [PATCH 424/777] Add null check for mProvider mProvider is null before register is called. But toString call mProvider.getProviderId() without null check and caused NullPointerException. This commit add null check and fix this issue. Original change: https://android-review.googlesource.com/c/platform/frameworks/libs/net/+/2076539 Bug: 228796405 Test: m Ignore-AOSP-First: manual cherry-pick from AOSP Change-Id: Ic8e23b21d11705219f1a8fddd544941fbddb183e --- staticlibs/device/android/net/NetworkFactoryImpl.java | 7 +++---- .../device/android/net/NetworkFactoryLegacyImpl.java | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/staticlibs/device/android/net/NetworkFactoryImpl.java b/staticlibs/device/android/net/NetworkFactoryImpl.java index 439ea1421a..9c1190c219 100644 --- a/staticlibs/device/android/net/NetworkFactoryImpl.java +++ b/staticlibs/device/android/net/NetworkFactoryImpl.java @@ -315,9 +315,8 @@ class NetworkFactoryImpl extends NetworkFactoryLegacyImpl { } @Override public String toString() { - return "providerId=" - + mProvider.getProviderId() + ", ScoreFilter=" - + mScore + ", Filter=" + mCapabilityFilter + ", requests=" - + mNetworkRequests.size(); + return "providerId=" + (mProvider != null ? mProvider.getProviderId() : "null") + + ", ScoreFilter=" + mScore + ", Filter=" + mCapabilityFilter + + ", requests=" + mNetworkRequests.size(); } } diff --git a/staticlibs/device/android/net/NetworkFactoryLegacyImpl.java b/staticlibs/device/android/net/NetworkFactoryLegacyImpl.java index 6dd0adb0c9..6cba625888 100644 --- a/staticlibs/device/android/net/NetworkFactoryLegacyImpl.java +++ b/staticlibs/device/android/net/NetworkFactoryLegacyImpl.java @@ -390,9 +390,8 @@ class NetworkFactoryLegacyImpl extends Handler } @Override public String toString() { - return "providerId=" - + mProvider.getProviderId() + ", ScoreFilter=" - + mScore + ", Filter=" + mCapabilityFilter + ", requests=" - + mNetworkRequests.size(); + return "providerId=" + (mProvider != null ? mProvider.getProviderId() : "null") + + ", ScoreFilter=" + mScore + ", Filter=" + mCapabilityFilter + + ", requests=" + mNetworkRequests.size(); } } From ed1292644e113e2b75209ed0fcaaf70e06ee7024 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Tue, 26 Apr 2022 19:10:45 +0800 Subject: [PATCH 425/777] Freeze netd_aidl_interface V9 Deprecate APIs which were moved the implementation to mainline module. - clatdStart (since T) - clatdStop (since T) - tetherOffloadRuleAdd (since S) - tetherOffloadRuleRemove (since S) - tetherOffloadGetStats (since S) - tetherOffloadSetInterfaceQuota (since S) - tetherOffloadGetAndClearStats (since S) Bug: 212345928 Test: cd system/netd; atest Change-Id: I7916512c7174a7b50833036bc89df37a266ca67e --- staticlibs/netd/Android.bp | 58 +++-- .../netd/aidl_api/netd_aidl_interface/9/.hash | 1 + .../9/android/net/INetd.aidl | 221 ++++++++++++++++++ .../net/INetdUnsolicitedEventListener.aidl | 48 ++++ .../net/InterfaceConfigurationParcel.aidl | 42 ++++ .../9/android/net/MarkMaskParcel.aidl | 39 ++++ .../9/android/net/NativeNetworkConfig.aidl | 44 ++++ .../9/android/net/NativeNetworkType.aidl | 39 ++++ .../9/android/net/NativeVpnType.aidl | 41 ++++ .../9/android/net/RouteInfoParcel.aidl | 40 ++++ .../9/android/net/TetherConfigParcel.aidl | 39 ++++ .../android/net/TetherOffloadRuleParcel.aidl | 44 ++++ .../9/android/net/TetherStatsParcel.aidl | 43 ++++ .../9/android/net/UidRangeParcel.aidl | 40 ++++ .../net/netd/aidl/NativeUidRangeConfig.aidl | 41 ++++ .../current/android/net/INetd.aidl | 21 ++ staticlibs/netd/binder/android/net/INetd.aidl | 16 +- 17 files changed, 802 insertions(+), 15 deletions(-) create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeNetworkConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeNetworkType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeVpnType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/netd/aidl/NativeUidRangeConfig.aidl diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index 6bc7c01400..cfa9bbb3d9 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -21,7 +21,7 @@ java_library { sdk_version: "system_current", min_sdk_version: "29", static_libs: [ - "netd_aidl_interface-V8-java", + "netd_aidl_interface-V9-java", ], apex_available: [ "//apex_available:platform", // used from services.net @@ -44,7 +44,7 @@ cc_library_static { cc_library_static { name: "netd_aidl_interface-lateststable-ndk", whole_static_libs: [ - "netd_aidl_interface-V8-ndk", + "netd_aidl_interface-V9-ndk", ], apex_available: [ "com.android.resolv", @@ -57,18 +57,18 @@ cc_library_static { cc_library_static { name: "netd_aidl_interface-lateststable-cpp", whole_static_libs: [ - "netd_aidl_interface-V8-cpp", + "netd_aidl_interface-V9-cpp", ], } cc_defaults { name: "netd_aidl_interface_lateststable_cpp_static", - static_libs: ["netd_aidl_interface-V8-cpp"], + static_libs: ["netd_aidl_interface-V9-cpp"], } cc_defaults { name: "netd_aidl_interface_lateststable_cpp_shared", - shared_libs: ["netd_aidl_interface-V8-cpp"], + shared_libs: ["netd_aidl_interface-V9-cpp"], } aidl_interface { @@ -116,16 +116,46 @@ aidl_interface { min_sdk_version: "29", }, }, - versions: [ - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", + versions_with_info: [ + { + version: "1", + imports: [], + }, + { + version: "2", + imports: [], + }, + { + version: "3", + imports: [], + }, + { + version: "4", + imports: [], + }, + { + version: "5", + imports: [], + }, + { + version: "6", + imports: [], + }, + { + version: "7", + imports: [], + }, + { + version: "8", + imports: [], + }, + { + version: "9", + imports: [], + }, + ], + } java_library { diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/9/.hash new file mode 100644 index 0000000000..94dd240d92 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/.hash @@ -0,0 +1 @@ +2bffe06ea8c13f35f90b86d6dfd1a2b4c4d4daf5 diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/INetd.aidl new file mode 100644 index 0000000000..c780a59ee7 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/INetd.aidl @@ -0,0 +1,221 @@ +/** + * Copyright (c) 2016, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreatePhysical(int netId, int permission); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + void networkCreate(in android.net.NativeNetworkConfig config); + void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const int DUMMY_NET_ID = 51; + const int UNREACHABLE_NET_ID = 52; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + /** + * @deprecated use FIREWALL_ALLOWLIST. + */ + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_ALLOWLIST = 0; + /** + * @deprecated use FIREWALL_DENYLIST. + */ + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_DENYLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const int FIREWALL_CHAIN_RESTRICTED = 4; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..31775dfd11 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2018, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..1869d8d49e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..8ea20d118f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/MarkMaskParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeNetworkConfig.aidl new file mode 100644 index 0000000000..77d814b825 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeNetworkConfig.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeNetworkConfig { + int netId; + android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL; + int permission; + boolean secure; + android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM; + boolean excludeLocalRoutes = false; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeNetworkType.aidl new file mode 100644 index 0000000000..06c8979d51 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeNetworkType.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeNetworkType { + PHYSICAL = 0, + VIRTUAL = 1, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeVpnType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeVpnType.aidl new file mode 100644 index 0000000000..8a8be83958 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeVpnType.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeVpnType { + SERVICE = 1, + PLATFORM = 2, + LEGACY = 3, + OEM = 4, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5ef95e67ca --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/RouteInfoParcel.aidl @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2020, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..7b39c22e4e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherConfigParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..983e9860ea --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..5f1b722690 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherStatsParcel.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..72e987a2af --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/UidRangeParcel.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/netd/aidl/NativeUidRangeConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/netd/aidl/NativeUidRangeConfig.aidl new file mode 100644 index 0000000000..9bb679f1c1 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/netd/aidl/NativeUidRangeConfig.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.netd.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeUidRangeConfig { + int netId; + android.net.UidRangeParcel[] uidRanges; + int subPriority; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl index ec03d86b6c..c780a59ee7 100644 --- a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl @@ -76,7 +76,13 @@ interface INetd { void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); void strictUidCleartextPenalty(int uid, int policyPenalty); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ void clatdStop(in @utf8InCpp String ifName); boolean ipfwdEnabled(); @utf8InCpp String[] ipfwdGetRequesterList(); @@ -139,10 +145,25 @@ interface INetd { void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ android.net.TetherStatsParcel[] tetherOffloadGetStats(); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); void networkCreate(in android.net.NativeNetworkConfig config); void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); diff --git a/staticlibs/netd/binder/android/net/INetd.aidl b/staticlibs/netd/binder/android/net/INetd.aidl index d6398c1222..ad469f8165 100644 --- a/staticlibs/netd/binder/android/net/INetd.aidl +++ b/staticlibs/netd/binder/android/net/INetd.aidl @@ -548,6 +548,8 @@ interface INetd { /** * Start clatd * + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd + * control plane moved to the mainline module starting in T. See ClatCoordinator. * @param ifName interface name to start clatd * @param nat64Prefix the NAT64 prefix, e.g., "2001:db8:64::/96". * @return a string, the IPv6 address that will be used for 464xlat. @@ -559,6 +561,8 @@ interface INetd { /** * Stop clatd * + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd + * control plane moved to the mainline module starting in T. See ClatCoordinator. * @param ifName interface name to stop clatd * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. @@ -1283,6 +1287,8 @@ interface INetd { * Currently, only downstream /128 IPv6 entries are supported. An existing rule will be updated * if the input interface and destination prefix match. Otherwise, a new rule will be created. * + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline + * module accesses the BPF map directly starting in S. See BpfCoordinator. * @param rule The rule to add or update. * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. @@ -1296,6 +1302,8 @@ interface INetd { * if the destination IP address and the source interface match. It is not an error if there is * no matching rule to delete. * + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline + * module accesses the BPF map directly starting in S. See BpfCoordinator. * @param rule The rule to delete. * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. @@ -1305,6 +1313,8 @@ interface INetd { /** * Return BPF tethering offload statistics. * + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline + * module accesses the BPF map directly starting in S. See BpfCoordinator. * @return an array of TetherStatsParcel's, where each entry contains the upstream interface * index and its tethering statistics since tethering was first started. * There will only ever be one entry for a given interface index. @@ -1316,9 +1326,11 @@ interface INetd { /** * Set a per-interface quota for tethering offload. * + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline + * module accesses the BPF map directly starting in S. See BpfCoordinator. * @param ifIndex Index of upstream interface * @param quotaBytes The quota defined as the number of bytes, starting from zero and counting - * from *now*. A value of QUOTA_UNLIMITED (-1) indicates there is no limit. + * from *now*. A value of QUOTA_UNLIMITED (-1) indicates there is no limit. * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. */ @@ -1334,6 +1346,8 @@ interface INetd { * The stats and limit for a given upstream interface must be initialized (using * tetherOffloadSetInterfaceQuota) before any offload will occur on that interface. * + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline + * module accesses the BPF map directly starting in S. See BpfCoordinator. * @param ifIndex Index of upstream interface. * @return TetherStatsParcel, which contains the given upstream interface index and its * tethering statistics since tethering was first started on that upstream interface. From 3707615abc25c0037b21aaf93b0b7f01705758d2 Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Thu, 28 Apr 2022 12:37:48 +0800 Subject: [PATCH 426/777] Delete netd_aidl_interface-lateststable-cpp The netd_aidl_interface-lateststable-cpp has been replaced by netd_aidl_interface_lateststable_cpp_static. Test: TH Bug: N/A Change-Id: I6ea1317bac81b602e6b398681cc453a25bf8c399 --- staticlibs/netd/Android.bp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index cfa9bbb3d9..798fa3a367 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -53,14 +53,6 @@ cc_library_static { min_sdk_version: "29", } -// TODO: delete this one when AOSP is no longer auto-merge to git_sc-mainline-prod. -cc_library_static { - name: "netd_aidl_interface-lateststable-cpp", - whole_static_libs: [ - "netd_aidl_interface-V9-cpp", - ], -} - cc_defaults { name: "netd_aidl_interface_lateststable_cpp_static", static_libs: ["netd_aidl_interface-V9-cpp"], From c56679d1b533284bc184a63454d4eaa564e0f773 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Thu, 28 Apr 2022 15:38:43 +0800 Subject: [PATCH 427/777] Migrate compareMajorMinorVersion from ConnectivityManagerTest Move compareMajorMinorVersion() and getVersionFromString() from ConnectivityManagerTest.java. Test: atest DeviceInfoUtilsTest Change-Id: Ib8245890856a3e4518e48e0afeada746a24e8b22 --- .../android/testutils/DeviceInfoUtils.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java b/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java new file mode 100644 index 0000000000..69cb5f81a7 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java @@ -0,0 +1,63 @@ +/* + * 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 com.android.testutils; + +import android.text.TextUtils; +import android.util.Pair; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Utilities for device information. + */ +public class DeviceInfoUtils { + private static Pair getVersionFromString(String version) { + // Only gets major and minor number of the version string. + final Pattern versionPattern = Pattern.compile("^(\\d+)(\\.(\\d+))?.*"); + final Matcher m = versionPattern.matcher(version); + if (m.matches()) { + final int major = Integer.parseInt(m.group(1)); + final int minor = TextUtils.isEmpty(m.group(3)) ? 0 : Integer.parseInt(m.group(3)); + return new Pair<>(major, minor); + } else { + return new Pair<>(0, 0); + } + } + + /** + * Compares two version strings numerically. Compare only major and minor number of the + * version string. The version comparison uses #Integer.compare. Possible version + * 5, 5.10, 5-beta1, 4.8-RC1, 4.7.10.10 and so on. + * + * @param s1 the first version string to compare + * @param s2 the second version string to compare + * @return the value 0 if s1 == s2; + * a value less than 0 if s1 < s2 and + * a value greater than 0 if s1 > s2. + */ + public static int compareMajorMinorVersion(final String s1, final String s2) { + final Pair v1 = getVersionFromString(s1); + final Pair v2 = getVersionFromString(s2); + + if (v1.first == v2.first) { + return Integer.compare(v1.second, v2.second); + } else { + return Integer.compare(v1.first, v2.first); + } + } +} From 96f0254477ebe33f0d8c95409d6ba9630b2f7f7c Mon Sep 17 00:00:00 2001 From: Simon Bowden Date: Tue, 3 May 2022 11:53:44 +0000 Subject: [PATCH 428/777] Revert "Delete netd_aidl_interface-lateststable-cpp" This reverts commit 41fb07fc2f87db0f1f2bf6198a3b4d9f660768f6. Reason for revert: b/231290697 broken mainline test build Change-Id: I8051e634b06c645739779078c0ff6445db9304d0 --- staticlibs/netd/Android.bp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index 798fa3a367..cfa9bbb3d9 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -53,6 +53,14 @@ cc_library_static { min_sdk_version: "29", } +// TODO: delete this one when AOSP is no longer auto-merge to git_sc-mainline-prod. +cc_library_static { + name: "netd_aidl_interface-lateststable-cpp", + whole_static_libs: [ + "netd_aidl_interface-V9-cpp", + ], +} + cc_defaults { name: "netd_aidl_interface_lateststable_cpp_static", static_libs: ["netd_aidl_interface-V9-cpp"], From aadb17ed59be867a78efc83b82169da99b8b82b8 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Thu, 5 May 2022 23:35:33 +0800 Subject: [PATCH 429/777] Make IBpfMap extends AutoCloseable and BpfMap implements IBpfMap IBpfMap defines all required functions of BpfMap interface. Ex: close() from AutoCloseable After: AutoCloseable ---> IBpfMap ---> BpfMap Before: AutoCloseable -+ | +---> BpfMap | IBpfMap -------+ Test: BpfMapTest Change-Id: I5266d9bfdfcb68f632c13d214705309893dded95 --- staticlibs/device/com/android/net/module/util/BpfMap.java | 2 +- staticlibs/device/com/android/net/module/util/IBpfMap.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java index d4ce83b48e..f1420c2131 100644 --- a/staticlibs/device/com/android/net/module/util/BpfMap.java +++ b/staticlibs/device/com/android/net/module/util/BpfMap.java @@ -39,7 +39,7 @@ import java.util.Objects; * @param the key of the map. * @param the value of the map. */ -public class BpfMap implements IBpfMap, AutoCloseable { +public class BpfMap implements IBpfMap { static { System.loadLibrary(JniUtil.getJniLibraryName(BpfMap.class.getPackage())); } diff --git a/staticlibs/device/com/android/net/module/util/IBpfMap.java b/staticlibs/device/com/android/net/module/util/IBpfMap.java index d43b22c619..dce369a25c 100644 --- a/staticlibs/device/com/android/net/module/util/IBpfMap.java +++ b/staticlibs/device/com/android/net/module/util/IBpfMap.java @@ -20,7 +20,6 @@ import android.system.ErrnoException; import androidx.annotation.NonNull; import java.util.NoSuchElementException; -import java.util.function.BiConsumer; /** * The interface of BpfMap. This could be used to inject for testing. @@ -29,7 +28,7 @@ import java.util.function.BiConsumer; * @param the key of the map. * @param the value of the map. */ -public interface IBpfMap { +public interface IBpfMap extends AutoCloseable { /** Update an existing or create a new key -> value entry in an eBbpf map. */ void updateEntry(K key, V value) throws ErrnoException; From ab28c7ef13ce5ccb5649be9e3b52613a9eb99763 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Thu, 28 Apr 2022 15:38:43 +0800 Subject: [PATCH 430/777] Migrate compareMajorMinorVersion from ConnectivityManagerTest Move compareMajorMinorVersion() and getVersionFromString() from ConnectivityManagerTest.java. Test: atest DeviceInfoUtilsTest Change-Id: Ib8245890856a3e4518e48e0afeada746a24e8b22 (cherry picked from commit 5c3d6e0d708ce8248d63d671f3db383169ee63f8) Merged-In: Ib8245890856a3e4518e48e0afeada746a24e8b22 --- .../android/testutils/DeviceInfoUtils.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java b/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java new file mode 100644 index 0000000000..69cb5f81a7 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java @@ -0,0 +1,63 @@ +/* + * 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 com.android.testutils; + +import android.text.TextUtils; +import android.util.Pair; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Utilities for device information. + */ +public class DeviceInfoUtils { + private static Pair getVersionFromString(String version) { + // Only gets major and minor number of the version string. + final Pattern versionPattern = Pattern.compile("^(\\d+)(\\.(\\d+))?.*"); + final Matcher m = versionPattern.matcher(version); + if (m.matches()) { + final int major = Integer.parseInt(m.group(1)); + final int minor = TextUtils.isEmpty(m.group(3)) ? 0 : Integer.parseInt(m.group(3)); + return new Pair<>(major, minor); + } else { + return new Pair<>(0, 0); + } + } + + /** + * Compares two version strings numerically. Compare only major and minor number of the + * version string. The version comparison uses #Integer.compare. Possible version + * 5, 5.10, 5-beta1, 4.8-RC1, 4.7.10.10 and so on. + * + * @param s1 the first version string to compare + * @param s2 the second version string to compare + * @return the value 0 if s1 == s2; + * a value less than 0 if s1 < s2 and + * a value greater than 0 if s1 > s2. + */ + public static int compareMajorMinorVersion(final String s1, final String s2) { + final Pair v1 = getVersionFromString(s1); + final Pair v2 = getVersionFromString(s2); + + if (v1.first == v2.first) { + return Integer.compare(v1.second, v2.second); + } else { + return Integer.compare(v1.first, v2.first); + } + } +} From c9345142db1445fdd0afad7d924927fc8b121afe Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Mon, 9 May 2022 21:07:40 +0800 Subject: [PATCH 431/777] Move DeviceInfoUtilsTest from NetworkStack to frameworks/lib/net Test: atest com.android.testutils.DeviceInfoUtilsTest Change-Id: Ib45dea951980eae0c1576d37842477192539a740 --- .../testutils/DeviceInfoUtilsTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java diff --git a/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java b/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java new file mode 100644 index 0000000000..f99700a6f4 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java @@ -0,0 +1,45 @@ +/* + * 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 com.android.testutils; + +import static org.junit.Assert.assertEquals; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +@SmallTest +public final class DeviceInfoUtilsTest { + /** + * Verifies that version string compare logic returns expected result for various cases. + * Note that only major and minor number are compared. + */ + @Test + public void testMajorMinorVersionCompare() { + assertEquals(0, DeviceInfoUtils.compareMajorMinorVersion("4.8.1", "4.8")); + assertEquals(1, DeviceInfoUtils.compareMajorMinorVersion("4.9", "4.8.1")); + assertEquals(1, DeviceInfoUtils.compareMajorMinorVersion("5.0", "4.8")); + assertEquals(1, DeviceInfoUtils.compareMajorMinorVersion("5", "4.8")); + assertEquals(0, DeviceInfoUtils.compareMajorMinorVersion("5", "5.0")); + assertEquals(1, DeviceInfoUtils.compareMajorMinorVersion("5-beta1", "4.8")); + assertEquals(0, DeviceInfoUtils.compareMajorMinorVersion("4.8.0.0", "4.8")); + assertEquals(0, DeviceInfoUtils.compareMajorMinorVersion("4.8-RC1", "4.8")); + assertEquals(0, DeviceInfoUtils.compareMajorMinorVersion("4.8", "4.8")); + assertEquals(-1, DeviceInfoUtils.compareMajorMinorVersion("3.10", "4.8.0")); + assertEquals(-1, DeviceInfoUtils.compareMajorMinorVersion("4.7.10.10", "4.8")); + } +} From b411547dd2653a1ab2c1b5637a95ff9e8cee74d3 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Thu, 12 May 2022 13:39:39 +0800 Subject: [PATCH 432/777] BpfMap: wrap native fd with ParcelFileDescriptor to avoid fd leak ParcelFileDescriptor has implemented finalize(). Wrap native fd into ParcelFileDescriptor which helps to release fd automatically. Bug: 230880517 Test: manual test Steps: 1. Connect to IPv6 only wifi and clat maps are created $ adb shell cmd wifi set-wifi-enabled enabled 05-12 13:53:41.182 1793 2031 W BpfMap : open /sys/fs/bpf/net_shared/map_clatd_clat_ingress6_map..: 493 05-12 13:53:41.182 1793 2031 W BpfMap : open /sys/fs/bpf/net_shared/map_clatd_clat_egress4_map..: 546 $ adb shell ls -all proc/1793/fd | grep bpf .. system system 64 2022-05-12 13:55:35 .. 493 -> anon_inode:bpf-map .. system system 64 2022-05-12 13:55:35 .. 546 -> anon_inode:bpf-map $ adb shell dumpsys connectivity Forwarding rules: BPF ingress map: iif nat64Prefix v6Addr -> v4Addr oif 47 /64:ff9b::/96 /2a00:79e1:abc:6f02:6efd:1d4b:f05e:25bd -> /192.0.0.4 54 BPF egress map: iif v4Addr -> v6Addr nat64Prefix oif 54 /192.0.0.4 -> /2a00:79e1:abc:6f02:6efd:1d4b:f05e:25bd /64:ff9b::/96 47 ether 2. Disconnect from IPv6 only wifi, force GC and clat map fds are released $ adb shell cmd wifi set-wifi-enabled disabled $ adb shell kill -10 1793 $ adb shell ls -all proc/1793/fd | grep bpf (fd 493 and 546 are removed) Change-Id: I26bbafbd73eccab6f4ae2c71690ecad12bbef7df --- .../com/android/net/module/util/BpfMap.java | 32 +++++++++---------- .../com_android_net_module_util_BpfMap.cpp | 11 ------- 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java index f1420c2131..0ee862acfe 100644 --- a/staticlibs/device/com/android/net/module/util/BpfMap.java +++ b/staticlibs/device/com/android/net/module/util/BpfMap.java @@ -18,6 +18,7 @@ package com.android.net.module.util; import static android.system.OsConstants.EEXIST; import static android.system.OsConstants.ENOENT; +import android.os.ParcelFileDescriptor; import android.system.ErrnoException; import androidx.annotation.NonNull; @@ -26,6 +27,7 @@ import androidx.annotation.VisibleForTesting; import com.android.net.module.util.Struct; +import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.NoSuchElementException; @@ -57,7 +59,7 @@ public class BpfMap implements IBpfMap private static final int BPF_NOEXIST = 1; private static final int BPF_EXIST = 2; - private final int mMapFd; + private final ParcelFileDescriptor mMapFd; private final Class mKeyClass; private final Class mValueClass; private final int mKeySize; @@ -72,8 +74,7 @@ public class BpfMap implements IBpfMap */ public BpfMap(@NonNull final String path, final int flag, final Class key, final Class value) throws ErrnoException, NullPointerException { - mMapFd = bpfFdGet(path, flag); - + mMapFd = ParcelFileDescriptor.adoptFd(bpfFdGet(path, flag)); mKeyClass = key; mValueClass = value; mKeySize = Struct.getSize(key); @@ -85,10 +86,11 @@ public class BpfMap implements IBpfMap * The derived class implements an internal mocked map. It need to implement all functions * which are related with the native BPF map because the BPF map handler is not initialized. * See BpfCoordinatorTest#TestBpfMap. + * TODO: remove once TestBpfMap derive from IBpfMap. */ @VisibleForTesting protected BpfMap(final Class key, final Class value) { - mMapFd = -1; + mMapFd = ParcelFileDescriptor.adoptFd(-1 /*invalid*/); // unused mKeyClass = key; mValueClass = value; mKeySize = Struct.getSize(key); @@ -101,7 +103,7 @@ public class BpfMap implements IBpfMap */ @Override public void updateEntry(K key, V value) throws ErrnoException { - writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_ANY); + writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_ANY); } /** @@ -112,7 +114,7 @@ public class BpfMap implements IBpfMap public void insertEntry(K key, V value) throws ErrnoException, IllegalStateException { try { - writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_NOEXIST); + writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_NOEXIST); } catch (ErrnoException e) { if (e.errno == EEXIST) throw new IllegalStateException(key + " already exists"); @@ -128,7 +130,7 @@ public class BpfMap implements IBpfMap public void replaceEntry(K key, V value) throws ErrnoException, NoSuchElementException { try { - writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_EXIST); + writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_EXIST); } catch (ErrnoException e) { if (e.errno == ENOENT) throw new NoSuchElementException(key + " not found"); @@ -146,13 +148,13 @@ public class BpfMap implements IBpfMap public boolean insertOrReplaceEntry(K key, V value) throws ErrnoException { try { - writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_NOEXIST); + writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_NOEXIST); return true; /* insert succeeded */ } catch (ErrnoException e) { if (e.errno != EEXIST) throw e; } try { - writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_EXIST); + writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_EXIST); return false; /* replace succeeded */ } catch (ErrnoException e) { if (e.errno != ENOENT) throw e; @@ -169,7 +171,7 @@ public class BpfMap implements IBpfMap /** Remove existing key from eBpf map. Return false if map was not modified. */ @Override public boolean deleteEntry(K key) throws ErrnoException { - return deleteMapEntry(mMapFd, key.writeToBytes()); + return deleteMapEntry(mMapFd.getFd(), key.writeToBytes()); } /** Returns {@code true} if this map contains no elements. */ @@ -202,7 +204,7 @@ public class BpfMap implements IBpfMap private byte[] getNextRawKey(@Nullable final byte[] key) throws ErrnoException { byte[] nextKey = new byte[mKeySize]; - if (getNextMapKey(mMapFd, key, nextKey)) return nextKey; + if (getNextMapKey(mMapFd.getFd(), key, nextKey)) return nextKey; return null; } @@ -237,7 +239,7 @@ public class BpfMap implements IBpfMap private byte[] getRawValue(final byte[] key) throws ErrnoException { byte[] value = new byte[mValueSize]; - if (findMapEntry(mMapFd, key, value)) return value; + if (findMapEntry(mMapFd.getFd(), key, value)) return value; return null; } @@ -262,8 +264,8 @@ public class BpfMap implements IBpfMap } @Override - public void close() throws ErrnoException { - closeMap(mMapFd); + public void close() throws IOException { + mMapFd.close(); } /** @@ -281,8 +283,6 @@ public class BpfMap implements IBpfMap } } - private static native int closeMap(int fd) throws ErrnoException; - private native int bpfFdGet(String path, int mode) throws ErrnoException, NullPointerException; private native void writeToMapEntry(int fd, byte[] key, byte[] value, int flags) diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp index e25e17de36..e3f48e5644 100644 --- a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp +++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp @@ -27,15 +27,6 @@ namespace android { -static jint com_android_net_module_util_BpfMap_closeMap(JNIEnv *env, jobject clazz, - jint fd) { - int ret = close(fd); - - if (ret) jniThrowErrnoException(env, "closeMap", errno); - - return ret; -} - static jint com_android_net_module_util_BpfMap_bpfFdGet(JNIEnv *env, jobject clazz, jstring path, jint mode) { ScopedUtfChars pathname(env, path); @@ -112,8 +103,6 @@ static jboolean com_android_net_module_util_BpfMap_findMapEntry(JNIEnv *env, job */ static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ - { "closeMap", "(I)I", - (void*) com_android_net_module_util_BpfMap_closeMap }, { "bpfFdGet", "(Ljava/lang/String;I)I", (void*) com_android_net_module_util_BpfMap_bpfFdGet }, { "writeToMapEntry", "(I[B[BI)V", From 7c29887e0f3d45db4c9ee9d43455d8293b80719a Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 5 May 2022 18:14:57 +0800 Subject: [PATCH 433/777] Add PerUidCounter The class keeps track of the counters under different uid, fire exception if the counter exceeded the specified maximum value. This is reimplemented and generalized based on the one inside ConnectivityService. Test: atest NetworkStaticLibTests:com.android.net.moduletests.util.PerUidCounterTest Test: atest ConnectivityCoverageTests:android.net.connectivity.com.android.net.module.util.PerUidCounterTest Bug: 229103088 Change-Id: I7dfb16342e3ca4eab45bb40f2e1355981e04b44b --- .../net/module/util/PerUidCounter.java | 107 ++++++++++++++++ .../net/module/util/PerUidCounterTest.kt | 114 ++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 staticlibs/framework/com/android/net/module/util/PerUidCounter.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt diff --git a/staticlibs/framework/com/android/net/module/util/PerUidCounter.java b/staticlibs/framework/com/android/net/module/util/PerUidCounter.java new file mode 100644 index 0000000000..7e0526d1f7 --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/PerUidCounter.java @@ -0,0 +1,107 @@ +/* + * 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 com.android.net.module.util; + +import android.util.SparseIntArray; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; + +/** + * Keeps track of the counters under different uid, fire exception if the counter + * exceeded the specified maximum value. + * + * @hide + */ +public class PerUidCounter { + private final int mMaxCountPerUid; + + // Map from UID to count that UID has filed. + @VisibleForTesting + @GuardedBy("mUidToCount") + final SparseIntArray mUidToCount = new SparseIntArray(); + + /** + * Constructor + * + * @param maxCountPerUid the maximum count per uid allowed + */ + public PerUidCounter(final int maxCountPerUid) { + if (maxCountPerUid < 0) { + throw new IllegalArgumentException("Maximum counter value cannot be negative"); + } + mMaxCountPerUid = maxCountPerUid; + } + + /** + * Increments the count of the given uid. Throws an exception if the number + * of the counter for the uid exceeds the value of maxCounterPerUid which is the value + * passed into the constructor. see: {@link #PerUidCounter(int)}. + * + * @throws IllegalStateException if the number of counter for the uid exceed + * the allowed number. + * + * @param uid the uid that the counter was made under + */ + public void incrementCountOrThrow(final int uid) { + synchronized (mUidToCount) { + incrementCountOrThrow(uid, 1 /* numToIncrement */); + } + } + + public void incrementCountOrThrow(final int uid, final int numToIncrement) { + if (numToIncrement <= 0) { + throw new IllegalArgumentException("Increment count must be positive"); + } + final long newCount = ((long) mUidToCount.get(uid, 0)) + numToIncrement; + if (newCount > mMaxCountPerUid) { + throw new IllegalStateException("Uid " + uid + " exceeded its allowed limit"); + } + // Since the count cannot be greater than Integer.MAX_VALUE here, + // it is safe to cast to int. + mUidToCount.put(uid, (int) newCount); + } + + /** + * Decrements the count of the given uid. Throws an exception if the number + * of the counter goes below zero. + * + * @throws IllegalStateException if the number of counter for the uid goes below + * zero. + * + * @param uid the uid that the count was made under + */ + public void decrementCountOrThrow(final int uid) { + synchronized (mUidToCount) { + decrementCountOrThrow(uid, 1 /* numToDecrement */); + } + } + + public void decrementCountOrThrow(final int uid, final int numToDecrement) { + if (numToDecrement <= 0) { + throw new IllegalArgumentException("Decrement count must be positive"); + } + final int newCount = mUidToCount.get(uid, 0) - numToDecrement; + if (newCount < 0) { + throw new IllegalStateException("BUG: too small count " + newCount + " for UID " + uid); + } else if (newCount == 0) { + mUidToCount.delete(uid); + } else { + mUidToCount.put(uid, newCount); + } + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt new file mode 100644 index 0000000000..c479d81bf6 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt @@ -0,0 +1,114 @@ +/* + * 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 com.android.net.module.util + +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.test.assertFailsWith + +@RunWith(AndroidJUnit4::class) +@SmallTest +class PerUidCounterTest { + private val UID_A = 1000 + private val UID_B = 1001 + + @Test + fun testCounterMaximum() { + assertFailsWith { + PerUidCounter(-1) + } + + val uselessCounter = PerUidCounter(0) + assertFailsWith { + uselessCounter.incrementCountOrThrow(UID_A) + } + assertFailsWith { + uselessCounter.decrementCountOrThrow(UID_A) + } + + val largeMaxCounter = PerUidCounter(Integer.MAX_VALUE) + largeMaxCounter.incrementCountOrThrow(UID_A, Integer.MAX_VALUE) + assertFailsWith { + largeMaxCounter.incrementCountOrThrow(UID_A) + } + } + + @Test + fun testIncrementCountOrThrow() { + val counter = PerUidCounter(3) + + // Verify the increment count cannot be zero. + assertFailsWith { + counter.incrementCountOrThrow(UID_A, 0) + } + + // Verify the counters work independently. + counter.incrementCountOrThrow(UID_A) + counter.incrementCountOrThrow(UID_B, 2) + counter.incrementCountOrThrow(UID_B) + counter.incrementCountOrThrow(UID_A) + counter.incrementCountOrThrow(UID_A) + assertFailsWith { + counter.incrementCountOrThrow(UID_A) + } + assertFailsWith { + counter.incrementCountOrThrow(UID_B) + } + + // Verify exception can be triggered again. + assertFailsWith { + counter.incrementCountOrThrow(UID_A) + } + assertFailsWith { + counter.incrementCountOrThrow(UID_A, 3) + } + } + + @Test + fun testDecrementCountOrThrow() { + val counter = PerUidCounter(3) + + // Verify the decrement count cannot be zero. + assertFailsWith { + counter.decrementCountOrThrow(UID_A, 0) + } + + // Verify the count cannot go below zero. + assertFailsWith { + counter.decrementCountOrThrow(UID_A) + } + assertFailsWith { + counter.decrementCountOrThrow(UID_A, 5) + } + assertFailsWith { + counter.decrementCountOrThrow(UID_A, Integer.MAX_VALUE) + } + + // Verify the counters work independently. + counter.incrementCountOrThrow(UID_A) + counter.incrementCountOrThrow(UID_B) + assertFailsWith { + counter.decrementCountOrThrow(UID_A, 3) + } + counter.decrementCountOrThrow(UID_A) + assertFailsWith { + counter.decrementCountOrThrow(UID_A) + } + } +} \ No newline at end of file From 5ce819777846d3f4b65cf73c03e3060bace9a6da Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Thu, 12 May 2022 13:39:39 +0800 Subject: [PATCH 434/777] BpfMap: wrap native fd with ParcelFileDescriptor to avoid fd leak ParcelFileDescriptor has implemented finalize(). Wrap native fd into ParcelFileDescriptor which helps to release fd automatically. Bug: 230880517 Test: manual test Steps: 1. Connect to IPv6 only wifi and clat maps are created $ adb shell cmd wifi set-wifi-enabled enabled 05-12 13:53:41.182 1793 2031 W BpfMap : open /sys/fs/bpf/net_shared/map_clatd_clat_ingress6_map..: 493 05-12 13:53:41.182 1793 2031 W BpfMap : open /sys/fs/bpf/net_shared/map_clatd_clat_egress4_map..: 546 $ adb shell ls -all proc/1793/fd | grep bpf .. system system 64 2022-05-12 13:55:35 .. 493 -> anon_inode:bpf-map .. system system 64 2022-05-12 13:55:35 .. 546 -> anon_inode:bpf-map $ adb shell dumpsys connectivity Forwarding rules: BPF ingress map: iif nat64Prefix v6Addr -> v4Addr oif 47 /64:ff9b::/96 /2a00:79e1:abc:6f02:6efd:1d4b:f05e:25bd -> /192.0.0.4 54 BPF egress map: iif v4Addr -> v6Addr nat64Prefix oif 54 /192.0.0.4 -> /2a00:79e1:abc:6f02:6efd:1d4b:f05e:25bd /64:ff9b::/96 47 ether 2. Disconnect from IPv6 only wifi, force GC and clat map fds are released $ adb shell cmd wifi set-wifi-enabled disabled $ adb shell kill -10 1793 $ adb shell ls -all proc/1793/fd | grep bpf (fd 493 and 546 are removed) Change-Id: I26bbafbd73eccab6f4ae2c71690ecad12bbef7df (cherry picked from commit ef5e791312fbed4ead02809893039d8e21b43a03) Merged-In: I26bbafbd73eccab6f4ae2c71690ecad12bbef7df --- .../com/android/net/module/util/BpfMap.java | 32 +++++++++---------- .../com_android_net_module_util_BpfMap.cpp | 11 ------- 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java index d4ce83b48e..a7fbab77e9 100644 --- a/staticlibs/device/com/android/net/module/util/BpfMap.java +++ b/staticlibs/device/com/android/net/module/util/BpfMap.java @@ -18,6 +18,7 @@ package com.android.net.module.util; import static android.system.OsConstants.EEXIST; import static android.system.OsConstants.ENOENT; +import android.os.ParcelFileDescriptor; import android.system.ErrnoException; import androidx.annotation.NonNull; @@ -26,6 +27,7 @@ import androidx.annotation.VisibleForTesting; import com.android.net.module.util.Struct; +import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.NoSuchElementException; @@ -57,7 +59,7 @@ public class BpfMap implements IBpfMap private static final int BPF_NOEXIST = 1; private static final int BPF_EXIST = 2; - private final int mMapFd; + private final ParcelFileDescriptor mMapFd; private final Class mKeyClass; private final Class mValueClass; private final int mKeySize; @@ -72,8 +74,7 @@ public class BpfMap implements IBpfMap */ public BpfMap(@NonNull final String path, final int flag, final Class key, final Class value) throws ErrnoException, NullPointerException { - mMapFd = bpfFdGet(path, flag); - + mMapFd = ParcelFileDescriptor.adoptFd(bpfFdGet(path, flag)); mKeyClass = key; mValueClass = value; mKeySize = Struct.getSize(key); @@ -85,10 +86,11 @@ public class BpfMap implements IBpfMap * The derived class implements an internal mocked map. It need to implement all functions * which are related with the native BPF map because the BPF map handler is not initialized. * See BpfCoordinatorTest#TestBpfMap. + * TODO: remove once TestBpfMap derive from IBpfMap. */ @VisibleForTesting protected BpfMap(final Class key, final Class value) { - mMapFd = -1; + mMapFd = ParcelFileDescriptor.adoptFd(-1 /*invalid*/); // unused mKeyClass = key; mValueClass = value; mKeySize = Struct.getSize(key); @@ -101,7 +103,7 @@ public class BpfMap implements IBpfMap */ @Override public void updateEntry(K key, V value) throws ErrnoException { - writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_ANY); + writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_ANY); } /** @@ -112,7 +114,7 @@ public class BpfMap implements IBpfMap public void insertEntry(K key, V value) throws ErrnoException, IllegalStateException { try { - writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_NOEXIST); + writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_NOEXIST); } catch (ErrnoException e) { if (e.errno == EEXIST) throw new IllegalStateException(key + " already exists"); @@ -128,7 +130,7 @@ public class BpfMap implements IBpfMap public void replaceEntry(K key, V value) throws ErrnoException, NoSuchElementException { try { - writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_EXIST); + writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_EXIST); } catch (ErrnoException e) { if (e.errno == ENOENT) throw new NoSuchElementException(key + " not found"); @@ -146,13 +148,13 @@ public class BpfMap implements IBpfMap public boolean insertOrReplaceEntry(K key, V value) throws ErrnoException { try { - writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_NOEXIST); + writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_NOEXIST); return true; /* insert succeeded */ } catch (ErrnoException e) { if (e.errno != EEXIST) throw e; } try { - writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_EXIST); + writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_EXIST); return false; /* replace succeeded */ } catch (ErrnoException e) { if (e.errno != ENOENT) throw e; @@ -169,7 +171,7 @@ public class BpfMap implements IBpfMap /** Remove existing key from eBpf map. Return false if map was not modified. */ @Override public boolean deleteEntry(K key) throws ErrnoException { - return deleteMapEntry(mMapFd, key.writeToBytes()); + return deleteMapEntry(mMapFd.getFd(), key.writeToBytes()); } /** Returns {@code true} if this map contains no elements. */ @@ -202,7 +204,7 @@ public class BpfMap implements IBpfMap private byte[] getNextRawKey(@Nullable final byte[] key) throws ErrnoException { byte[] nextKey = new byte[mKeySize]; - if (getNextMapKey(mMapFd, key, nextKey)) return nextKey; + if (getNextMapKey(mMapFd.getFd(), key, nextKey)) return nextKey; return null; } @@ -237,7 +239,7 @@ public class BpfMap implements IBpfMap private byte[] getRawValue(final byte[] key) throws ErrnoException { byte[] value = new byte[mValueSize]; - if (findMapEntry(mMapFd, key, value)) return value; + if (findMapEntry(mMapFd.getFd(), key, value)) return value; return null; } @@ -262,8 +264,8 @@ public class BpfMap implements IBpfMap } @Override - public void close() throws ErrnoException { - closeMap(mMapFd); + public void close() throws IOException { + mMapFd.close(); } /** @@ -281,8 +283,6 @@ public class BpfMap implements IBpfMap } } - private static native int closeMap(int fd) throws ErrnoException; - private native int bpfFdGet(String path, int mode) throws ErrnoException, NullPointerException; private native void writeToMapEntry(int fd, byte[] key, byte[] value, int flags) diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp index e25e17de36..e3f48e5644 100644 --- a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp +++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp @@ -27,15 +27,6 @@ namespace android { -static jint com_android_net_module_util_BpfMap_closeMap(JNIEnv *env, jobject clazz, - jint fd) { - int ret = close(fd); - - if (ret) jniThrowErrnoException(env, "closeMap", errno); - - return ret; -} - static jint com_android_net_module_util_BpfMap_bpfFdGet(JNIEnv *env, jobject clazz, jstring path, jint mode) { ScopedUtfChars pathname(env, path); @@ -112,8 +103,6 @@ static jboolean com_android_net_module_util_BpfMap_findMapEntry(JNIEnv *env, job */ static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ - { "closeMap", "(I)I", - (void*) com_android_net_module_util_BpfMap_closeMap }, { "bpfFdGet", "(Ljava/lang/String;I)I", (void*) com_android_net_module_util_BpfMap_bpfFdGet }, { "writeToMapEntry", "(I[B[BI)V", From d39942d65a4ea71c11ab6e6886559af55310e7bb Mon Sep 17 00:00:00 2001 From: Chiachang Date: Wed, 11 May 2022 05:39:15 +0000 Subject: [PATCH 435/777] Add IPPrefix.contains() Add helper methods to check whether the specified prefix is entirely contained in this prefix, or the specified address is contained in this prefix. Bug: 184750836 Test: atest IPPrefixTest Change-Id: I838510b347ac5741c589ee8f3983111209155588 --- .../libnetdutils/InternetAddressesTest.cpp | 187 ++++++++++++++++++ .../include/netdutils/InternetAddresses.h | 6 + 2 files changed, 193 insertions(+) diff --git a/staticlibs/netd/libnetdutils/InternetAddressesTest.cpp b/staticlibs/netd/libnetdutils/InternetAddressesTest.cpp index f75fa769ee..9e37d11f7e 100644 --- a/staticlibs/netd/libnetdutils/InternetAddressesTest.cpp +++ b/staticlibs/netd/libnetdutils/InternetAddressesTest.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include "netdutils/InternetAddresses.h" @@ -438,6 +439,192 @@ TEST(IPPrefixTest, TruncationOther) { } } +TEST(IPPrefixTest, containsPrefix) { + const struct { + const char* prefix; + const char* otherPrefix; + const bool expected; + std::string asParameters() const { + return fmt::format("prefix={}, other={}, expect={}", prefix, otherPrefix, expected); + } + } testExpectations[] = { + {"192.0.0.0/8", "192.0.0.0/8", true}, + {"192.1.0.0/16", "192.1.0.0/16", true}, + {"192.1.2.0/24", "192.1.2.0/24", true}, + {"192.1.2.3/32", "192.1.2.3/32", true}, + {"0.0.0.0/0", "192.0.0.0/8", true}, + {"0.0.0.0/0", "192.1.0.0/16", true}, + {"0.0.0.0/0", "192.1.2.0/24", true}, + {"0.0.0.0/0", "192.1.2.3/32", true}, + {"192.0.0.0/8", "192.1.0.0/16", true}, + {"192.0.0.0/8", "192.1.2.0/24", true}, + {"192.0.0.0/8", "192.1.2.5/32", true}, + {"192.1.0.0/16", "192.1.2.0/24", true}, + {"192.1.0.0/16", "192.1.3.6/32", true}, + {"192.5.6.0/24", "192.5.6.7/32", true}, + {"192.1.2.3/32", "192.1.2.0/24", false}, + {"192.1.2.3/32", "192.1.0.0/16", false}, + {"192.1.2.3/32", "192.0.0.0/8", false}, + {"192.1.2.3/32", "0.0.0.0/0", false}, + {"192.1.2.0/24", "192.1.0.0/16", false}, + {"192.1.2.0/24", "192.0.0.0/8", false}, + {"192.1.2.0/24", "0.0.0.0/0", false}, + {"192.9.0.0/16", "192.0.0.0/8", false}, + {"192.9.0.0/16", "0.0.0.0/0", false}, + {"192.0.0.0/8", "0.0.0.0/0", false}, + {"192.0.0.0/8", "191.0.0.0/8", false}, + {"191.0.0.0/8", "192.0.0.0/8", false}, + {"192.8.0.0/16", "192.7.0.0/16", false}, + {"192.7.0.0/16", "192.8.0.0/16", false}, + {"192.8.6.0/24", "192.7.5.0/24", false}, + {"192.7.5.0/24", "192.8.6.0/24", false}, + {"192.8.6.100/32", "192.8.6.200/32", false}, + {"192.8.6.200/32", "192.8.6.100/32", false}, + {"192.0.0.0/8", "192.0.0.0/12", true}, + {"192.0.0.0/12", "192.0.0.0/8", false}, + {"2001::/16", "2001::/16", true}, + {"2001:db8::/32", "2001:db8::/32", true}, + {"2001:db8:cafe::/48", "2001:db8:cafe::/48", true}, + {"2001:db8:cafe:d00d::/64", "2001:db8:cafe:d00d::/64", true}, + {"2001:db8:cafe:d00d:fec0::/80", "2001:db8:cafe:d00d:fec0::/80", true}, + {"2001:db8:cafe:d00d:fec0:de::/96", "2001:db8:cafe:d00d:fec0:de::/96", true}, + {"2001:db8:cafe:d00d:fec0:de:ac::/112", "2001:db8:cafe:d00d:fec0:de:ac::/112", true}, + {"2001:db8::cafe:0:1/128", "2001:db8::cafe:0:1/128", true}, + {"2001::/16", "2001:db8::/32", true}, + {"2001::/16", "2001:db8:cafe::/48", true}, + {"2001::/16", "2001:db8:cafe:d00d::/64", true}, + {"2001::/16", "2001:db8:cafe:d00d:fec0::/80", true}, + {"2001::/16", "2001:db8:cafe:d00d:fec0:de::/96", true}, + {"2001::/16", "2001:db8:cafe:d00d:fec0:de:ac::/112", true}, + {"2001::/16", "2001:db8:cafe:d00d:fec0:de:ac:dd/128", true}, + {"::/0", "2001::/16", true}, + {"::/0", "2001:db8::/32", true}, + {"::/0", "2001:db8:cafe::/48", true}, + {"::/0", "2001:db8:cafe:d00d::/64", true}, + {"::/0", "2001:db8:cafe:d00d:fec0::/80", true}, + {"::/0", "2001:db8:cafe:d00d:fec0:de::/96", true}, + {"::/0", "2001:db8:cafe:d00d:fec0:de:ac::/112", true}, + {"::/0", "2001:db8:cafe:d00d:fec0:de:ac:dd/128", true}, + {"2001:db8::dd/128", "2001::/16", false}, + {"2001:db8::dd/128", "2001:db8::/32", false}, + {"2001:db8::dd/128", "2001:db8:cafe::/48", false}, + {"2001:db8::dd/128", "2001:db8:cafe:d00d::/64", false}, + {"2001:db8::dd/128", "2001:db8:cafe:d00d:fec0::/80", false}, + {"2001:db8::dd/128", "2001:db8:cafe:d00d:fec0:de::/96", false}, + {"2001:db8::dd/128", "2001:db8:cafe:d00d:fec0:de:ac::/112", false}, + {"2001:db7::/32", "2001:db8::/32", false}, + {"2001:db8::/32", "2001:db7::/32", false}, + {"2001:db8:caff::/48", "2001:db8:cafe::/48", false}, + {"2001:db8:cafe::/48", "2001:db8:caff::/48", false}, + {"2001:db8:cafe:a00d::/64", "2001:db8:cafe:d00d::/64", false}, + {"2001:db8:cafe:d00d::/64", "2001:db8:cafe:a00d::/64", false}, + {"2001:db8:cafe:d00d:fec1::/80", "2001:db8:cafe:d00d:fec0::/80", false}, + {"2001:db8:cafe:d00d:fec0::/80", "2001:db8:cafe:d00d:fec1::/80", false}, + {"2001:db8:cafe:d00d:fec0:dd::/96", "2001:db8:cafe:d00d:fec0:ae::/96", false}, + {"2001:db8:cafe:d00d:fec0:ae::/96", "2001:db8:cafe:d00d:fec0:dd::/96", false}, + {"2001:db8:cafe:d00d:fec0:de:aa::/112", "2001:db8:cafe:d00d:fec0:de:ac::/112", false}, + {"2001:db8:cafe:d00d:fec0:de:ac::/112", "2001:db8:cafe:d00d:fec0:de:aa::/112", false}, + {"2001:db8::cafe:0:123/128", "2001:db8::cafe:0:456/128", false}, + {"2001:db8::cafe:0:456/128", "2001:db8::cafe:0:123/128", false}, + {"2001:db8::/32", "2001:db8::/64", true}, + {"2001:db8::/64", "2001:db8::/32", false}, + {"::/0", "0.0.0.0/0", false}, + {"::/0", "1.0.0.0/8", false}, + {"::/0", "1.2.0.0/16", false}, + {"::/0", "1.2.3.0/24", false}, + {"::/0", "1.2.3.4/32", false}, + {"2001::/16", "1.2.3.4/32", false}, + {"2001::db8::/32", "1.2.3.4/32", false}, + {"2001:db8:cafe::/48", "1.2.3.4/32", false}, + {"2001:db8:cafe:d00d::/64", "1.2.3.4/32", false}, + {"2001:db8:cafe:d00d:fec0::/80", "1.2.3.4/32", false}, + {"2001:db8:cafe:d00d:fec0:ae::/96", "1.2.3.4/32", false}, + {"2001:db8:cafe:d00d:fec0:de:aa::/112", "1.2.3.4/32", false}, + {"0.0.0.0/0", "::/0", false}, + {"0.0.0.0/0", "2001::/16", false}, + {"0.0.0.0/0", "2001::db8::/32", false}, + {"0.0.0.0/0", "2001:db8:cafe::/48", false}, + {"0.0.0.0/0", "2001:db8:cafe:d00d::/64", false}, + {"0.0.0.0/0", "2001:db8:cafe:d00d:fec0::/80", false}, + {"0.0.0.0/0", "2001:db8:cafe:d00d:fec0:ae::/96", false}, + {"0.0.0.0/0", "2001:db8:cafe:d00d:fec0:de:aa::/112", false}, + {"1.2.3.4/32", "2001:db8:cafe:d00d:fec0:de:aa::/112", false}, + {"1.2.3.0/24", "2001:db8:cafe:d00d:fec0:de:aa::/112", false}, + {"1.2.0.0/16", "2001:db8:cafe:d00d:fec0:de:aa::/112", false}, + {"1.0.0.0/8", "2001:db8:cafe:d00d:fec0:de:aa::/112", false}, + }; + + for (const auto& expectation : testExpectations) { + SCOPED_TRACE(expectation.asParameters()); + IPPrefix a = IPPrefix::forString(expectation.prefix); + IPPrefix b = IPPrefix::forString(expectation.otherPrefix); + EXPECT_EQ(expectation.expected, a.contains(b)); + } +} + +TEST(IPPrefixTest, containsAddress) { + const struct { + const char* prefix; + const char* address; + const bool expected; + std::string asParameters() const { + return fmt::format("prefix={}, address={}, expect={}", prefix, address, expected); + } + } testExpectations[] = { + {"0.0.0.0/0", "255.255.255.255", true}, + {"0.0.0.0/0", "1.2.3.4", true}, + {"0.0.0.0/0", "1.2.3.0", true}, + {"0.0.0.0/0", "1.2.0.0", true}, + {"0.0.0.0/0", "1.0.0.0", true}, + {"0.0.0.0/0", "0.0.0.0", true}, + {"0.0.0.0/0", "2001:4868:4860::8888", false}, + {"0.0.0.0/0", "::/0", false}, + {"192.0.2.0/23", "192.0.2.0", true}, + {"192.0.2.0/23", "192.0.2.43", true}, + {"192.0.2.0/23", "192.0.3.21", true}, + {"192.0.2.0/23", "192.0.0.21", false}, + {"192.0.2.0/23", "8.8.8.8", false}, + {"192.0.2.0/23", "2001:4868:4860::8888", false}, + {"192.0.2.0/23", "::/0", false}, + {"1.2.3.4/32", "1.2.3.4", true}, + {"1.2.3.4/32", "1.2.3.5", false}, + {"10.0.0.0/8", "10.2.0.0", true}, + {"10.0.0.0/8", "10.2.3.5", true}, + {"10.0.0.0/8", "10.0.0.0", true}, + {"10.0.0.0/8", "10.255.255.254", true}, + {"10.0.0.0/8", "11.0.0.0", false}, + {"::/0", "2001:db8:f000::ace:d00c", true}, + {"::/0", "2002:db8:f00::ace:d00d", true}, + {"::/0", "2001:db7:f00::ace:d00e", true}, + {"::/0", "2001:db8:f01::bad:d00d", true}, + {"::/0", "::", true}, + {"::/0", "0.0.0.0", false}, + {"::/0", "1.2.3.4", false}, + {"2001:db8:f00::ace:d00d/127", "2001:db8:f00::ace:d00c", true}, + {"2001:db8:f00::ace:d00d/127", "2001:db8:f00::ace:d00d", true}, + {"2001:db8:f00::ace:d00d/127", "2001:db8:f00::ace:d00e", false}, + {"2001:db8:f00::ace:d00d/127", "2001:db8:f00::bad:d00d", false}, + {"2001:db8:f00::ace:d00d/127", "2001:4868:4860::8888", false}, + {"2001:db8:f00::ace:d00d/127", "8.8.8.8", false}, + {"2001:db8:f00::ace:d00d/127", "0.0.0.0", false}, + {"2001:db8:f00::ace:d00d/128", "2001:db8:f00::ace:d00d", true}, + {"2001:db8:f00::ace:d00d/128", "2001:db8:f00::ace:d00c", false}, + {"2001::/16", "2001::", true}, + {"2001::/16", "2001:db8:f00::ace:d00d", true}, + {"2001::/16", "2001:db8:f00::bad:d00d", true}, + {"2001::/16", "2001::abc", true}, + {"2001::/16", "2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff", true}, + {"2001::/16", "2000::", false}, + }; + + for (const auto& expectation : testExpectations) { + SCOPED_TRACE(expectation.asParameters()); + IPPrefix a = IPPrefix::forString(expectation.prefix); + IPAddress b = IPAddress::forString(expectation.address); + EXPECT_EQ(expectation.expected, a.contains(b)); + } +} + TEST(IPPrefixTest, GamutOfOperators) { const std::vector> kExpectations{ {EQ, IPPrefix(), IPPrefix()}, diff --git a/staticlibs/netd/libnetdutils/include/netdutils/InternetAddresses.h b/staticlibs/netd/libnetdutils/include/netdutils/InternetAddresses.h index d5cbe2b466..d10cec7d5d 100644 --- a/staticlibs/netd/libnetdutils/include/netdutils/InternetAddresses.h +++ b/staticlibs/netd/libnetdutils/include/netdutils/InternetAddresses.h @@ -221,6 +221,12 @@ class IPPrefix { in_addr addr4() const noexcept { return mData.ip.v4; } in6_addr addr6() const noexcept { return mData.ip.v6; } constexpr int length() const noexcept { return mData.cidrlen; } + bool contains(const IPPrefix& other) { + return length() <= other.length() && IPPrefix(other.ip(), length()).ip() == ip(); + } + bool contains(const IPAddress& other) { + return IPPrefix(other, length()).ip() == ip(); + } bool isUninitialized() const noexcept; std::string toString() const noexcept; From 22007784e2142c31bd86a342e61eecd699df7180 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 16 May 2022 10:43:20 +0800 Subject: [PATCH 436/777] Address comments at ag/18372083 This includes: 1. Fix synchronization error 2. Disallow 0 as maximum counter value 3. Fix comments Test: atest NetworkStaticLibTests:com.android.net.moduletests.util.PerUidCounterTest Test: atest ConnectivityCoverageTests:android.net.connectivity.com.android.net.module.util.PerUidCounterTest Bug: 229103088 Change-Id: I54c6017ffc62341d1a5da6591e5a045d687601d4 --- .../net/module/util/PerUidCounter.java | 20 ++++++++----------- .../net/module/util/PerUidCounterTest.kt | 9 ++------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/PerUidCounter.java b/staticlibs/framework/com/android/net/module/util/PerUidCounter.java index 7e0526d1f7..0b2de7a2a1 100644 --- a/staticlibs/framework/com/android/net/module/util/PerUidCounter.java +++ b/staticlibs/framework/com/android/net/module/util/PerUidCounter.java @@ -41,8 +41,8 @@ public class PerUidCounter { * @param maxCountPerUid the maximum count per uid allowed */ public PerUidCounter(final int maxCountPerUid) { - if (maxCountPerUid < 0) { - throw new IllegalArgumentException("Maximum counter value cannot be negative"); + if (maxCountPerUid <= 0) { + throw new IllegalArgumentException("Maximum counter value must be positive"); } mMaxCountPerUid = maxCountPerUid; } @@ -58,12 +58,10 @@ public class PerUidCounter { * @param uid the uid that the counter was made under */ public void incrementCountOrThrow(final int uid) { - synchronized (mUidToCount) { - incrementCountOrThrow(uid, 1 /* numToIncrement */); - } + incrementCountOrThrow(uid, 1 /* numToIncrement */); } - public void incrementCountOrThrow(final int uid, final int numToIncrement) { + public synchronized void incrementCountOrThrow(final int uid, final int numToIncrement) { if (numToIncrement <= 0) { throw new IllegalArgumentException("Increment count must be positive"); } @@ -71,8 +69,8 @@ public class PerUidCounter { if (newCount > mMaxCountPerUid) { throw new IllegalStateException("Uid " + uid + " exceeded its allowed limit"); } - // Since the count cannot be greater than Integer.MAX_VALUE here, - // it is safe to cast to int. + // Since the count cannot be greater than Integer.MAX_VALUE here since mMaxCountPerUid + // is an integer, it is safe to cast to int. mUidToCount.put(uid, (int) newCount); } @@ -86,12 +84,10 @@ public class PerUidCounter { * @param uid the uid that the count was made under */ public void decrementCountOrThrow(final int uid) { - synchronized (mUidToCount) { - decrementCountOrThrow(uid, 1 /* numToDecrement */); - } + decrementCountOrThrow(uid, 1 /* numToDecrement */); } - public void decrementCountOrThrow(final int uid, final int numToDecrement) { + public synchronized void decrementCountOrThrow(final int uid, final int numToDecrement) { if (numToDecrement <= 0) { throw new IllegalArgumentException("Decrement count must be positive"); } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt index c479d81bf6..0f2d52acac 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt @@ -33,13 +33,8 @@ class PerUidCounterTest { assertFailsWith { PerUidCounter(-1) } - - val uselessCounter = PerUidCounter(0) - assertFailsWith { - uselessCounter.incrementCountOrThrow(UID_A) - } - assertFailsWith { - uselessCounter.decrementCountOrThrow(UID_A) + assertFailsWith { + PerUidCounter(0) } val largeMaxCounter = PerUidCounter(Integer.MAX_VALUE) From 594000106c51eaa6ea7a017d63a86d34acc044a8 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 5 May 2022 18:14:57 +0800 Subject: [PATCH 437/777] Add PerUidCounter The class keeps track of the counters under different uid, fire exception if the counter exceeded the specified maximum value. This is reimplemented and generalized based on the one inside ConnectivityService. Test: atest NetworkStaticLibTests:com.android.net.moduletests.util.PerUidCounterTest Test: atest ConnectivityCoverageTests:android.net.connectivity.com.android.net.module.util.PerUidCounterTest Bug: 229103088 Change-Id: I7dfb16342e3ca4eab45bb40f2e1355981e04b44b (cherry picked from commit fe8cf1d1e9817afc804a05148dcb39f7ae24c360) Merged-In: I7dfb16342e3ca4eab45bb40f2e1355981e04b44b --- .../net/module/util/PerUidCounter.java | 107 ++++++++++++++++ .../net/module/util/PerUidCounterTest.kt | 114 ++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 staticlibs/framework/com/android/net/module/util/PerUidCounter.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt diff --git a/staticlibs/framework/com/android/net/module/util/PerUidCounter.java b/staticlibs/framework/com/android/net/module/util/PerUidCounter.java new file mode 100644 index 0000000000..7e0526d1f7 --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/PerUidCounter.java @@ -0,0 +1,107 @@ +/* + * 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 com.android.net.module.util; + +import android.util.SparseIntArray; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; + +/** + * Keeps track of the counters under different uid, fire exception if the counter + * exceeded the specified maximum value. + * + * @hide + */ +public class PerUidCounter { + private final int mMaxCountPerUid; + + // Map from UID to count that UID has filed. + @VisibleForTesting + @GuardedBy("mUidToCount") + final SparseIntArray mUidToCount = new SparseIntArray(); + + /** + * Constructor + * + * @param maxCountPerUid the maximum count per uid allowed + */ + public PerUidCounter(final int maxCountPerUid) { + if (maxCountPerUid < 0) { + throw new IllegalArgumentException("Maximum counter value cannot be negative"); + } + mMaxCountPerUid = maxCountPerUid; + } + + /** + * Increments the count of the given uid. Throws an exception if the number + * of the counter for the uid exceeds the value of maxCounterPerUid which is the value + * passed into the constructor. see: {@link #PerUidCounter(int)}. + * + * @throws IllegalStateException if the number of counter for the uid exceed + * the allowed number. + * + * @param uid the uid that the counter was made under + */ + public void incrementCountOrThrow(final int uid) { + synchronized (mUidToCount) { + incrementCountOrThrow(uid, 1 /* numToIncrement */); + } + } + + public void incrementCountOrThrow(final int uid, final int numToIncrement) { + if (numToIncrement <= 0) { + throw new IllegalArgumentException("Increment count must be positive"); + } + final long newCount = ((long) mUidToCount.get(uid, 0)) + numToIncrement; + if (newCount > mMaxCountPerUid) { + throw new IllegalStateException("Uid " + uid + " exceeded its allowed limit"); + } + // Since the count cannot be greater than Integer.MAX_VALUE here, + // it is safe to cast to int. + mUidToCount.put(uid, (int) newCount); + } + + /** + * Decrements the count of the given uid. Throws an exception if the number + * of the counter goes below zero. + * + * @throws IllegalStateException if the number of counter for the uid goes below + * zero. + * + * @param uid the uid that the count was made under + */ + public void decrementCountOrThrow(final int uid) { + synchronized (mUidToCount) { + decrementCountOrThrow(uid, 1 /* numToDecrement */); + } + } + + public void decrementCountOrThrow(final int uid, final int numToDecrement) { + if (numToDecrement <= 0) { + throw new IllegalArgumentException("Decrement count must be positive"); + } + final int newCount = mUidToCount.get(uid, 0) - numToDecrement; + if (newCount < 0) { + throw new IllegalStateException("BUG: too small count " + newCount + " for UID " + uid); + } else if (newCount == 0) { + mUidToCount.delete(uid); + } else { + mUidToCount.put(uid, newCount); + } + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt new file mode 100644 index 0000000000..c479d81bf6 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt @@ -0,0 +1,114 @@ +/* + * 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 com.android.net.module.util + +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.test.assertFailsWith + +@RunWith(AndroidJUnit4::class) +@SmallTest +class PerUidCounterTest { + private val UID_A = 1000 + private val UID_B = 1001 + + @Test + fun testCounterMaximum() { + assertFailsWith { + PerUidCounter(-1) + } + + val uselessCounter = PerUidCounter(0) + assertFailsWith { + uselessCounter.incrementCountOrThrow(UID_A) + } + assertFailsWith { + uselessCounter.decrementCountOrThrow(UID_A) + } + + val largeMaxCounter = PerUidCounter(Integer.MAX_VALUE) + largeMaxCounter.incrementCountOrThrow(UID_A, Integer.MAX_VALUE) + assertFailsWith { + largeMaxCounter.incrementCountOrThrow(UID_A) + } + } + + @Test + fun testIncrementCountOrThrow() { + val counter = PerUidCounter(3) + + // Verify the increment count cannot be zero. + assertFailsWith { + counter.incrementCountOrThrow(UID_A, 0) + } + + // Verify the counters work independently. + counter.incrementCountOrThrow(UID_A) + counter.incrementCountOrThrow(UID_B, 2) + counter.incrementCountOrThrow(UID_B) + counter.incrementCountOrThrow(UID_A) + counter.incrementCountOrThrow(UID_A) + assertFailsWith { + counter.incrementCountOrThrow(UID_A) + } + assertFailsWith { + counter.incrementCountOrThrow(UID_B) + } + + // Verify exception can be triggered again. + assertFailsWith { + counter.incrementCountOrThrow(UID_A) + } + assertFailsWith { + counter.incrementCountOrThrow(UID_A, 3) + } + } + + @Test + fun testDecrementCountOrThrow() { + val counter = PerUidCounter(3) + + // Verify the decrement count cannot be zero. + assertFailsWith { + counter.decrementCountOrThrow(UID_A, 0) + } + + // Verify the count cannot go below zero. + assertFailsWith { + counter.decrementCountOrThrow(UID_A) + } + assertFailsWith { + counter.decrementCountOrThrow(UID_A, 5) + } + assertFailsWith { + counter.decrementCountOrThrow(UID_A, Integer.MAX_VALUE) + } + + // Verify the counters work independently. + counter.incrementCountOrThrow(UID_A) + counter.incrementCountOrThrow(UID_B) + assertFailsWith { + counter.decrementCountOrThrow(UID_A, 3) + } + counter.decrementCountOrThrow(UID_A) + assertFailsWith { + counter.decrementCountOrThrow(UID_A) + } + } +} \ No newline at end of file From 2af1a7b846df1aa5e7e7a2b58be900eeb526387a Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 16 May 2022 10:43:20 +0800 Subject: [PATCH 438/777] Address comments at ag/18372083 This includes: 1. Fix synchronization error 2. Disallow 0 as maximum counter value 3. Fix comments Test: atest NetworkStaticLibTests:com.android.net.moduletests.util.PerUidCounterTest Test: atest ConnectivityCoverageTests:android.net.connectivity.com.android.net.module.util.PerUidCounterTest Bug: 229103088 Change-Id: I54c6017ffc62341d1a5da6591e5a045d687601d4 (cherry picked from commit 3103fb626a804c5d4a8ec15ac22a575bf7da314e) Merged-In: I54c6017ffc62341d1a5da6591e5a045d687601d4 --- .../net/module/util/PerUidCounter.java | 20 ++++++++----------- .../net/module/util/PerUidCounterTest.kt | 9 ++------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/PerUidCounter.java b/staticlibs/framework/com/android/net/module/util/PerUidCounter.java index 7e0526d1f7..0b2de7a2a1 100644 --- a/staticlibs/framework/com/android/net/module/util/PerUidCounter.java +++ b/staticlibs/framework/com/android/net/module/util/PerUidCounter.java @@ -41,8 +41,8 @@ public class PerUidCounter { * @param maxCountPerUid the maximum count per uid allowed */ public PerUidCounter(final int maxCountPerUid) { - if (maxCountPerUid < 0) { - throw new IllegalArgumentException("Maximum counter value cannot be negative"); + if (maxCountPerUid <= 0) { + throw new IllegalArgumentException("Maximum counter value must be positive"); } mMaxCountPerUid = maxCountPerUid; } @@ -58,12 +58,10 @@ public class PerUidCounter { * @param uid the uid that the counter was made under */ public void incrementCountOrThrow(final int uid) { - synchronized (mUidToCount) { - incrementCountOrThrow(uid, 1 /* numToIncrement */); - } + incrementCountOrThrow(uid, 1 /* numToIncrement */); } - public void incrementCountOrThrow(final int uid, final int numToIncrement) { + public synchronized void incrementCountOrThrow(final int uid, final int numToIncrement) { if (numToIncrement <= 0) { throw new IllegalArgumentException("Increment count must be positive"); } @@ -71,8 +69,8 @@ public class PerUidCounter { if (newCount > mMaxCountPerUid) { throw new IllegalStateException("Uid " + uid + " exceeded its allowed limit"); } - // Since the count cannot be greater than Integer.MAX_VALUE here, - // it is safe to cast to int. + // Since the count cannot be greater than Integer.MAX_VALUE here since mMaxCountPerUid + // is an integer, it is safe to cast to int. mUidToCount.put(uid, (int) newCount); } @@ -86,12 +84,10 @@ public class PerUidCounter { * @param uid the uid that the count was made under */ public void decrementCountOrThrow(final int uid) { - synchronized (mUidToCount) { - decrementCountOrThrow(uid, 1 /* numToDecrement */); - } + decrementCountOrThrow(uid, 1 /* numToDecrement */); } - public void decrementCountOrThrow(final int uid, final int numToDecrement) { + public synchronized void decrementCountOrThrow(final int uid, final int numToDecrement) { if (numToDecrement <= 0) { throw new IllegalArgumentException("Decrement count must be positive"); } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt index c479d81bf6..0f2d52acac 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt @@ -33,13 +33,8 @@ class PerUidCounterTest { assertFailsWith { PerUidCounter(-1) } - - val uselessCounter = PerUidCounter(0) - assertFailsWith { - uselessCounter.incrementCountOrThrow(UID_A) - } - assertFailsWith { - uselessCounter.decrementCountOrThrow(UID_A) + assertFailsWith { + PerUidCounter(0) } val largeMaxCounter = PerUidCounter(Integer.MAX_VALUE) From 8ffa79ce34958ec99318200a31b6f4f2daf2c4ec Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Sat, 14 May 2022 21:38:26 +0800 Subject: [PATCH 439/777] PacketBuilder: add IPv6 support Support IPv6 packet builder and verify with UDP packet unit test. Bug: 215655463 Test: atest NetworkStaticLibTests Change-Id: I5edf0ffbc9b37ecf0e0a6da0dc7d04716fc4c38c --- .../net/module/util/PacketBuilder.java | 89 +++-- .../net/module/util/PacketBuilderTest.java | 336 +++++++++++++++--- 2 files changed, 357 insertions(+), 68 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/PacketBuilder.java b/staticlibs/device/com/android/net/module/util/PacketBuilder.java index c9085289e8..8acb2965f8 100644 --- a/staticlibs/device/com/android/net/module/util/PacketBuilder.java +++ b/staticlibs/device/com/android/net/module/util/PacketBuilder.java @@ -17,6 +17,7 @@ package com.android.net.module.util; import static android.system.OsConstants.IPPROTO_IP; +import static android.system.OsConstants.IPPROTO_IPV6; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; @@ -25,6 +26,7 @@ import static com.android.net.module.util.IpUtils.tcpChecksum; import static com.android.net.module.util.IpUtils.udpChecksum; import static com.android.net.module.util.NetworkStackConstants.IPV4_CHECKSUM_OFFSET; import static com.android.net.module.util.NetworkStackConstants.IPV4_LENGTH_OFFSET; +import static com.android.net.module.util.NetworkStackConstants.IPV6_LEN_OFFSET; import static com.android.net.module.util.NetworkStackConstants.TCP_CHECKSUM_OFFSET; import static com.android.net.module.util.NetworkStackConstants.UDP_CHECKSUM_OFFSET; import static com.android.net.module.util.NetworkStackConstants.UDP_LENGTH_OFFSET; @@ -35,11 +37,13 @@ import androidx.annotation.NonNull; import com.android.net.module.util.structs.EthernetHeader; import com.android.net.module.util.structs.Ipv4Header; +import com.android.net.module.util.structs.Ipv6Header; import com.android.net.module.util.structs.TcpHeader; import com.android.net.module.util.structs.UdpHeader; import java.io.IOException; import java.net.Inet4Address; +import java.net.Inet6Address; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; @@ -49,7 +53,7 @@ import java.nio.ByteBuffer; * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Layer 2 header (EthernetHeader) | (optional) * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Layer 3 header (Ipv4Header) | + * | Layer 3 header (Ipv4Header, Ipv6Header) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Layer 4 header (TcpHeader, UdpHeader) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -74,11 +78,14 @@ import java.nio.ByteBuffer; * sendPacket(buf); */ public class PacketBuilder { + private static final int INVALID_OFFSET = -1; + private final ByteBuffer mBuffer; - private int mIpv4HeaderOffset = -1; - private int mTcpHeaderOffset = -1; - private int mUdpHeaderOffset = -1; + private int mIpv4HeaderOffset = INVALID_OFFSET; + private int mIpv6HeaderOffset = INVALID_OFFSET; + private int mTcpHeaderOffset = INVALID_OFFSET; + private int mUdpHeaderOffset = INVALID_OFFSET; public PacketBuilder(@NonNull ByteBuffer buffer) { mBuffer = buffer; @@ -129,6 +136,31 @@ public class PacketBuilder { } } + /** + * Write an IPv6 header. + * The IP header length is calculated and written back in #finalizePacket. + * + * @param vtf version, traffic class and flow label + * @param nextHeader the transport layer protocol + * @param hopLimit hop limit + * @param srcIp source IP address + * @param dstIp destination IP address + */ + public void writeIpv6Header(int vtf, byte nextHeader, short hopLimit, + @NonNull final Inet6Address srcIp, @NonNull final Inet6Address dstIp) + throws IOException { + mIpv6HeaderOffset = mBuffer.position(); + final Ipv6Header ipv6Header = new Ipv6Header(vtf, + (short) 0 /* payloadLength, calculate in #finalizePacket */, nextHeader, + hopLimit, srcIp, dstIp); + + try { + ipv6Header.writeToByteBuffer(mBuffer); + } catch (IllegalArgumentException | BufferOverflowException e) { + throw new IOException("Error writing to buffer: ", e); + } + } + /** * Write a TCP header. * The TCP header checksum is calculated and written back in #finalizePacket. @@ -186,32 +218,42 @@ public class PacketBuilder { */ @NonNull public ByteBuffer finalizePacket() throws IOException { - if (mIpv4HeaderOffset < 0) { - // TODO: add support for IPv6 - throw new IOException("Packet is missing IPv4 header"); + // Finalize IPv4 or IPv6 header. + int ipHeaderOffset = INVALID_OFFSET; + if (mIpv4HeaderOffset != INVALID_OFFSET) { + ipHeaderOffset = mIpv4HeaderOffset; + + // Populate the IPv4 totalLength field. + mBuffer.putShort(mIpv4HeaderOffset + IPV4_LENGTH_OFFSET, + (short) (mBuffer.position() - mIpv4HeaderOffset)); + + // Populate the IPv4 header checksum field. + mBuffer.putShort(mIpv4HeaderOffset + IPV4_CHECKSUM_OFFSET, + ipChecksum(mBuffer, mIpv4HeaderOffset /* headerOffset */)); + } else if (mIpv6HeaderOffset != INVALID_OFFSET) { + ipHeaderOffset = mIpv6HeaderOffset; + + // Populate the IPv6 payloadLength field. + mBuffer.putShort(mIpv6HeaderOffset + IPV6_LEN_OFFSET, + (short) (mBuffer.position() - mIpv6HeaderOffset)); + } else { + throw new IOException("Packet is missing neither IPv4 nor IPv6 header"); } - // Populate the IPv4 totalLength field. - mBuffer.putShort(mIpv4HeaderOffset + IPV4_LENGTH_OFFSET, - (short) (mBuffer.position() - mIpv4HeaderOffset)); - - // Populate the IPv4 header checksum field. - mBuffer.putShort(mIpv4HeaderOffset + IPV4_CHECKSUM_OFFSET, - ipChecksum(mBuffer, mIpv4HeaderOffset /* headerOffset */)); - - if (mTcpHeaderOffset > 0) { + // Finalize TCP or UDP header. + if (mTcpHeaderOffset != INVALID_OFFSET) { // Populate the TCP header checksum field. mBuffer.putShort(mTcpHeaderOffset + TCP_CHECKSUM_OFFSET, tcpChecksum(mBuffer, - mIpv4HeaderOffset /* ipOffset */, mTcpHeaderOffset /* transportOffset */, + ipHeaderOffset /* ipOffset */, mTcpHeaderOffset /* transportOffset */, mBuffer.position() - mTcpHeaderOffset /* transportLen */)); - } else if (mUdpHeaderOffset > 0) { + } else if (mUdpHeaderOffset != INVALID_OFFSET) { // Populate the UDP header length field. mBuffer.putShort(mUdpHeaderOffset + UDP_LENGTH_OFFSET, (short) (mBuffer.position() - mUdpHeaderOffset)); // Populate the UDP header checksum field. mBuffer.putShort(mUdpHeaderOffset + UDP_CHECKSUM_OFFSET, udpChecksum(mBuffer, - mIpv4HeaderOffset /* ipOffset */, mUdpHeaderOffset /* transportOffset */)); + ipHeaderOffset /* ipOffset */, mUdpHeaderOffset /* transportOffset */)); } else { throw new IOException("Packet is missing neither TCP nor UDP header"); } @@ -225,15 +267,15 @@ public class PacketBuilder { * * @param hasEther has ethernet header. Set this flag to indicate that the packet has an * ethernet header. - * @param l3proto the layer 3 protocol. Only {@code IPPROTO_IP} currently supported. + * @param l3proto the layer 3 protocol. Only {@code IPPROTO_IP} and {@code IPPROTO_IPV6} + * currently supported. * @param l4proto the layer 4 protocol. Only {@code IPPROTO_TCP} and {@code IPPROTO_UDP} * currently supported. * @param payloadLen length of the payload. */ @NonNull public static ByteBuffer allocate(boolean hasEther, int l3proto, int l4proto, int payloadLen) { - if (l3proto != IPPROTO_IP) { - // TODO: add support for IPv6 + if (l3proto != IPPROTO_IP && l3proto != IPPROTO_IPV6) { throw new IllegalArgumentException("Unsupported layer 3 protocol " + l3proto); } @@ -247,7 +289,8 @@ public class PacketBuilder { int packetLen = 0; if (hasEther) packetLen += Struct.getSize(EthernetHeader.class); - packetLen += Struct.getSize(Ipv4Header.class); + packetLen += (l3proto == IPPROTO_IP) ? Struct.getSize(Ipv4Header.class) + : Struct.getSize(Ipv6Header.class); packetLen += (l4proto == IPPROTO_TCP) ? Struct.getSize(TcpHeader.class) : Struct.getSize(UdpHeader.class); packetLen += payloadLen; diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java index 8f9a1f996e..c02763a07d 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java @@ -17,11 +17,14 @@ package com.android.net.module.util; import static android.system.OsConstants.IPPROTO_IP; +import static android.system.OsConstants.IPPROTO_IPV6; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV4; +import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6; import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN; +import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN; import static com.android.net.module.util.NetworkStackConstants.TCPHDR_ACK; import static com.android.net.module.util.NetworkStackConstants.TCP_HEADER_MIN_LEN; import static com.android.net.module.util.NetworkStackConstants.UDP_HEADER_LEN; @@ -41,6 +44,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.net.module.util.structs.EthernetHeader; import com.android.net.module.util.structs.Ipv4Header; +import com.android.net.module.util.structs.Ipv6Header; import com.android.net.module.util.structs.TcpHeader; import com.android.net.module.util.structs.UdpHeader; @@ -49,6 +53,7 @@ import org.junit.runner.RunWith; import java.io.IOException; import java.net.Inet4Address; +import java.net.Inet6Address; import java.nio.ByteBuffer; @RunWith(AndroidJUnit4.class) @@ -56,8 +61,10 @@ import java.nio.ByteBuffer; public class PacketBuilderTest { private static final MacAddress SRC_MAC = MacAddress.fromString("11:22:33:44:55:66"); private static final MacAddress DST_MAC = MacAddress.fromString("aa:bb:cc:dd:ee:ff"); - private static final Inet4Address IPV4_SRC_ADDR = addr("192.0.2.1"); - private static final Inet4Address IPV4_DST_ADDR = addr("198.51.100.1"); + private static final Inet4Address IPV4_SRC_ADDR = addr4("192.0.2.1"); + private static final Inet4Address IPV4_DST_ADDR = addr4("198.51.100.1"); + private static final Inet6Address IPV6_SRC_ADDR = addr6("2001:db8::1"); + private static final Inet6Address IPV6_DST_ADDR = addr6("2001:db8::2"); private static final short SRC_PORT = 9876; private static final short DST_PORT = 433; private static final short SEQ_NO = 13579; @@ -68,6 +75,9 @@ public class PacketBuilderTest { private static final byte TIME_TO_LIVE = (byte) 0x40; private static final short WINDOW = (short) 0x2000; private static final short URGENT_POINTER = 0; + // version=6, traffic class=0x80, flowlabel=0x515ca; + private static final int VERSION_TRAFFICCLASS_FLOWLABEL = 0x680515ca; + private static final short HOP_LIMIT = 0x40; private static final ByteBuffer DATA = ByteBuffer.wrap(new byte[] { (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef }); @@ -256,15 +266,123 @@ public class PacketBuilderTest { (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef }; + private static final byte[] TEST_PACKET_ETHERHDR_IPV6HDR_UDPHDR = + new byte[] { + // packet = (scapy.Ether(src="11:22:33:44:55:66", dst="aa:bb:cc:dd:ee:ff", + // type='IPv6') / + // scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, + // fl=0x515ca, plen=48, hlim=0x40) / + // scapy.UDP(sport=9876, dport=433)) + // Note that plen(48) = ipv6hdr(40) + udphdr(8). + // Ether header + (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, + (byte) 0xee, (byte) 0xff, (byte) 0x11, (byte) 0x22, + (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66, + (byte) 0x86, (byte) 0xdd, + // IP header + (byte) 0x68, (byte) 0x05, (byte) 0x15, (byte) 0xca, + (byte) 0x00, (byte) 0x30, (byte) 0x11, (byte) 0x40, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, + // UDP header + (byte) 0x26, (byte) 0x94, (byte) 0x01, (byte) 0xb1, + (byte) 0x00, (byte) 0x08, (byte) 0x7c, (byte) 0x24 + }; + + private static final byte[] TEST_PACKET_ETHERHDR_IPV6HDR_UDPHDR_DATA = + new byte[] { + // packet = (scapy.Ether(src="11:22:33:44:55:66", dst="aa:bb:cc:dd:ee:ff", + // type='IPv6') / + // scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, + // fl=0x515ca, plen=52, hlim=0x40) / + // scapy.UDP(sport=9876, dport=433) / + // b'\xde\xad\xbe\xef') + // Note that plen(52) = ipv6hdr(40) + udphdr(8) + data(4). + // Ether header + (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, + (byte) 0xee, (byte) 0xff, (byte) 0x11, (byte) 0x22, + (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66, + (byte) 0x86, (byte) 0xdd, + // IP header + (byte) 0x68, (byte) 0x05, (byte) 0x15, (byte) 0xca, + (byte) 0x00, (byte) 0x34, (byte) 0x11, (byte) 0x40, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, + // UDP header + (byte) 0x26, (byte) 0x94, (byte) 0x01, (byte) 0xb1, + (byte) 0x00, (byte) 0x0c, (byte) 0xde, (byte) 0x7e, + // Data + (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef + }; + + private static final byte[] TEST_PACKET_IPV6HDR_UDPHDR = + new byte[] { + // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, + // fl=0x515ca, plen=48, hlim=0x40) / + // scapy.UDP(sport=9876, dport=433)) + // Note that plen(48) = ipv6hdr(40) + udphdr(8). + // IP header + (byte) 0x68, (byte) 0x05, (byte) 0x15, (byte) 0xca, + (byte) 0x00, (byte) 0x30, (byte) 0x11, (byte) 0x40, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, + // UDP header + (byte) 0x26, (byte) 0x94, (byte) 0x01, (byte) 0xb1, + (byte) 0x00, (byte) 0x08, (byte) 0x7c, (byte) 0x24 + }; + + private static final byte[] TEST_PACKET_IPV6HDR_UDPHDR_DATA = + new byte[] { + // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, + // fl=0x515ca, plen=52, hlim=0x40) / + // scapy.UDP(sport=9876, dport=433) / + // b'\xde\xad\xbe\xef') + // Note that plen(52) = ipv6hdr(40) + udphdr(8) + data(4). + // IP header + (byte) 0x68, (byte) 0x05, (byte) 0x15, (byte) 0xca, + (byte) 0x00, (byte) 0x34, (byte) 0x11, (byte) 0x40, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, + // UDP header + (byte) 0x26, (byte) 0x94, (byte) 0x01, (byte) 0xb1, + (byte) 0x00, (byte) 0x0c, (byte) 0xde, (byte) 0x7e, + // Data + (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef + }; + /** - * Build an IPv4 packet which has ether header, IPv4 header, TCP/UDP header and data. + * Build a packet which has ether header, IP header, TCP/UDP header and data. * The ethernet header and data are optional. Note that both source mac address and * destination mac address are required for ethernet header. * * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Layer 2 header (EthernetHeader) | (optional) * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Layer 3 header (Ipv4Header) | + * | Layer 3 header (Ipv4Header, Ipv6Header) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Layer 4 header (TcpHeader, UdpHeader) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -273,33 +391,55 @@ public class PacketBuilderTest { * * @param srcMac source MAC address. used by L2 ether header. * @param dstMac destination MAC address. used by L2 ether header. - * @param l4proto the layer 4 protocol. support either IPPROTO_TCP or IPPROTO_UDP. + * @param l3proto the layer 3 protocol. Only {@code IPPROTO_IP} and {@code IPPROTO_IPV6} + * currently supported. + * @param l4proto the layer 4 protocol. Only {@code IPPROTO_TCP} and {@code IPPROTO_UDP} + * currently supported. * @param payload the payload. */ @NonNull - private ByteBuffer buildIpv4Packet(@Nullable final MacAddress srcMac, - @Nullable final MacAddress dstMac, final int l4proto, + private ByteBuffer buildPacket(@Nullable final MacAddress srcMac, + @Nullable final MacAddress dstMac, final int l3proto, final int l4proto, @Nullable final ByteBuffer payload) throws Exception { + if (l3proto != IPPROTO_IP && l3proto != IPPROTO_IPV6) { + fail("Unsupported layer 3 protocol " + l3proto); + } + if (l4proto != IPPROTO_TCP && l4proto != IPPROTO_UDP) { fail("Unsupported layer 4 protocol " + l4proto); } final boolean hasEther = (srcMac != null && dstMac != null); final int payloadLen = (payload == null) ? 0 : payload.limit(); - final ByteBuffer buffer = PacketBuilder.allocate(hasEther, IPPROTO_IP, l4proto, + final ByteBuffer buffer = PacketBuilder.allocate(hasEther, l3proto, l4proto, payloadLen); final PacketBuilder packetBuilder = new PacketBuilder(buffer); - if (hasEther) packetBuilder.writeL2Header(srcMac, dstMac, (short) ETHER_TYPE_IPV4); - packetBuilder.writeIpv4Header(TYPE_OF_SERVICE, ID, FLAGS_AND_FRAGMENT_OFFSET, - TIME_TO_LIVE, (byte) l4proto, IPV4_SRC_ADDR, IPV4_DST_ADDR); + // [1] Build ether header. + if (hasEther) { + final int etherType = (l3proto == IPPROTO_IP) ? ETHER_TYPE_IPV4 : ETHER_TYPE_IPV6; + packetBuilder.writeL2Header(srcMac, dstMac, (short) etherType); + } + + // [2] Build IP header. + if (l3proto == IPPROTO_IP) { + packetBuilder.writeIpv4Header(TYPE_OF_SERVICE, ID, FLAGS_AND_FRAGMENT_OFFSET, + TIME_TO_LIVE, (byte) l4proto, IPV4_SRC_ADDR, IPV4_DST_ADDR); + } else if (l3proto == IPPROTO_IPV6) { + packetBuilder.writeIpv6Header(VERSION_TRAFFICCLASS_FLOWLABEL, + (byte) l4proto, HOP_LIMIT, IPV6_SRC_ADDR, IPV6_DST_ADDR); + } + + // [3] Build TCP or UDP header. if (l4proto == IPPROTO_TCP) { packetBuilder.writeTcpHeader(SRC_PORT, DST_PORT, SEQ_NO, ACK_NO, TCPHDR_ACK, WINDOW, URGENT_POINTER); } else if (l4proto == IPPROTO_UDP) { packetBuilder.writeUdpHeader(SRC_PORT, DST_PORT); } + + // [4] Build payload. if (payload != null) { buffer.put(payload); // in case data might be reused by caller, restore the position and @@ -313,19 +453,27 @@ public class PacketBuilderTest { /** * Check ethernet header. * + * @param l3proto the layer 3 protocol. Only {@code IPPROTO_IP} and {@code IPPROTO_IPV6} + * currently supported. * @param actual the packet to check. */ - private void checkEtherHeader(final ByteBuffer actual) { + private void checkEtherHeader(final int l3proto, final ByteBuffer actual) { + if (l3proto != IPPROTO_IP && l3proto != IPPROTO_IPV6) { + fail("Unsupported layer 3 protocol " + l3proto); + } + final EthernetHeader eth = Struct.parse(EthernetHeader.class, actual); assertEquals(SRC_MAC, eth.srcMac); assertEquals(DST_MAC, eth.dstMac); - assertEquals(ETHER_TYPE_IPV4, eth.etherType); + final int expectedEtherType = (l3proto == IPPROTO_IP) ? ETHER_TYPE_IPV4 : ETHER_TYPE_IPV6; + assertEquals(expectedEtherType, eth.etherType); } /** * Check IPv4 header. * - * @param l4proto the layer 4 protocol. support either IPPROTO_TCP or IPPROTO_UDP. + * @param l4proto the layer 4 protocol. Only {@code IPPROTO_TCP} and {@code IPPROTO_UDP} + * currently supported. * @param hasData true if the packet has data payload; false otherwise. * @param actual the packet to check. */ @@ -359,16 +507,57 @@ public class PacketBuilderTest { } /** - * Check TCPv4 packet. + * Check IPv6 header. * - * @param hasEther true if the packet has ether header; false otherwise. + * @param l4proto the layer 4 protocol. Only {@code IPPROTO_TCP} and {@code IPPROTO_UDP} + * currently supported. * @param hasData true if the packet has data payload; false otherwise. * @param actual the packet to check. */ - private void checkTcpv4Packet(final boolean hasEther, final boolean hasData, + private void checkIpv6Header(final int l4proto, final boolean hasData, final ByteBuffer actual) { + if (l4proto != IPPROTO_TCP && l4proto != IPPROTO_UDP) { + fail("Unsupported layer 4 protocol " + l4proto); + } + + final Ipv6Header ipv6Header = Struct.parse(Ipv6Header.class, actual); + + assertEquals(VERSION_TRAFFICCLASS_FLOWLABEL, ipv6Header.vtf); + assertEquals(HOP_LIMIT, ipv6Header.hopLimit); + assertEquals(IPV6_SRC_ADDR, ipv6Header.srcIp); + assertEquals(IPV6_DST_ADDR, ipv6Header.dstIp); + + final int dataLength = hasData ? DATA.limit() : 0; + if (l4proto == IPPROTO_TCP) { + assertEquals(IPV6_HEADER_LEN + TCP_HEADER_MIN_LEN + dataLength, + ipv6Header.payloadLength); + assertEquals((byte) IPPROTO_TCP, ipv6Header.nextHeader); + } else if (l4proto == IPPROTO_UDP) { + assertEquals(IPV6_HEADER_LEN + UDP_HEADER_LEN + dataLength, + ipv6Header.payloadLength); + assertEquals((byte) IPPROTO_UDP, ipv6Header.nextHeader); + } + } + + /** + * Check TCPv4 packet. + * + * @param hasEther true if the packet has ether header; false otherwise. + * @param l3proto the layer 3 protocol. Only {@code IPPROTO_IP} and {@code IPPROTO_IPV6} + * currently supported. + * @param hasData true if the packet has data payload; false otherwise. + * @param actual the packet to check. + * + * TODO: support IPv6 + */ + private void checkTcpv4Packet(final boolean hasEther, final int l3proto, final boolean hasData, + final ByteBuffer actual) { + if (l3proto != IPPROTO_IP && l3proto != IPPROTO_IPV6) { + fail("Unsupported layer 3 protocol " + l3proto); + } + if (hasEther) { - checkEtherHeader(actual); + checkEtherHeader(l3proto, actual); } checkIpv4Header(IPPROTO_TCP, hasData, actual); @@ -389,26 +578,45 @@ public class PacketBuilderTest { } /** - * Check UDPv4 packet. + * Check UDP packet. * * @param hasEther true if the packet has ether header; false otherwise. + * @param l3proto the layer 3 protocol. Only {@code IPPROTO_IP} and {@code IPPROTO_IPV6} + * currently supported. * @param hasData true if the packet has data payload; false otherwise. * @param actual the packet to check. */ - private void checkUdpv4Packet(final boolean hasEther, final boolean hasData, + private void checkUdpPacket(final boolean hasEther, final int l3proto, final boolean hasData, final ByteBuffer actual) { - if (hasEther) { - checkEtherHeader(actual); + if (l3proto != IPPROTO_IP && l3proto != IPPROTO_IPV6) { + fail("Unsupported layer 3 protocol " + l3proto); } - checkIpv4Header(IPPROTO_UDP, hasData, actual); + // [1] Check ether header. + if (hasEther) { + checkEtherHeader(l3proto, actual); + } + + // [2] Check IP header. + if (l3proto == IPPROTO_IP) { + checkIpv4Header(IPPROTO_UDP, hasData, actual); + } else if (l3proto == IPPROTO_IPV6) { + checkIpv6Header(IPPROTO_UDP, hasData, actual); + } + + // [3] Check UDP header. final UdpHeader udpHeader = Struct.parse(UdpHeader.class, actual); assertEquals(SRC_PORT, udpHeader.srcPort); assertEquals(DST_PORT, udpHeader.dstPort); final int dataLength = hasData ? DATA.limit() : 0; assertEquals(UDP_HEADER_LEN + dataLength, udpHeader.length); - assertEquals(hasData ? (short) 0x4dbd : (short) 0xeb62, udpHeader.checksum); + if (l3proto == IPPROTO_IP) { + assertEquals(hasData ? (short) 0x4dbd : (short) 0xeb62, udpHeader.checksum); + } else if (l3proto == IPPROTO_IPV6) { + assertEquals(hasData ? (short) 0xde7e : (short) 0x7c24, udpHeader.checksum); + } + // [4] Check payload. if (hasData) { assertEquals(0xdeadbeef, actual.getInt()); } @@ -416,65 +624,99 @@ public class PacketBuilderTest { @Test public void testBuildPacketEtherIPv4Tcp() throws Exception { - final ByteBuffer packet = buildIpv4Packet(SRC_MAC, DST_MAC, IPPROTO_TCP, null /* data */); - checkTcpv4Packet(true /* hasEther */, false /* hasData */, packet); + final ByteBuffer packet = buildPacket(SRC_MAC, DST_MAC, IPPROTO_IP, IPPROTO_TCP, + null /* data */); + checkTcpv4Packet(true /* hasEther */, IPPROTO_IP, false /* hasData */, packet); assertArrayEquals(TEST_PACKET_ETHERHDR_IPV4HDR_TCPHDR, packet.array()); } @Test public void testBuildPacketEtherIPv4TcpData() throws Exception { - final ByteBuffer packet = buildIpv4Packet(SRC_MAC, DST_MAC, IPPROTO_TCP, DATA); - checkTcpv4Packet(true /* hasEther */, true /* hasData */, packet); + final ByteBuffer packet = buildPacket(SRC_MAC, DST_MAC, IPPROTO_IP, IPPROTO_TCP, DATA); + checkTcpv4Packet(true /* hasEther */, IPPROTO_IP, true /* hasData */, packet); assertArrayEquals(TEST_PACKET_ETHERHDR_IPV4HDR_TCPHDR_DATA, packet.array()); } @Test public void testBuildPacketIPv4Tcp() throws Exception { - final ByteBuffer packet = buildIpv4Packet(null /* srcMac */, null /* dstMac */, - IPPROTO_TCP, null /* data */); - checkTcpv4Packet(false /* hasEther */, false /* hasData */, packet); + final ByteBuffer packet = buildPacket(null /* srcMac */, null /* dstMac */, + IPPROTO_IP, IPPROTO_TCP, null /* data */); + checkTcpv4Packet(false /* hasEther */, IPPROTO_IP, false /* hasData */, packet); assertArrayEquals(TEST_PACKET_IPV4HDR_TCPHDR, packet.array()); } @Test public void testBuildPacketIPv4TcpData() throws Exception { - final ByteBuffer packet = buildIpv4Packet(null /* srcMac */, null /* dstMac */, - IPPROTO_TCP, DATA); - checkTcpv4Packet(false /* hasEther */, true /* hasData */, packet); + final ByteBuffer packet = buildPacket(null /* srcMac */, null /* dstMac */, + IPPROTO_IP, IPPROTO_TCP, DATA); + checkTcpv4Packet(false /* hasEther */, IPPROTO_IP, true /* hasData */, packet); assertArrayEquals(TEST_PACKET_IPV4HDR_TCPHDR_DATA, packet.array()); } @Test public void testBuildPacketEtherIPv4Udp() throws Exception { - final ByteBuffer packet = buildIpv4Packet(SRC_MAC, DST_MAC, IPPROTO_UDP, null /* data */); - checkUdpv4Packet(true /* hasEther */, false /* hasData */, packet); + final ByteBuffer packet = buildPacket(SRC_MAC, DST_MAC, IPPROTO_IP, IPPROTO_UDP, + null /* data */); + checkUdpPacket(true /* hasEther */, IPPROTO_IP, false /* hasData */, packet); assertArrayEquals(TEST_PACKET_ETHERHDR_IPV4HDR_UDPHDR, packet.array()); } @Test public void testBuildPacketEtherIPv4UdpData() throws Exception { - final ByteBuffer packet = buildIpv4Packet(SRC_MAC, DST_MAC, IPPROTO_UDP, DATA); - checkUdpv4Packet(true /* hasEther */, true /* hasData */, packet); + final ByteBuffer packet = buildPacket(SRC_MAC, DST_MAC, IPPROTO_IP, IPPROTO_UDP, DATA); + checkUdpPacket(true /* hasEther */, IPPROTO_IP, true /* hasData */, packet); assertArrayEquals(TEST_PACKET_ETHERHDR_IPV4HDR_UDPHDR_DATA, packet.array()); } @Test public void testBuildPacketIPv4Udp() throws Exception { - final ByteBuffer packet = buildIpv4Packet(null /* srcMac */, null /* dstMac */, - IPPROTO_UDP, null /*data*/); - checkUdpv4Packet(false /* hasEther */, false /* hasData */, packet); + final ByteBuffer packet = buildPacket(null /* srcMac */, null /* dstMac */, + IPPROTO_IP, IPPROTO_UDP, null /*data*/); + checkUdpPacket(false /* hasEther */, IPPROTO_IP, false /* hasData */, packet); assertArrayEquals(TEST_PACKET_IPV4HDR_UDPHDR, packet.array()); } @Test public void testBuildPacketIPv4UdpData() throws Exception { - final ByteBuffer packet = buildIpv4Packet(null /* srcMac */, null /* dstMac */, - IPPROTO_UDP, DATA); - checkUdpv4Packet(false /* hasEther */, true /* hasData */, packet); + final ByteBuffer packet = buildPacket(null /* srcMac */, null /* dstMac */, + IPPROTO_IP, IPPROTO_UDP, DATA); + checkUdpPacket(false /* hasEther */, IPPROTO_IP, true /* hasData */, packet); assertArrayEquals(TEST_PACKET_IPV4HDR_UDPHDR_DATA, packet.array()); } + @Test + public void testBuildPacketEtherIPv6Udp() throws Exception { + final ByteBuffer packet = buildPacket(SRC_MAC, DST_MAC, IPPROTO_IPV6, IPPROTO_UDP, + null /* data */); + checkUdpPacket(true /* hasEther */, IPPROTO_IPV6, false /* hasData */, packet); + assertArrayEquals(TEST_PACKET_ETHERHDR_IPV6HDR_UDPHDR, packet.array()); + } + + @Test + public void testBuildPacketEtherIPv6UdpData() throws Exception { + final ByteBuffer packet = buildPacket(SRC_MAC, DST_MAC, IPPROTO_IPV6, IPPROTO_UDP, + DATA); + checkUdpPacket(true /* hasEther */, IPPROTO_IPV6, true /* hasData */, packet); + assertArrayEquals(TEST_PACKET_ETHERHDR_IPV6HDR_UDPHDR_DATA, packet.array()); + } + + @Test + public void testBuildPacketIPv6Udp() throws Exception { + final ByteBuffer packet = buildPacket(null /* srcMac */, null /* dstMac */, + IPPROTO_IPV6, IPPROTO_UDP, null /*data*/); + checkUdpPacket(false /* hasEther */, IPPROTO_IPV6, false /* hasData */, packet); + assertArrayEquals(TEST_PACKET_IPV6HDR_UDPHDR, packet.array()); + } + + @Test + public void testBuildPacketIPv6UdpData() throws Exception { + final ByteBuffer packet = buildPacket(null /* srcMac */, null /* dstMac */, + IPPROTO_IPV6, IPPROTO_UDP, DATA); + checkUdpPacket(false /* hasEther */, IPPROTO_IPV6, true /* hasData */, packet); + assertArrayEquals(TEST_PACKET_IPV6HDR_UDPHDR_DATA, packet.array()); + } + @Test public void testFinalizePacketWithoutIpv4Header() throws Exception { final ByteBuffer buffer = PacketBuilder.allocate(false /* hasEther */, IPPROTO_IP, @@ -526,7 +768,11 @@ public class PacketBuilderTest { assertThrows(IOException.class, () -> packetBuilder.writeUdpHeader(SRC_PORT, DST_PORT)); } - private static Inet4Address addr(String addr) { + private static Inet4Address addr4(String addr) { return (Inet4Address) InetAddresses.parseNumericAddress(addr); } + + private static Inet6Address addr6(String addr) { + return (Inet6Address) InetAddresses.parseNumericAddress(addr); + } } From 3288afaede471324eb79cb87831eb21f8bd9e174 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Tue, 17 May 2022 22:31:06 +0800 Subject: [PATCH 440/777] PacketBuilderTest: add IPv6 TCP test Bug: 215655463 Test: atest NetworkStaticLibTests Change-Id: I62771a8f2549c7785919504f4816a28f30551953 --- .../net/module/util/PacketBuilderTest.java | 188 +++++++++++++++++- 1 file changed, 178 insertions(+), 10 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java index c02763a07d..1a0752a022 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java @@ -327,6 +327,130 @@ public class PacketBuilderTest { (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef }; + private static final byte[] TEST_PACKET_ETHERHDR_IPV6HDR_TCPHDR_DATA = + new byte[] { + // packet = (scapy.Ether(src="11:22:33:44:55:66", dst="aa:bb:cc:dd:ee:ff", + // type='IPv6') / + // scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, + // fl=0x515ca, plen=64, hlim=0x40) / + // scapy.TCP(sport=9876, dport=433, seq=13579, ack=24680, + // flags='A', window=8192, urgptr=0) / + // b'\xde\xad\xbe\xef') + // Note that plen(64) = ipv6hdr(40) + udphdr(20) + data(4). + // Ether header + (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, + (byte) 0xee, (byte) 0xff, (byte) 0x11, (byte) 0x22, + (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66, + (byte) 0x86, (byte) 0xdd, + // IPv6 header + (byte) 0x68, (byte) 0x05, (byte) 0x15, (byte) 0xca, + (byte) 0x00, (byte) 0x40, (byte) 0x06, (byte) 0x40, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, + // TCP header + (byte) 0x26, (byte) 0x94, (byte) 0x01, (byte) 0xb1, + (byte) 0x00, (byte) 0x00, (byte) 0x35, (byte) 0x0b, + (byte) 0x00, (byte) 0x00, (byte) 0x60, (byte) 0x68, + (byte) 0x50, (byte) 0x10, (byte) 0x20, (byte) 0x00, + (byte) 0xd9, (byte) 0x05, (byte) 0x00, (byte) 0x00, + // Data + (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef + }; + + private static final byte[] TEST_PACKET_ETHERHDR_IPV6HDR_TCPHDR = + new byte[] { + // packet = (scapy.Ether(src="11:22:33:44:55:66", dst="aa:bb:cc:dd:ee:ff", + // type='IPv6') / + // scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, + // fl=0x515ca, plen=60, hlim=0x40) / + // scapy.TCP(sport=9876, dport=433, seq=13579, ack=24680, + // flags='A', window=8192, urgptr=0)) + // Note that plen(60) = ipv6hdr(40) + udphdr(20). + // Ether header + (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, + (byte) 0xee, (byte) 0xff, (byte) 0x11, (byte) 0x22, + (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66, + (byte) 0x86, (byte) 0xdd, + // IPv6 header + (byte) 0x68, (byte) 0x05, (byte) 0x15, (byte) 0xca, + (byte) 0x00, (byte) 0x3c, (byte) 0x06, (byte) 0x40, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, + // TCP header + (byte) 0x26, (byte) 0x94, (byte) 0x01, (byte) 0xb1, + (byte) 0x00, (byte) 0x00, (byte) 0x35, (byte) 0x0b, + (byte) 0x00, (byte) 0x00, (byte) 0x60, (byte) 0x68, + (byte) 0x50, (byte) 0x10, (byte) 0x20, (byte) 0x00, + (byte) 0x76, (byte) 0xa7, (byte) 0x00, (byte) 0x00 + }; + + private static final byte[] TEST_PACKET_IPV6HDR_TCPHDR_DATA = + new byte[] { + // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, + // fl=0x515ca, plen=64, hlim=0x40) / + // scapy.TCP(sport=9876, dport=433, seq=13579, ack=24680, + // flags='A', window=8192, urgptr=0) / + // b'\xde\xad\xbe\xef') + // Note that plen(64) = ipv6hdr(40) + udphdr(20) + data(4). + // IPv6 header + (byte) 0x68, (byte) 0x05, (byte) 0x15, (byte) 0xca, + (byte) 0x00, (byte) 0x40, (byte) 0x06, (byte) 0x40, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, + // TCP header + (byte) 0x26, (byte) 0x94, (byte) 0x01, (byte) 0xb1, + (byte) 0x00, (byte) 0x00, (byte) 0x35, (byte) 0x0b, + (byte) 0x00, (byte) 0x00, (byte) 0x60, (byte) 0x68, + (byte) 0x50, (byte) 0x10, (byte) 0x20, (byte) 0x00, + (byte) 0xd9, (byte) 0x05, (byte) 0x00, (byte) 0x00, + // Data + (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef + }; + + private static final byte[] TEST_PACKET_IPV6HDR_TCPHDR = + new byte[] { + // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, + // fl=0x515ca, plen=60, hlim=0x40) / + // scapy.TCP(sport=9876, dport=433, seq=13579, ack=24680, + // flags='A', window=8192, urgptr=0)) + // Note that plen(60) = ipv6hdr(40) + udphdr(20). + // IPv6 header + (byte) 0x68, (byte) 0x05, (byte) 0x15, (byte) 0xca, + (byte) 0x00, (byte) 0x3c, (byte) 0x06, (byte) 0x40, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, + // TCP header + (byte) 0x26, (byte) 0x94, (byte) 0x01, (byte) 0xb1, + (byte) 0x00, (byte) 0x00, (byte) 0x35, (byte) 0x0b, + (byte) 0x00, (byte) 0x00, (byte) 0x60, (byte) 0x68, + (byte) 0x50, (byte) 0x10, (byte) 0x20, (byte) 0x00, + (byte) 0x76, (byte) 0xa7, (byte) 0x00, (byte) 0x00 + }; + private static final byte[] TEST_PACKET_IPV6HDR_UDPHDR = new byte[] { // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, @@ -540,27 +664,33 @@ public class PacketBuilderTest { } /** - * Check TCPv4 packet. + * Check TCP packet. * * @param hasEther true if the packet has ether header; false otherwise. * @param l3proto the layer 3 protocol. Only {@code IPPROTO_IP} and {@code IPPROTO_IPV6} * currently supported. * @param hasData true if the packet has data payload; false otherwise. * @param actual the packet to check. - * - * TODO: support IPv6 */ - private void checkTcpv4Packet(final boolean hasEther, final int l3proto, final boolean hasData, + private void checkTcpPacket(final boolean hasEther, final int l3proto, final boolean hasData, final ByteBuffer actual) { if (l3proto != IPPROTO_IP && l3proto != IPPROTO_IPV6) { fail("Unsupported layer 3 protocol " + l3proto); } + // [1] Check ether header. if (hasEther) { checkEtherHeader(l3proto, actual); } - checkIpv4Header(IPPROTO_TCP, hasData, actual); + // [2] Check IP header. + if (l3proto == IPPROTO_IP) { + checkIpv4Header(IPPROTO_TCP, hasData, actual); + } else if (l3proto == IPPROTO_IPV6) { + checkIpv6Header(IPPROTO_TCP, hasData, actual); + } + + // [3] Check TCP header. final TcpHeader tcpHeader = Struct.parse(TcpHeader.class, actual); assertEquals(SRC_PORT, tcpHeader.srcPort); assertEquals(DST_PORT, tcpHeader.dstPort); @@ -569,9 +699,14 @@ public class PacketBuilderTest { assertEquals((short) 0x5010 /* offset=5(*4bytes), control bits=ACK */, tcpHeader.dataOffsetAndControlBits); assertEquals(WINDOW, tcpHeader.window); - assertEquals(hasData ? (short) 0x4844 : (short) 0xe5e5, tcpHeader.checksum); assertEquals(URGENT_POINTER, tcpHeader.urgentPointer); + if (l3proto == IPPROTO_IP) { + assertEquals(hasData ? (short) 0x4844 : (short) 0xe5e5, tcpHeader.checksum); + } else if (l3proto == IPPROTO_IPV6) { + assertEquals(hasData ? (short) 0xd905 : (short) 0x76a7, tcpHeader.checksum); + } + // [4] Check payload. if (hasData) { assertEquals(0xdeadbeef, actual.getInt()); } @@ -626,14 +761,14 @@ public class PacketBuilderTest { public void testBuildPacketEtherIPv4Tcp() throws Exception { final ByteBuffer packet = buildPacket(SRC_MAC, DST_MAC, IPPROTO_IP, IPPROTO_TCP, null /* data */); - checkTcpv4Packet(true /* hasEther */, IPPROTO_IP, false /* hasData */, packet); + checkTcpPacket(true /* hasEther */, IPPROTO_IP, false /* hasData */, packet); assertArrayEquals(TEST_PACKET_ETHERHDR_IPV4HDR_TCPHDR, packet.array()); } @Test public void testBuildPacketEtherIPv4TcpData() throws Exception { final ByteBuffer packet = buildPacket(SRC_MAC, DST_MAC, IPPROTO_IP, IPPROTO_TCP, DATA); - checkTcpv4Packet(true /* hasEther */, IPPROTO_IP, true /* hasData */, packet); + checkTcpPacket(true /* hasEther */, IPPROTO_IP, true /* hasData */, packet); assertArrayEquals(TEST_PACKET_ETHERHDR_IPV4HDR_TCPHDR_DATA, packet.array()); } @@ -642,7 +777,7 @@ public class PacketBuilderTest { public void testBuildPacketIPv4Tcp() throws Exception { final ByteBuffer packet = buildPacket(null /* srcMac */, null /* dstMac */, IPPROTO_IP, IPPROTO_TCP, null /* data */); - checkTcpv4Packet(false /* hasEther */, IPPROTO_IP, false /* hasData */, packet); + checkTcpPacket(false /* hasEther */, IPPROTO_IP, false /* hasData */, packet); assertArrayEquals(TEST_PACKET_IPV4HDR_TCPHDR, packet.array()); } @@ -650,7 +785,7 @@ public class PacketBuilderTest { public void testBuildPacketIPv4TcpData() throws Exception { final ByteBuffer packet = buildPacket(null /* srcMac */, null /* dstMac */, IPPROTO_IP, IPPROTO_TCP, DATA); - checkTcpv4Packet(false /* hasEther */, IPPROTO_IP, true /* hasData */, packet); + checkTcpPacket(false /* hasEther */, IPPROTO_IP, true /* hasData */, packet); assertArrayEquals(TEST_PACKET_IPV4HDR_TCPHDR_DATA, packet.array()); } @@ -685,6 +820,39 @@ public class PacketBuilderTest { assertArrayEquals(TEST_PACKET_IPV4HDR_UDPHDR_DATA, packet.array()); } + @Test + public void testBuildPacketEtherIPv6TcpData() throws Exception { + final ByteBuffer packet = buildPacket(SRC_MAC, DST_MAC, IPPROTO_IPV6, IPPROTO_TCP, DATA); + checkTcpPacket(true /* hasEther */, IPPROTO_IPV6, true /* hasData */, packet); + assertArrayEquals(TEST_PACKET_ETHERHDR_IPV6HDR_TCPHDR_DATA, + packet.array()); + } + + @Test + public void testBuildPacketEtherIPv6Tcp() throws Exception { + final ByteBuffer packet = buildPacket(SRC_MAC, DST_MAC, IPPROTO_IPV6, IPPROTO_TCP, + null /*data*/); + checkTcpPacket(true /* hasEther */, IPPROTO_IPV6, false /* hasData */, packet); + assertArrayEquals(TEST_PACKET_ETHERHDR_IPV6HDR_TCPHDR, + packet.array()); + } + + @Test + public void testBuildPacketIPv6TcpData() throws Exception { + final ByteBuffer packet = buildPacket(null /* srcMac */, null /* dstMac */, IPPROTO_IPV6, + IPPROTO_TCP, DATA); + checkTcpPacket(false /* hasEther */, IPPROTO_IPV6, true /* hasData */, packet); + assertArrayEquals(TEST_PACKET_IPV6HDR_TCPHDR_DATA, packet.array()); + } + + @Test + public void testBuildPacketIPv6Tcp() throws Exception { + final ByteBuffer packet = buildPacket(null /* srcMac */, null /* dstMac */, IPPROTO_IPV6, + IPPROTO_TCP, null /*data*/); + checkTcpPacket(false /* hasEther */, IPPROTO_IPV6, false /* hasData */, packet); + assertArrayEquals(TEST_PACKET_IPV6HDR_TCPHDR, packet.array()); + } + @Test public void testBuildPacketEtherIPv6Udp() throws Exception { final ByteBuffer packet = buildPacket(SRC_MAC, DST_MAC, IPPROTO_IPV6, IPPROTO_UDP, From 28e5347154731fe7ffafb5a52e05c38c798d102b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 13 May 2022 06:06:34 -0700 Subject: [PATCH 441/777] BpfMap: cache bpf map file descriptors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We switch back to int from ParcelFileDescriptor, and eliminate all calls to close(). Bpf Map FDs now live till process exit. Bug: 230880517 Test: TreeHugger, atest com.android.networkstack.tethering.BpfMapTest Signed-off-by: Maciej Żenczykowski Change-Id: I89b6dc88ea56cb1e50695f8daf54ed79bce3fba2 --- .../com/android/net/module/util/BpfMap.java | 71 ++++++++++++++----- .../com_android_net_module_util_BpfMap.cpp | 40 +++++------ 2 files changed, 75 insertions(+), 36 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java index 0ee862acfe..f7019a503b 100644 --- a/staticlibs/device/com/android/net/module/util/BpfMap.java +++ b/staticlibs/device/com/android/net/module/util/BpfMap.java @@ -20,6 +20,7 @@ import static android.system.OsConstants.ENOENT; import android.os.ParcelFileDescriptor; import android.system.ErrnoException; +import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -32,6 +33,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.NoSuchElementException; import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; /** * BpfMap is a key -> value mapping structure that is designed to maintained the bpf map entries. @@ -65,6 +67,27 @@ public class BpfMap implements IBpfMap private final int mKeySize; private final int mValueSize; + private static ConcurrentHashMap, ParcelFileDescriptor> sFdCache = + new ConcurrentHashMap<>(); + + private static ParcelFileDescriptor cachedBpfFdGet(String path, int mode) + throws ErrnoException, NullPointerException { + Pair key = Pair.create(path, mode); + // unlocked fetch is safe: map is concurrent read capable, and only inserted into + ParcelFileDescriptor fd = sFdCache.get(key); + if (fd != null) return fd; + // ok, no cached fd present, need to grab a lock + synchronized (BpfMap.class) { + // need to redo the check + fd = sFdCache.get(key); + if (fd != null) return fd; + // okay, we really haven't opened this before... + fd = ParcelFileDescriptor.adoptFd(nativeBpfFdGet(path, mode)); + sFdCache.put(key, fd); + return fd; + } + } + /** * Create a BpfMap map wrapper with "path" of filesystem. * @@ -74,7 +97,7 @@ public class BpfMap implements IBpfMap */ public BpfMap(@NonNull final String path, final int flag, final Class key, final Class value) throws ErrnoException, NullPointerException { - mMapFd = ParcelFileDescriptor.adoptFd(bpfFdGet(path, flag)); + mMapFd = cachedBpfFdGet(path, flag); mKeyClass = key; mValueClass = value; mKeySize = Struct.getSize(key); @@ -90,7 +113,7 @@ public class BpfMap implements IBpfMap */ @VisibleForTesting protected BpfMap(final Class key, final Class value) { - mMapFd = ParcelFileDescriptor.adoptFd(-1 /*invalid*/); // unused + mMapFd = null; // unused mKeyClass = key; mValueClass = value; mKeySize = Struct.getSize(key); @@ -103,7 +126,7 @@ public class BpfMap implements IBpfMap */ @Override public void updateEntry(K key, V value) throws ErrnoException { - writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_ANY); + nativeWriteToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_ANY); } /** @@ -114,7 +137,8 @@ public class BpfMap implements IBpfMap public void insertEntry(K key, V value) throws ErrnoException, IllegalStateException { try { - writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_NOEXIST); + nativeWriteToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), + BPF_NOEXIST); } catch (ErrnoException e) { if (e.errno == EEXIST) throw new IllegalStateException(key + " already exists"); @@ -130,7 +154,8 @@ public class BpfMap implements IBpfMap public void replaceEntry(K key, V value) throws ErrnoException, NoSuchElementException { try { - writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_EXIST); + nativeWriteToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), + BPF_EXIST); } catch (ErrnoException e) { if (e.errno == ENOENT) throw new NoSuchElementException(key + " not found"); @@ -148,13 +173,15 @@ public class BpfMap implements IBpfMap public boolean insertOrReplaceEntry(K key, V value) throws ErrnoException { try { - writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_NOEXIST); + nativeWriteToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), + BPF_NOEXIST); return true; /* insert succeeded */ } catch (ErrnoException e) { if (e.errno != EEXIST) throw e; } try { - writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_EXIST); + nativeWriteToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), + BPF_EXIST); return false; /* replace succeeded */ } catch (ErrnoException e) { if (e.errno != ENOENT) throw e; @@ -171,7 +198,7 @@ public class BpfMap implements IBpfMap /** Remove existing key from eBpf map. Return false if map was not modified. */ @Override public boolean deleteEntry(K key) throws ErrnoException { - return deleteMapEntry(mMapFd.getFd(), key.writeToBytes()); + return nativeDeleteMapEntry(mMapFd.getFd(), key.writeToBytes()); } /** Returns {@code true} if this map contains no elements. */ @@ -204,7 +231,7 @@ public class BpfMap implements IBpfMap private byte[] getNextRawKey(@Nullable final byte[] key) throws ErrnoException { byte[] nextKey = new byte[mKeySize]; - if (getNextMapKey(mMapFd.getFd(), key, nextKey)) return nextKey; + if (nativeGetNextMapKey(mMapFd.getFd(), key, nextKey)) return nextKey; return null; } @@ -239,7 +266,7 @@ public class BpfMap implements IBpfMap private byte[] getRawValue(final byte[] key) throws ErrnoException { byte[] value = new byte[mValueSize]; - if (findMapEntry(mMapFd.getFd(), key, value)) return value; + if (nativeFindMapEntry(mMapFd.getFd(), key, value)) return value; return null; } @@ -263,9 +290,13 @@ public class BpfMap implements IBpfMap } } + /* Empty implementation to implement AutoCloseable, so we can use BpfMaps + * with try with resources, but due to persistent FD cache, there is no actual + * need to close anything. File descriptors will actually be closed when we + * unlock the BpfMap class and destroy the ParcelFileDescriptor objects. + */ @Override public void close() throws IOException { - mMapFd.close(); } /** @@ -283,17 +314,25 @@ public class BpfMap implements IBpfMap } } - private native int bpfFdGet(String path, int mode) throws ErrnoException, NullPointerException; + private static native int nativeBpfFdGet(String path, int mode) + throws ErrnoException, NullPointerException; - private native void writeToMapEntry(int fd, byte[] key, byte[] value, int flags) + // Note: the following methods appear to not require the object by virtue of taking the + // fd as an int argument, but the hidden reference to this is actually what prevents + // the object from being garbage collected (and thus potentially maps closed) prior + // to the native code actually running (with a possibly already closed fd). + + private native void nativeWriteToMapEntry(int fd, byte[] key, byte[] value, int flags) throws ErrnoException; - private native boolean deleteMapEntry(int fd, byte[] key) throws ErrnoException; + private native boolean nativeDeleteMapEntry(int fd, byte[] key) throws ErrnoException; // If key is found, the operation returns true and the nextKey would reference to the next // element. If key is not found, the operation returns true and the nextKey would reference to // the first element. If key is the last element, false is returned. - private native boolean getNextMapKey(int fd, byte[] key, byte[] nextKey) throws ErrnoException; + private native boolean nativeGetNextMapKey(int fd, byte[] key, byte[] nextKey) + throws ErrnoException; - private native boolean findMapEntry(int fd, byte[] key, byte[] value) throws ErrnoException; + private native boolean nativeFindMapEntry(int fd, byte[] key, byte[] value) + throws ErrnoException; } diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp index e3f48e5644..2e88fc83dc 100644 --- a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp +++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp @@ -27,18 +27,18 @@ namespace android { -static jint com_android_net_module_util_BpfMap_bpfFdGet(JNIEnv *env, jobject clazz, +static jint com_android_net_module_util_BpfMap_nativeBpfFdGet(JNIEnv *env, jclass clazz, jstring path, jint mode) { ScopedUtfChars pathname(env, path); jint fd = bpf::bpfFdGet(pathname.c_str(), static_cast(mode)); - if (fd < 0) jniThrowErrnoException(env, "bpfFdGet", errno); + if (fd < 0) jniThrowErrnoException(env, "nativeBpfFdGet", errno); return fd; } -static void com_android_net_module_util_BpfMap_writeToMapEntry(JNIEnv *env, jobject clazz, +static void com_android_net_module_util_BpfMap_nativeWriteToMapEntry(JNIEnv *env, jobject self, jint fd, jbyteArray key, jbyteArray value, jint flags) { ScopedByteArrayRO keyRO(env, key); ScopedByteArrayRO valueRO(env, value); @@ -46,7 +46,7 @@ static void com_android_net_module_util_BpfMap_writeToMapEntry(JNIEnv *env, jobj int ret = bpf::writeToMapEntry(static_cast(fd), keyRO.get(), valueRO.get(), static_cast(flags)); - if (ret) jniThrowErrnoException(env, "writeToMapEntry", errno); + if (ret) jniThrowErrnoException(env, "nativeWriteToMapEntry", errno); } static jboolean throwIfNotEnoent(JNIEnv *env, const char* functionName, int ret, int err) { @@ -56,7 +56,7 @@ static jboolean throwIfNotEnoent(JNIEnv *env, const char* functionName, int ret, return false; } -static jboolean com_android_net_module_util_BpfMap_deleteMapEntry(JNIEnv *env, jobject clazz, +static jboolean com_android_net_module_util_BpfMap_nativeDeleteMapEntry(JNIEnv *env, jobject self, jint fd, jbyteArray key) { ScopedByteArrayRO keyRO(env, key); @@ -64,10 +64,10 @@ static jboolean com_android_net_module_util_BpfMap_deleteMapEntry(JNIEnv *env, j // to ENOENT. int ret = bpf::deleteMapEntry(static_cast(fd), keyRO.get()); - return throwIfNotEnoent(env, "deleteMapEntry", ret, errno); + return throwIfNotEnoent(env, "nativeDeleteMapEntry", ret, errno); } -static jboolean com_android_net_module_util_BpfMap_getNextMapKey(JNIEnv *env, jobject clazz, +static jboolean com_android_net_module_util_BpfMap_nativeGetNextMapKey(JNIEnv *env, jobject self, jint fd, jbyteArray key, jbyteArray nextKey) { // If key is found, the operation returns zero and sets the next key pointer to the key of the // next element. If key is not found, the operation returns zero and sets the next key pointer @@ -83,10 +83,10 @@ static jboolean com_android_net_module_util_BpfMap_getNextMapKey(JNIEnv *env, jo ret = bpf::getNextMapKey(static_cast(fd), keyRO.get(), nextKeyRW.get()); } - return throwIfNotEnoent(env, "getNextMapKey", ret, errno); + return throwIfNotEnoent(env, "nativeGetNextMapKey", ret, errno); } -static jboolean com_android_net_module_util_BpfMap_findMapEntry(JNIEnv *env, jobject clazz, +static jboolean com_android_net_module_util_BpfMap_nativeFindMapEntry(JNIEnv *env, jobject self, jint fd, jbyteArray key, jbyteArray value) { ScopedByteArrayRO keyRO(env, key); ScopedByteArrayRW valueRW(env, value); @@ -95,7 +95,7 @@ static jboolean com_android_net_module_util_BpfMap_findMapEntry(JNIEnv *env, job // "value". If no element is found, the operation returns -1 and sets errno to ENOENT. int ret = bpf::findMapEntry(static_cast(fd), keyRO.get(), valueRW.get()); - return throwIfNotEnoent(env, "findMapEntry", ret, errno); + return throwIfNotEnoent(env, "nativeFindMapEntry", ret, errno); } /* @@ -103,16 +103,16 @@ static jboolean com_android_net_module_util_BpfMap_findMapEntry(JNIEnv *env, job */ static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ - { "bpfFdGet", "(Ljava/lang/String;I)I", - (void*) com_android_net_module_util_BpfMap_bpfFdGet }, - { "writeToMapEntry", "(I[B[BI)V", - (void*) com_android_net_module_util_BpfMap_writeToMapEntry }, - { "deleteMapEntry", "(I[B)Z", - (void*) com_android_net_module_util_BpfMap_deleteMapEntry }, - { "getNextMapKey", "(I[B[B)Z", - (void*) com_android_net_module_util_BpfMap_getNextMapKey }, - { "findMapEntry", "(I[B[B)Z", - (void*) com_android_net_module_util_BpfMap_findMapEntry }, + { "nativeBpfFdGet", "(Ljava/lang/String;I)I", + (void*) com_android_net_module_util_BpfMap_nativeBpfFdGet }, + { "nativeWriteToMapEntry", "(I[B[BI)V", + (void*) com_android_net_module_util_BpfMap_nativeWriteToMapEntry }, + { "nativeDeleteMapEntry", "(I[B)Z", + (void*) com_android_net_module_util_BpfMap_nativeDeleteMapEntry }, + { "nativeGetNextMapKey", "(I[B[B)Z", + (void*) com_android_net_module_util_BpfMap_nativeGetNextMapKey }, + { "nativeFindMapEntry", "(I[B[B)Z", + (void*) com_android_net_module_util_BpfMap_nativeFindMapEntry }, }; From a59401269d167e2a3f4c1ae2119c550411905bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 13 May 2022 06:06:34 -0700 Subject: [PATCH 442/777] BpfMap: cache bpf map file descriptors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We switch back to int from ParcelFileDescriptor, and eliminate all calls to close(). Bpf Map FDs now live till process exit. Bug: 230880517 Test: TreeHugger, atest com.android.networkstack.tethering.BpfMapTest Signed-off-by: Maciej Żenczykowski Change-Id: I89b6dc88ea56cb1e50695f8daf54ed79bce3fba2 (cherry picked from commit 8888c198daa8141988ee806adcf54b43e68b1076) Merged-In: I89b6dc88ea56cb1e50695f8daf54ed79bce3fba2 --- .../com/android/net/module/util/BpfMap.java | 71 ++++++++++++++----- .../com_android_net_module_util_BpfMap.cpp | 40 +++++------ 2 files changed, 75 insertions(+), 36 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java index a7fbab77e9..854b9fdfe9 100644 --- a/staticlibs/device/com/android/net/module/util/BpfMap.java +++ b/staticlibs/device/com/android/net/module/util/BpfMap.java @@ -20,6 +20,7 @@ import static android.system.OsConstants.ENOENT; import android.os.ParcelFileDescriptor; import android.system.ErrnoException; +import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -32,6 +33,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.NoSuchElementException; import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; /** * BpfMap is a key -> value mapping structure that is designed to maintained the bpf map entries. @@ -65,6 +67,27 @@ public class BpfMap implements IBpfMap private final int mKeySize; private final int mValueSize; + private static ConcurrentHashMap, ParcelFileDescriptor> sFdCache = + new ConcurrentHashMap<>(); + + private static ParcelFileDescriptor cachedBpfFdGet(String path, int mode) + throws ErrnoException, NullPointerException { + Pair key = Pair.create(path, mode); + // unlocked fetch is safe: map is concurrent read capable, and only inserted into + ParcelFileDescriptor fd = sFdCache.get(key); + if (fd != null) return fd; + // ok, no cached fd present, need to grab a lock + synchronized (BpfMap.class) { + // need to redo the check + fd = sFdCache.get(key); + if (fd != null) return fd; + // okay, we really haven't opened this before... + fd = ParcelFileDescriptor.adoptFd(nativeBpfFdGet(path, mode)); + sFdCache.put(key, fd); + return fd; + } + } + /** * Create a BpfMap map wrapper with "path" of filesystem. * @@ -74,7 +97,7 @@ public class BpfMap implements IBpfMap */ public BpfMap(@NonNull final String path, final int flag, final Class key, final Class value) throws ErrnoException, NullPointerException { - mMapFd = ParcelFileDescriptor.adoptFd(bpfFdGet(path, flag)); + mMapFd = cachedBpfFdGet(path, flag); mKeyClass = key; mValueClass = value; mKeySize = Struct.getSize(key); @@ -90,7 +113,7 @@ public class BpfMap implements IBpfMap */ @VisibleForTesting protected BpfMap(final Class key, final Class value) { - mMapFd = ParcelFileDescriptor.adoptFd(-1 /*invalid*/); // unused + mMapFd = null; // unused mKeyClass = key; mValueClass = value; mKeySize = Struct.getSize(key); @@ -103,7 +126,7 @@ public class BpfMap implements IBpfMap */ @Override public void updateEntry(K key, V value) throws ErrnoException { - writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_ANY); + nativeWriteToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_ANY); } /** @@ -114,7 +137,8 @@ public class BpfMap implements IBpfMap public void insertEntry(K key, V value) throws ErrnoException, IllegalStateException { try { - writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_NOEXIST); + nativeWriteToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), + BPF_NOEXIST); } catch (ErrnoException e) { if (e.errno == EEXIST) throw new IllegalStateException(key + " already exists"); @@ -130,7 +154,8 @@ public class BpfMap implements IBpfMap public void replaceEntry(K key, V value) throws ErrnoException, NoSuchElementException { try { - writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_EXIST); + nativeWriteToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), + BPF_EXIST); } catch (ErrnoException e) { if (e.errno == ENOENT) throw new NoSuchElementException(key + " not found"); @@ -148,13 +173,15 @@ public class BpfMap implements IBpfMap public boolean insertOrReplaceEntry(K key, V value) throws ErrnoException { try { - writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_NOEXIST); + nativeWriteToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), + BPF_NOEXIST); return true; /* insert succeeded */ } catch (ErrnoException e) { if (e.errno != EEXIST) throw e; } try { - writeToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_EXIST); + nativeWriteToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), + BPF_EXIST); return false; /* replace succeeded */ } catch (ErrnoException e) { if (e.errno != ENOENT) throw e; @@ -171,7 +198,7 @@ public class BpfMap implements IBpfMap /** Remove existing key from eBpf map. Return false if map was not modified. */ @Override public boolean deleteEntry(K key) throws ErrnoException { - return deleteMapEntry(mMapFd.getFd(), key.writeToBytes()); + return nativeDeleteMapEntry(mMapFd.getFd(), key.writeToBytes()); } /** Returns {@code true} if this map contains no elements. */ @@ -204,7 +231,7 @@ public class BpfMap implements IBpfMap private byte[] getNextRawKey(@Nullable final byte[] key) throws ErrnoException { byte[] nextKey = new byte[mKeySize]; - if (getNextMapKey(mMapFd.getFd(), key, nextKey)) return nextKey; + if (nativeGetNextMapKey(mMapFd.getFd(), key, nextKey)) return nextKey; return null; } @@ -239,7 +266,7 @@ public class BpfMap implements IBpfMap private byte[] getRawValue(final byte[] key) throws ErrnoException { byte[] value = new byte[mValueSize]; - if (findMapEntry(mMapFd.getFd(), key, value)) return value; + if (nativeFindMapEntry(mMapFd.getFd(), key, value)) return value; return null; } @@ -263,9 +290,13 @@ public class BpfMap implements IBpfMap } } + /* Empty implementation to implement AutoCloseable, so we can use BpfMaps + * with try with resources, but due to persistent FD cache, there is no actual + * need to close anything. File descriptors will actually be closed when we + * unlock the BpfMap class and destroy the ParcelFileDescriptor objects. + */ @Override public void close() throws IOException { - mMapFd.close(); } /** @@ -283,17 +314,25 @@ public class BpfMap implements IBpfMap } } - private native int bpfFdGet(String path, int mode) throws ErrnoException, NullPointerException; + private static native int nativeBpfFdGet(String path, int mode) + throws ErrnoException, NullPointerException; - private native void writeToMapEntry(int fd, byte[] key, byte[] value, int flags) + // Note: the following methods appear to not require the object by virtue of taking the + // fd as an int argument, but the hidden reference to this is actually what prevents + // the object from being garbage collected (and thus potentially maps closed) prior + // to the native code actually running (with a possibly already closed fd). + + private native void nativeWriteToMapEntry(int fd, byte[] key, byte[] value, int flags) throws ErrnoException; - private native boolean deleteMapEntry(int fd, byte[] key) throws ErrnoException; + private native boolean nativeDeleteMapEntry(int fd, byte[] key) throws ErrnoException; // If key is found, the operation returns true and the nextKey would reference to the next // element. If key is not found, the operation returns true and the nextKey would reference to // the first element. If key is the last element, false is returned. - private native boolean getNextMapKey(int fd, byte[] key, byte[] nextKey) throws ErrnoException; + private native boolean nativeGetNextMapKey(int fd, byte[] key, byte[] nextKey) + throws ErrnoException; - private native boolean findMapEntry(int fd, byte[] key, byte[] value) throws ErrnoException; + private native boolean nativeFindMapEntry(int fd, byte[] key, byte[] value) + throws ErrnoException; } diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp index e3f48e5644..2e88fc83dc 100644 --- a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp +++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp @@ -27,18 +27,18 @@ namespace android { -static jint com_android_net_module_util_BpfMap_bpfFdGet(JNIEnv *env, jobject clazz, +static jint com_android_net_module_util_BpfMap_nativeBpfFdGet(JNIEnv *env, jclass clazz, jstring path, jint mode) { ScopedUtfChars pathname(env, path); jint fd = bpf::bpfFdGet(pathname.c_str(), static_cast(mode)); - if (fd < 0) jniThrowErrnoException(env, "bpfFdGet", errno); + if (fd < 0) jniThrowErrnoException(env, "nativeBpfFdGet", errno); return fd; } -static void com_android_net_module_util_BpfMap_writeToMapEntry(JNIEnv *env, jobject clazz, +static void com_android_net_module_util_BpfMap_nativeWriteToMapEntry(JNIEnv *env, jobject self, jint fd, jbyteArray key, jbyteArray value, jint flags) { ScopedByteArrayRO keyRO(env, key); ScopedByteArrayRO valueRO(env, value); @@ -46,7 +46,7 @@ static void com_android_net_module_util_BpfMap_writeToMapEntry(JNIEnv *env, jobj int ret = bpf::writeToMapEntry(static_cast(fd), keyRO.get(), valueRO.get(), static_cast(flags)); - if (ret) jniThrowErrnoException(env, "writeToMapEntry", errno); + if (ret) jniThrowErrnoException(env, "nativeWriteToMapEntry", errno); } static jboolean throwIfNotEnoent(JNIEnv *env, const char* functionName, int ret, int err) { @@ -56,7 +56,7 @@ static jboolean throwIfNotEnoent(JNIEnv *env, const char* functionName, int ret, return false; } -static jboolean com_android_net_module_util_BpfMap_deleteMapEntry(JNIEnv *env, jobject clazz, +static jboolean com_android_net_module_util_BpfMap_nativeDeleteMapEntry(JNIEnv *env, jobject self, jint fd, jbyteArray key) { ScopedByteArrayRO keyRO(env, key); @@ -64,10 +64,10 @@ static jboolean com_android_net_module_util_BpfMap_deleteMapEntry(JNIEnv *env, j // to ENOENT. int ret = bpf::deleteMapEntry(static_cast(fd), keyRO.get()); - return throwIfNotEnoent(env, "deleteMapEntry", ret, errno); + return throwIfNotEnoent(env, "nativeDeleteMapEntry", ret, errno); } -static jboolean com_android_net_module_util_BpfMap_getNextMapKey(JNIEnv *env, jobject clazz, +static jboolean com_android_net_module_util_BpfMap_nativeGetNextMapKey(JNIEnv *env, jobject self, jint fd, jbyteArray key, jbyteArray nextKey) { // If key is found, the operation returns zero and sets the next key pointer to the key of the // next element. If key is not found, the operation returns zero and sets the next key pointer @@ -83,10 +83,10 @@ static jboolean com_android_net_module_util_BpfMap_getNextMapKey(JNIEnv *env, jo ret = bpf::getNextMapKey(static_cast(fd), keyRO.get(), nextKeyRW.get()); } - return throwIfNotEnoent(env, "getNextMapKey", ret, errno); + return throwIfNotEnoent(env, "nativeGetNextMapKey", ret, errno); } -static jboolean com_android_net_module_util_BpfMap_findMapEntry(JNIEnv *env, jobject clazz, +static jboolean com_android_net_module_util_BpfMap_nativeFindMapEntry(JNIEnv *env, jobject self, jint fd, jbyteArray key, jbyteArray value) { ScopedByteArrayRO keyRO(env, key); ScopedByteArrayRW valueRW(env, value); @@ -95,7 +95,7 @@ static jboolean com_android_net_module_util_BpfMap_findMapEntry(JNIEnv *env, job // "value". If no element is found, the operation returns -1 and sets errno to ENOENT. int ret = bpf::findMapEntry(static_cast(fd), keyRO.get(), valueRW.get()); - return throwIfNotEnoent(env, "findMapEntry", ret, errno); + return throwIfNotEnoent(env, "nativeFindMapEntry", ret, errno); } /* @@ -103,16 +103,16 @@ static jboolean com_android_net_module_util_BpfMap_findMapEntry(JNIEnv *env, job */ static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ - { "bpfFdGet", "(Ljava/lang/String;I)I", - (void*) com_android_net_module_util_BpfMap_bpfFdGet }, - { "writeToMapEntry", "(I[B[BI)V", - (void*) com_android_net_module_util_BpfMap_writeToMapEntry }, - { "deleteMapEntry", "(I[B)Z", - (void*) com_android_net_module_util_BpfMap_deleteMapEntry }, - { "getNextMapKey", "(I[B[B)Z", - (void*) com_android_net_module_util_BpfMap_getNextMapKey }, - { "findMapEntry", "(I[B[B)Z", - (void*) com_android_net_module_util_BpfMap_findMapEntry }, + { "nativeBpfFdGet", "(Ljava/lang/String;I)I", + (void*) com_android_net_module_util_BpfMap_nativeBpfFdGet }, + { "nativeWriteToMapEntry", "(I[B[BI)V", + (void*) com_android_net_module_util_BpfMap_nativeWriteToMapEntry }, + { "nativeDeleteMapEntry", "(I[B)Z", + (void*) com_android_net_module_util_BpfMap_nativeDeleteMapEntry }, + { "nativeGetNextMapKey", "(I[B[B)Z", + (void*) com_android_net_module_util_BpfMap_nativeGetNextMapKey }, + { "nativeFindMapEntry", "(I[B[B)Z", + (void*) com_android_net_module_util_BpfMap_nativeFindMapEntry }, }; From 95082d5818cfee66f87c996d0847c2b78404c978 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 24 May 2022 18:39:33 +0900 Subject: [PATCH 443/777] Move test URL keys to NetworkStackConstants This allows the tests to reference the constants without depending on all of NetworkStack. Test: atest CtsNetTestCases Change-Id: I6f54f525520a1a9454af943d1228399f13747d66 --- .../module/util/NetworkStackConstants.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 353fe6921e..1ad9c35910 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -228,6 +228,35 @@ public final class NetworkStackConstants { public static final int TAG_SYSTEM_PROBE = 0xFFFFFF81; public static final int TAG_SYSTEM_DNS = 0xFFFFFF82; + /** + * A test URL used to override configuration settings and overlays for the network validation + * HTTPS URL, when set in {@link android.provider.DeviceConfig} configuration. + * + *

This URL will be ignored if the host is not "localhost" (it can only be used to test with + * a local test server), and must not be set in production scenarios (as enforced by CTS tests). + * + *

{@link #TEST_URL_EXPIRATION_TIME} must also be set to use this setting. + */ + public static final String TEST_CAPTIVE_PORTAL_HTTPS_URL = "test_captive_portal_https_url"; + /** + * A test URL used to override configuration settings and overlays for the network validation + * HTTP URL, when set in {@link android.provider.DeviceConfig} configuration. + * + *

This URL will be ignored if the host is not "localhost" (it can only be used to test with + * a local test server), and must not be set in production scenarios (as enforced by CTS tests). + * + *

{@link #TEST_URL_EXPIRATION_TIME} must also be set to use this setting. + */ + public static final String TEST_CAPTIVE_PORTAL_HTTP_URL = "test_captive_portal_http_url"; + /** + * Expiration time of the test URL, in ms, relative to {@link System#currentTimeMillis()}. + * + *

After this expiration time, test URLs will be ignored. They will also be ignored if + * the expiration time is more than 10 minutes in the future, to avoid misconfiguration + * following test runs. + */ + public static final String TEST_URL_EXPIRATION_TIME = "test_url_expiration_time"; + // TODO: Move to Inet4AddressUtils // See aosp/1455936: NetworkStackConstants can't depend on it as it causes jarjar-related issues // for users of both the net-utils-device-common and net-utils-framework-common libraries. From 6f49c956866d15b706332983a9f9af8e0474ee0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 24 May 2022 16:07:16 -0700 Subject: [PATCH 444/777] bpf_helpers.h - add #define's for S/T bpfloader versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (by request from Lorenzo) Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I802d2aae8b103375d7cbe0ed5c35f0abf6c04ac9 --- .../native/bpf_headers/include/bpf/bpf_helpers.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index ac9f9bcb18..3e26028544 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -19,6 +19,17 @@ * * ******************************************************************************/ +// The actual versions of the bpfloader that shipped in various Android releases + +// Android P/Q/R: BpfLoader was initially part of netd, +// this was later split out into a standalone binary, but was unversioned. + +// Android S / 12 (api level 31) - added 'tethering' mainline eBPF support +#define BPFLOADER_S_VERSION 2u + +// Android T / 13 Beta 3 (api level 33) - added support for 'netd_shared' +#define BPFLOADER_T_BETA3_VERSION 13u + /* For mainline module use, you can #define BPFLOADER_{MIN/MAX}_VER * before #include "bpf_helpers.h" to change which bpfloaders will * process the resulting .o file. From eeb588721e8994589c23bbd6fcb9050543929354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 25 May 2022 12:29:37 -0700 Subject: [PATCH 445/777] cache kernelVersion(), make isAtLeastKernelVersion() cheaper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit not perfect due to this being in a header file, so multiple copies potentially exist, but it's really simple, and works nearly as well. Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Id90c6933d57bc12f4dd640c8918fd0885c7474cf --- staticlibs/native/bpf_headers/include/bpf/BpfUtils.h | 7 ++++++- staticlibs/native/tcutils/kernelversion.h | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index 8f1b9a28ac..7801c3ef07 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -92,7 +92,7 @@ static inline int setrlimitForTest() { #define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c)) -static inline unsigned kernelVersion() { +static inline unsigned uncachedKernelVersion() { struct utsname buf; int ret = uname(&buf); if (ret) return 0; @@ -108,6 +108,11 @@ static inline unsigned kernelVersion() { return KVER(kver_major, kver_minor, kver_sub); } +static inline unsigned kernelVersion() { + static unsigned kver = uncachedKernelVersion(); + return kver; +} + static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) { return kernelVersion() >= KVER(major, minor, sub); } diff --git a/staticlibs/native/tcutils/kernelversion.h b/staticlibs/native/tcutils/kernelversion.h index 3be1ad293f..492444ad74 100644 --- a/staticlibs/native/tcutils/kernelversion.h +++ b/staticlibs/native/tcutils/kernelversion.h @@ -32,7 +32,7 @@ namespace android { -static inline unsigned kernelVersion() { +static inline unsigned uncachedKernelVersion() { struct utsname buf; int ret = uname(&buf); if (ret) @@ -51,6 +51,11 @@ static inline unsigned kernelVersion() { return KVER(kver_major, kver_minor, kver_sub); } +static unsigned kernelVersion() { + static unsigned kver = uncachedKernelVersion(); + return kver; +} + static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) { return kernelVersion() >= KVER(major, minor, sub); From fa1baa1b4c0c71282f336042bde779086ce2b616 Mon Sep 17 00:00:00 2001 From: "eric.yan" Date: Thu, 26 May 2022 00:25:26 +0800 Subject: [PATCH 446/777] define necessary bpf helper functions add bpf helper functions: bpf_get_stackid; bpf_get_current_comm Signed-off-by: eric.yan Change-Id: If0daccfe8504fc107ed8d07bef92ed40b101dbc5 --- staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index ac9f9bcb18..5f3a4a368e 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -177,6 +177,8 @@ static int (*bpf_trace_printk)(const char* fmt, int fmt_size, ...) = (void*) BPF static unsigned long long (*bpf_get_current_pid_tgid)(void) = (void*) BPF_FUNC_get_current_pid_tgid; static unsigned long long (*bpf_get_current_uid_gid)(void) = (void*) BPF_FUNC_get_current_uid_gid; static unsigned long long (*bpf_get_smp_processor_id)(void) = (void*) BPF_FUNC_get_smp_processor_id; +static long (*bpf_get_stackid)(void* ctx, void* map, uint64_t flags) = (void*) BPF_FUNC_get_stackid; +static long (*bpf_get_current_comm)(void* buf, uint32_t buf_size) = (void*) BPF_FUNC_get_current_comm; #define DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \ opt) \ From 6b6fc1b38df19f8e04517c0b9a2b6c90b602abd1 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 25 May 2022 22:03:54 +0900 Subject: [PATCH 447/777] Add test to verify parsing multiple netlink messages in one buffer. Currently the netlink parsing code doesn't advance to the end of message if it doesn't consume the entire message, that results in the remaining attributes will be considered as a new netlink message, parsing the attributes will fail and return null. Have a testcase to verify this case. Bug: 163492391 Test: atest NetworkStaticLibsTests Change-Id: I2719cd917f9932d5e77002e615845076784139a2 --- .../netlink/RtNetlinkRouteMessageTest.java | 55 +++++++++++++++---- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java index 392314fbb4..93b9894b1c 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java @@ -63,15 +63,7 @@ public class RtNetlinkRouteMessageTest { return ByteBuffer.wrap(HexDump.hexStringToByteArray(hexString)); } - @Test - public void testParseRtmRouteAddress() { - final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_HEX); - byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. - final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); - assertNotNull(msg); - assertTrue(msg instanceof RtNetlinkRouteMessage); - final RtNetlinkRouteMessage routeMsg = (RtNetlinkRouteMessage) msg; - + private void assertRtmRouteMessage(final RtNetlinkRouteMessage routeMsg) { final StructNlMsgHdr hdr = routeMsg.getHeader(); assertNotNull(hdr); assertEquals(136, hdr.nlmsg_len); @@ -97,6 +89,18 @@ public class RtNetlinkRouteMessageTest { assertEquals((Inet6Address) routeMsg.getGateway(), TEST_IPV6_LINK_LOCAL_GATEWAY); } + @Test + public void testParseRtmRouteMessage() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkRouteMessage); + final RtNetlinkRouteMessage routeMsg = (RtNetlinkRouteMessage) msg; + assertRtmRouteMessage(routeMsg); + } + private static final String RTM_NEWROUTE_PACK_HEX = "4C000000180000060000000000000000" // struct nlmsghr + "0A400000FC02000100000000" // struct rtmsg @@ -143,7 +147,7 @@ public class RtNetlinkRouteMessageTest { + "08000400DF020000"; // RTA_OIF @Test - public void testParseRtmRouteAddress_IPv4MappedIPv6Gateway() { + public void testParseRtmRouteMessage_IPv4MappedIPv6Gateway() { final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_IPV4_MAPPED_IPV6_GATEWAY_HEX); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); @@ -160,7 +164,7 @@ public class RtNetlinkRouteMessageTest { + "08000400DF020000"; // RTA_OIF @Test - public void testParseRtmRouteAddress_IPv4MappedIPv6Destination() { + public void testParseRtmRouteMessage_IPv4MappedIPv6Destination() { final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_IPV4_MAPPED_IPV6_DST_HEX); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); @@ -169,6 +173,35 @@ public class RtNetlinkRouteMessageTest { assertNull(msg); } + // An example of the full RTM_NEWADDR message. + private static final String RTM_NEWADDR_HEX = + "48000000140000000000000000000000" // struct nlmsghr + + "0A4080FD1E000000" // struct ifaddrmsg + + "14000100FE800000000000002C415CFFFE096665" // IFA_ADDRESS + + "14000600100E0000201C00002A70000045700000" // IFA_CACHEINFO + + "0800080080000000"; // IFA_FLAGS + + @Test + public void testParseMultipleRtmMessagesInOneByteBuffer() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_HEX + RTM_NEWADDR_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + + // Try to parse the RTM_NEWROUTE message. + NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkRouteMessage); + final RtNetlinkRouteMessage routeMsg = (RtNetlinkRouteMessage) msg; + assertRtmRouteMessage(routeMsg); + + // Try to parse the RTM_NEWADDR message. + msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + // The current parse code does not advance to the end of the message if the + // entire message wasn't consumed, then the remaining attributes in the + // RTM_NEWROUTE message will be considered as another new rtm netlink message, + // that will return null. + assertNull(msg); + } + @Test public void testToString() { final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_HEX); From b02211a3128423fcb8cb84683a7769ae86b33110 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 26 May 2022 04:31:39 +0000 Subject: [PATCH 448/777] When parsing a netlink message, always advance to the end. NetlinkEvent#parse relies on message-specific classes to parse the payload of the message. If these classes do not consume the entire message, parse does not advance to the end of the message. This means that any code that loops over a ByteBuffer parsing messages one at a time (e.g., NetlinkMonitor) will think that there is still a message left to parse, and will attempt to parse the remainder of the message as a new netlink message. This is obviously incorrect for any buffer that contains more than one netlink message. Bug: 163492391 Test: existing unit tests Change-Id: Ifdb9748068857f75ca00c58f0c40f19809aae5c9 --- .../module/util/netlink/NetlinkMessage.java | 19 +++++++++++++------ .../netlink/RtNetlinkRouteMessageTest.java | 7 ++----- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java index a216752b42..9e1e26e760 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java @@ -51,8 +51,8 @@ public class NetlinkMessage { return null; } - int payloadLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len); - payloadLength -= StructNlMsgHdr.STRUCT_SIZE; + final int messageLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len); + final int payloadLength = messageLength - StructNlMsgHdr.STRUCT_SIZE; if (payloadLength < 0 || payloadLength > byteBuffer.remaining()) { // Malformed message or runt buffer. Pretend the buffer was consumed. byteBuffer.position(byteBuffer.limit()); @@ -68,15 +68,22 @@ public class NetlinkMessage { // Netlink family messages. The netlink family is required. Note that the reason for using // if-statement is that switch-case can't be used because the OsConstants.NETLINK_* are // not constant. + final NetlinkMessage parsed; if (nlFamily == OsConstants.NETLINK_ROUTE) { - return parseRtMessage(nlmsghdr, byteBuffer); + parsed = parseRtMessage(nlmsghdr, byteBuffer); } else if (nlFamily == OsConstants.NETLINK_INET_DIAG) { - return parseInetDiagMessage(nlmsghdr, byteBuffer); + parsed = parseInetDiagMessage(nlmsghdr, byteBuffer); } else if (nlFamily == OsConstants.NETLINK_NETFILTER) { - return parseNfMessage(nlmsghdr, byteBuffer); + parsed = parseNfMessage(nlmsghdr, byteBuffer); + } else { + parsed = null; } - return null; + // Advance to the end of the message, regardless of whether the parsing code consumed + // all of it or not. + byteBuffer.position(startPosition + messageLength); + + return parsed; } @NonNull diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java index 93b9894b1c..55cfd50d40 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java @@ -195,11 +195,8 @@ public class RtNetlinkRouteMessageTest { // Try to parse the RTM_NEWADDR message. msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); - // The current parse code does not advance to the end of the message if the - // entire message wasn't consumed, then the remaining attributes in the - // RTM_NEWROUTE message will be considered as another new rtm netlink message, - // that will return null. - assertNull(msg); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkAddressMessage); } @Test From f73d99fbe552d3fdd83d29f01d639f854a608371 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 25 May 2022 22:03:54 +0900 Subject: [PATCH 449/777] Add test to verify parsing multiple netlink messages in one buffer. Currently the netlink parsing code doesn't advance to the end of message if it doesn't consume the entire message, that results in the remaining attributes will be considered as a new netlink message, parsing the attributes will fail and return null. Have a testcase to verify this case. Bug: 163492391 Test: atest NetworkStaticLibsTests Change-Id: I2719cd917f9932d5e77002e615845076784139a2 (cherry picked from commit a8b53fd42b5f198e77733b292473c4bbe5ea80d8) Merged-In: I2719cd917f9932d5e77002e615845076784139a2 --- .../netlink/RtNetlinkRouteMessageTest.java | 55 +++++++++++++++---- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java index 392314fbb4..93b9894b1c 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java @@ -63,15 +63,7 @@ public class RtNetlinkRouteMessageTest { return ByteBuffer.wrap(HexDump.hexStringToByteArray(hexString)); } - @Test - public void testParseRtmRouteAddress() { - final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_HEX); - byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. - final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); - assertNotNull(msg); - assertTrue(msg instanceof RtNetlinkRouteMessage); - final RtNetlinkRouteMessage routeMsg = (RtNetlinkRouteMessage) msg; - + private void assertRtmRouteMessage(final RtNetlinkRouteMessage routeMsg) { final StructNlMsgHdr hdr = routeMsg.getHeader(); assertNotNull(hdr); assertEquals(136, hdr.nlmsg_len); @@ -97,6 +89,18 @@ public class RtNetlinkRouteMessageTest { assertEquals((Inet6Address) routeMsg.getGateway(), TEST_IPV6_LINK_LOCAL_GATEWAY); } + @Test + public void testParseRtmRouteMessage() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkRouteMessage); + final RtNetlinkRouteMessage routeMsg = (RtNetlinkRouteMessage) msg; + assertRtmRouteMessage(routeMsg); + } + private static final String RTM_NEWROUTE_PACK_HEX = "4C000000180000060000000000000000" // struct nlmsghr + "0A400000FC02000100000000" // struct rtmsg @@ -143,7 +147,7 @@ public class RtNetlinkRouteMessageTest { + "08000400DF020000"; // RTA_OIF @Test - public void testParseRtmRouteAddress_IPv4MappedIPv6Gateway() { + public void testParseRtmRouteMessage_IPv4MappedIPv6Gateway() { final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_IPV4_MAPPED_IPV6_GATEWAY_HEX); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); @@ -160,7 +164,7 @@ public class RtNetlinkRouteMessageTest { + "08000400DF020000"; // RTA_OIF @Test - public void testParseRtmRouteAddress_IPv4MappedIPv6Destination() { + public void testParseRtmRouteMessage_IPv4MappedIPv6Destination() { final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_IPV4_MAPPED_IPV6_DST_HEX); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); @@ -169,6 +173,35 @@ public class RtNetlinkRouteMessageTest { assertNull(msg); } + // An example of the full RTM_NEWADDR message. + private static final String RTM_NEWADDR_HEX = + "48000000140000000000000000000000" // struct nlmsghr + + "0A4080FD1E000000" // struct ifaddrmsg + + "14000100FE800000000000002C415CFFFE096665" // IFA_ADDRESS + + "14000600100E0000201C00002A70000045700000" // IFA_CACHEINFO + + "0800080080000000"; // IFA_FLAGS + + @Test + public void testParseMultipleRtmMessagesInOneByteBuffer() { + final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_HEX + RTM_NEWADDR_HEX); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. + + // Try to parse the RTM_NEWROUTE message. + NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkRouteMessage); + final RtNetlinkRouteMessage routeMsg = (RtNetlinkRouteMessage) msg; + assertRtmRouteMessage(routeMsg); + + // Try to parse the RTM_NEWADDR message. + msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); + // The current parse code does not advance to the end of the message if the + // entire message wasn't consumed, then the remaining attributes in the + // RTM_NEWROUTE message will be considered as another new rtm netlink message, + // that will return null. + assertNull(msg); + } + @Test public void testToString() { final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWROUTE_HEX); From 02898967b8871c0f8195d3d5495bf751a30043ef Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 26 May 2022 04:31:39 +0000 Subject: [PATCH 450/777] When parsing a netlink message, always advance to the end. NetlinkEvent#parse relies on message-specific classes to parse the payload of the message. If these classes do not consume the entire message, parse does not advance to the end of the message. This means that any code that loops over a ByteBuffer parsing messages one at a time (e.g., NetlinkMonitor) will think that there is still a message left to parse, and will attempt to parse the remainder of the message as a new netlink message. This is obviously incorrect for any buffer that contains more than one netlink message. Bug: 163492391 Test: existing unit tests Change-Id: Ifdb9748068857f75ca00c58f0c40f19809aae5c9 (cherry picked from commit 0bf51a89b2fbb6cc60668a39189ef2a90bea4c5b) Merged-In: Ifdb9748068857f75ca00c58f0c40f19809aae5c9 --- .../module/util/netlink/NetlinkMessage.java | 19 +++++++++++++------ .../netlink/RtNetlinkRouteMessageTest.java | 7 ++----- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java index a216752b42..9e1e26e760 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkMessage.java @@ -51,8 +51,8 @@ public class NetlinkMessage { return null; } - int payloadLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len); - payloadLength -= StructNlMsgHdr.STRUCT_SIZE; + final int messageLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len); + final int payloadLength = messageLength - StructNlMsgHdr.STRUCT_SIZE; if (payloadLength < 0 || payloadLength > byteBuffer.remaining()) { // Malformed message or runt buffer. Pretend the buffer was consumed. byteBuffer.position(byteBuffer.limit()); @@ -68,15 +68,22 @@ public class NetlinkMessage { // Netlink family messages. The netlink family is required. Note that the reason for using // if-statement is that switch-case can't be used because the OsConstants.NETLINK_* are // not constant. + final NetlinkMessage parsed; if (nlFamily == OsConstants.NETLINK_ROUTE) { - return parseRtMessage(nlmsghdr, byteBuffer); + parsed = parseRtMessage(nlmsghdr, byteBuffer); } else if (nlFamily == OsConstants.NETLINK_INET_DIAG) { - return parseInetDiagMessage(nlmsghdr, byteBuffer); + parsed = parseInetDiagMessage(nlmsghdr, byteBuffer); } else if (nlFamily == OsConstants.NETLINK_NETFILTER) { - return parseNfMessage(nlmsghdr, byteBuffer); + parsed = parseNfMessage(nlmsghdr, byteBuffer); + } else { + parsed = null; } - return null; + // Advance to the end of the message, regardless of whether the parsing code consumed + // all of it or not. + byteBuffer.position(startPosition + messageLength); + + return parsed; } @NonNull diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java index 93b9894b1c..55cfd50d40 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java @@ -195,11 +195,8 @@ public class RtNetlinkRouteMessageTest { // Try to parse the RTM_NEWADDR message. msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE); - // The current parse code does not advance to the end of the message if the - // entire message wasn't consumed, then the remaining attributes in the - // RTM_NEWROUTE message will be considered as another new rtm netlink message, - // that will return null. - assertNull(msg); + assertNotNull(msg); + assertTrue(msg instanceof RtNetlinkAddressMessage); } @Test From 690d1e15f53dbdaafad91ebf35fa516b911cf96e Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Fri, 27 May 2022 17:51:02 +0800 Subject: [PATCH 451/777] PacketBuilder: correct IPv6 header payload length Ipv6 payload length doesn't include header length. rfc8200 section 3 https://tools.ietf.org/html/rfc8200 Payload Length 16-bit unsigned integer. Length of the IPv6 payload, i.e., the rest of the packet following this IPv6 header, in octets. Bug: 215655463 Test: atest NetworkStaticLibTests Change-Id: Ifdc871125b0fe2eb3a8909b8b0723a62dbe44bcf --- .../net/module/util/PacketBuilder.java | 12 +++-- .../net/module/util/PacketBuilderTest.java | 47 +++++++------------ 2 files changed, 25 insertions(+), 34 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/PacketBuilder.java b/staticlibs/device/com/android/net/module/util/PacketBuilder.java index 8acb2965f8..33e5bfad21 100644 --- a/staticlibs/device/com/android/net/module/util/PacketBuilder.java +++ b/staticlibs/device/com/android/net/module/util/PacketBuilder.java @@ -26,6 +26,7 @@ import static com.android.net.module.util.IpUtils.tcpChecksum; import static com.android.net.module.util.IpUtils.udpChecksum; import static com.android.net.module.util.NetworkStackConstants.IPV4_CHECKSUM_OFFSET; import static com.android.net.module.util.NetworkStackConstants.IPV4_LENGTH_OFFSET; +import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN; import static com.android.net.module.util.NetworkStackConstants.IPV6_LEN_OFFSET; import static com.android.net.module.util.NetworkStackConstants.TCP_CHECKSUM_OFFSET; import static com.android.net.module.util.NetworkStackConstants.UDP_CHECKSUM_OFFSET; @@ -100,9 +101,9 @@ public class PacketBuilder { */ public void writeL2Header(MacAddress srcMac, MacAddress dstMac, short etherType) throws IOException { - final EthernetHeader ethv4Header = new EthernetHeader(dstMac, srcMac, etherType); + final EthernetHeader ethHeader = new EthernetHeader(dstMac, srcMac, etherType); try { - ethv4Header.writeToByteBuffer(mBuffer); + ethHeader.writeToByteBuffer(mBuffer); } catch (IllegalArgumentException | BufferOverflowException e) { throw new IOException("Error writing to buffer: ", e); } @@ -218,7 +219,7 @@ public class PacketBuilder { */ @NonNull public ByteBuffer finalizePacket() throws IOException { - // Finalize IPv4 or IPv6 header. + // [1] Finalize IPv4 or IPv6 header. int ipHeaderOffset = INVALID_OFFSET; if (mIpv4HeaderOffset != INVALID_OFFSET) { ipHeaderOffset = mIpv4HeaderOffset; @@ -234,13 +235,14 @@ public class PacketBuilder { ipHeaderOffset = mIpv6HeaderOffset; // Populate the IPv6 payloadLength field. + // The payload length doesn't include IPv6 header length. See rfc8200 section 3. mBuffer.putShort(mIpv6HeaderOffset + IPV6_LEN_OFFSET, - (short) (mBuffer.position() - mIpv6HeaderOffset)); + (short) (mBuffer.position() - mIpv6HeaderOffset - IPV6_HEADER_LEN)); } else { throw new IOException("Packet is missing neither IPv4 nor IPv6 header"); } - // Finalize TCP or UDP header. + // [2] Finalize TCP or UDP header. if (mTcpHeaderOffset != INVALID_OFFSET) { // Populate the TCP header checksum field. mBuffer.putShort(mTcpHeaderOffset + TCP_CHECKSUM_OFFSET, tcpChecksum(mBuffer, diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java index 1a0752a022..e40cd6b6bf 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PacketBuilderTest.java @@ -24,7 +24,6 @@ import static android.system.OsConstants.IPPROTO_UDP; import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV4; import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6; import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN; -import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN; import static com.android.net.module.util.NetworkStackConstants.TCPHDR_ACK; import static com.android.net.module.util.NetworkStackConstants.TCP_HEADER_MIN_LEN; import static com.android.net.module.util.NetworkStackConstants.UDP_HEADER_LEN; @@ -271,9 +270,8 @@ public class PacketBuilderTest { // packet = (scapy.Ether(src="11:22:33:44:55:66", dst="aa:bb:cc:dd:ee:ff", // type='IPv6') / // scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, - // fl=0x515ca, plen=48, hlim=0x40) / + // fl=0x515ca, hlim=0x40) / // scapy.UDP(sport=9876, dport=433)) - // Note that plen(48) = ipv6hdr(40) + udphdr(8). // Ether header (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, (byte) 0xee, (byte) 0xff, (byte) 0x11, (byte) 0x22, @@ -281,7 +279,7 @@ public class PacketBuilderTest { (byte) 0x86, (byte) 0xdd, // IP header (byte) 0x68, (byte) 0x05, (byte) 0x15, (byte) 0xca, - (byte) 0x00, (byte) 0x30, (byte) 0x11, (byte) 0x40, + (byte) 0x00, (byte) 0x08, (byte) 0x11, (byte) 0x40, (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, @@ -300,10 +298,9 @@ public class PacketBuilderTest { // packet = (scapy.Ether(src="11:22:33:44:55:66", dst="aa:bb:cc:dd:ee:ff", // type='IPv6') / // scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, - // fl=0x515ca, plen=52, hlim=0x40) / + // fl=0x515ca, hlim=0x40) / // scapy.UDP(sport=9876, dport=433) / // b'\xde\xad\xbe\xef') - // Note that plen(52) = ipv6hdr(40) + udphdr(8) + data(4). // Ether header (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, (byte) 0xee, (byte) 0xff, (byte) 0x11, (byte) 0x22, @@ -311,7 +308,7 @@ public class PacketBuilderTest { (byte) 0x86, (byte) 0xdd, // IP header (byte) 0x68, (byte) 0x05, (byte) 0x15, (byte) 0xca, - (byte) 0x00, (byte) 0x34, (byte) 0x11, (byte) 0x40, + (byte) 0x00, (byte) 0x0c, (byte) 0x11, (byte) 0x40, (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, @@ -332,11 +329,10 @@ public class PacketBuilderTest { // packet = (scapy.Ether(src="11:22:33:44:55:66", dst="aa:bb:cc:dd:ee:ff", // type='IPv6') / // scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, - // fl=0x515ca, plen=64, hlim=0x40) / + // fl=0x515ca, hlim=0x40) / // scapy.TCP(sport=9876, dport=433, seq=13579, ack=24680, // flags='A', window=8192, urgptr=0) / // b'\xde\xad\xbe\xef') - // Note that plen(64) = ipv6hdr(40) + udphdr(20) + data(4). // Ether header (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, (byte) 0xee, (byte) 0xff, (byte) 0x11, (byte) 0x22, @@ -344,7 +340,7 @@ public class PacketBuilderTest { (byte) 0x86, (byte) 0xdd, // IPv6 header (byte) 0x68, (byte) 0x05, (byte) 0x15, (byte) 0xca, - (byte) 0x00, (byte) 0x40, (byte) 0x06, (byte) 0x40, + (byte) 0x00, (byte) 0x18, (byte) 0x06, (byte) 0x40, (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, @@ -368,10 +364,9 @@ public class PacketBuilderTest { // packet = (scapy.Ether(src="11:22:33:44:55:66", dst="aa:bb:cc:dd:ee:ff", // type='IPv6') / // scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, - // fl=0x515ca, plen=60, hlim=0x40) / + // fl=0x515ca, hlim=0x40) / // scapy.TCP(sport=9876, dport=433, seq=13579, ack=24680, // flags='A', window=8192, urgptr=0)) - // Note that plen(60) = ipv6hdr(40) + udphdr(20). // Ether header (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, (byte) 0xee, (byte) 0xff, (byte) 0x11, (byte) 0x22, @@ -379,7 +374,7 @@ public class PacketBuilderTest { (byte) 0x86, (byte) 0xdd, // IPv6 header (byte) 0x68, (byte) 0x05, (byte) 0x15, (byte) 0xca, - (byte) 0x00, (byte) 0x3c, (byte) 0x06, (byte) 0x40, + (byte) 0x00, (byte) 0x14, (byte) 0x06, (byte) 0x40, (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, @@ -399,14 +394,13 @@ public class PacketBuilderTest { private static final byte[] TEST_PACKET_IPV6HDR_TCPHDR_DATA = new byte[] { // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, - // fl=0x515ca, plen=64, hlim=0x40) / + // fl=0x515ca, hlim=0x40) / // scapy.TCP(sport=9876, dport=433, seq=13579, ack=24680, // flags='A', window=8192, urgptr=0) / // b'\xde\xad\xbe\xef') - // Note that plen(64) = ipv6hdr(40) + udphdr(20) + data(4). // IPv6 header (byte) 0x68, (byte) 0x05, (byte) 0x15, (byte) 0xca, - (byte) 0x00, (byte) 0x40, (byte) 0x06, (byte) 0x40, + (byte) 0x00, (byte) 0x18, (byte) 0x06, (byte) 0x40, (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, @@ -428,13 +422,12 @@ public class PacketBuilderTest { private static final byte[] TEST_PACKET_IPV6HDR_TCPHDR = new byte[] { // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, - // fl=0x515ca, plen=60, hlim=0x40) / + // fl=0x515ca, hlim=0x40) / // scapy.TCP(sport=9876, dport=433, seq=13579, ack=24680, // flags='A', window=8192, urgptr=0)) - // Note that plen(60) = ipv6hdr(40) + udphdr(20). // IPv6 header (byte) 0x68, (byte) 0x05, (byte) 0x15, (byte) 0xca, - (byte) 0x00, (byte) 0x3c, (byte) 0x06, (byte) 0x40, + (byte) 0x00, (byte) 0x14, (byte) 0x06, (byte) 0x40, (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, @@ -454,12 +447,11 @@ public class PacketBuilderTest { private static final byte[] TEST_PACKET_IPV6HDR_UDPHDR = new byte[] { // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, - // fl=0x515ca, plen=48, hlim=0x40) / + // fl=0x515ca, hlim=0x40) / // scapy.UDP(sport=9876, dport=433)) - // Note that plen(48) = ipv6hdr(40) + udphdr(8). // IP header (byte) 0x68, (byte) 0x05, (byte) 0x15, (byte) 0xca, - (byte) 0x00, (byte) 0x30, (byte) 0x11, (byte) 0x40, + (byte) 0x00, (byte) 0x08, (byte) 0x11, (byte) 0x40, (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, @@ -476,13 +468,12 @@ public class PacketBuilderTest { private static final byte[] TEST_PACKET_IPV6HDR_UDPHDR_DATA = new byte[] { // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80, - // fl=0x515ca, plen=52, hlim=0x40) / + // fl=0x515ca, hlim=0x40) / // scapy.UDP(sport=9876, dport=433) / // b'\xde\xad\xbe\xef') - // Note that plen(52) = ipv6hdr(40) + udphdr(8) + data(4). // IP header (byte) 0x68, (byte) 0x05, (byte) 0x15, (byte) 0xca, - (byte) 0x00, (byte) 0x34, (byte) 0x11, (byte) 0x40, + (byte) 0x00, (byte) 0x0c, (byte) 0x11, (byte) 0x40, (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, @@ -653,12 +644,10 @@ public class PacketBuilderTest { final int dataLength = hasData ? DATA.limit() : 0; if (l4proto == IPPROTO_TCP) { - assertEquals(IPV6_HEADER_LEN + TCP_HEADER_MIN_LEN + dataLength, - ipv6Header.payloadLength); + assertEquals(TCP_HEADER_MIN_LEN + dataLength, ipv6Header.payloadLength); assertEquals((byte) IPPROTO_TCP, ipv6Header.nextHeader); } else if (l4proto == IPPROTO_UDP) { - assertEquals(IPV6_HEADER_LEN + UDP_HEADER_LEN + dataLength, - ipv6Header.payloadLength); + assertEquals(UDP_HEADER_LEN + dataLength, ipv6Header.payloadLength); assertEquals((byte) IPPROTO_UDP, ipv6Header.nextHeader); } } From 085b7f442acee4b831d9f618dfea1db2ddbe250f Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Thu, 26 May 2022 22:31:50 +0800 Subject: [PATCH 452/777] DeviceInfoUtils: add class and helper for three-part version number Add a class Version and string helper for handling a three-part kernel version number. Test: atest com.android.testutils.DeviceInfoUtilsTest Bug: 232332847 Change-Id: I0f229e935bd8332ef2ef93fc910a576df9c054ae --- .../testutils/DeviceInfoUtilsTest.java | 64 +++++++++++ .../android/testutils/DeviceInfoUtils.java | 103 +++++++++++++++++- 2 files changed, 164 insertions(+), 3 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java b/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java index f99700a6f4..6f603d50da 100644 --- a/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java @@ -17,6 +17,9 @@ package com.android.testutils; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; import androidx.test.filters.SmallTest; @@ -42,4 +45,65 @@ public final class DeviceInfoUtilsTest { assertEquals(-1, DeviceInfoUtils.compareMajorMinorVersion("3.10", "4.8.0")); assertEquals(-1, DeviceInfoUtils.compareMajorMinorVersion("4.7.10.10", "4.8")); } + + @Test + public void testGetMajorMinorSubminorVersion() throws Exception { + final DeviceInfoUtils.KVersion expected = new DeviceInfoUtils.KVersion(4, 19, 220); + assertEquals(expected, DeviceInfoUtils.getMajorMinorSubminorVersion("4.19.220")); + assertEquals(expected, DeviceInfoUtils.getMajorMinorSubminorVersion("4.19.220.50")); + assertEquals(expected, DeviceInfoUtils.getMajorMinorSubminorVersion( + "4.19.220-g500ede0aed22-ab8272303")); + + final DeviceInfoUtils.KVersion expected2 = new DeviceInfoUtils.KVersion(5, 17, 0); + assertEquals(expected2, DeviceInfoUtils.getMajorMinorSubminorVersion("5.17")); + assertEquals(expected2, DeviceInfoUtils.getMajorMinorSubminorVersion("5.17.")); + assertEquals(expected2, DeviceInfoUtils.getMajorMinorSubminorVersion("5.17.beta")); + assertEquals(expected2, DeviceInfoUtils.getMajorMinorSubminorVersion( + "5.17-rc6-g52099515ca00-ab8032400")); + + final DeviceInfoUtils.KVersion invalid = new DeviceInfoUtils.KVersion(0, 0, 0); + assertEquals(invalid, DeviceInfoUtils.getMajorMinorSubminorVersion("")); + assertEquals(invalid, DeviceInfoUtils.getMajorMinorSubminorVersion("4")); + assertEquals(invalid, DeviceInfoUtils.getMajorMinorSubminorVersion("4.")); + assertEquals(invalid, DeviceInfoUtils.getMajorMinorSubminorVersion("4-beta")); + assertEquals(invalid, DeviceInfoUtils.getMajorMinorSubminorVersion("1.x.1")); + assertEquals(invalid, DeviceInfoUtils.getMajorMinorSubminorVersion("x.1.1")); + } + + @Test + public void testVersion() throws Exception { + final DeviceInfoUtils.KVersion v1 = new DeviceInfoUtils.KVersion(4, 8, 1); + final DeviceInfoUtils.KVersion v2 = new DeviceInfoUtils.KVersion(4, 8, 1); + final DeviceInfoUtils.KVersion v3 = new DeviceInfoUtils.KVersion(4, 8, 2); + final DeviceInfoUtils.KVersion v4 = new DeviceInfoUtils.KVersion(4, 9, 1); + final DeviceInfoUtils.KVersion v5 = new DeviceInfoUtils.KVersion(5, 8, 1); + + assertEquals(v1, v2); + assertNotEquals(v1, v3); + assertNotEquals(v1, v4); + assertNotEquals(v1, v5); + + assertEquals(0, v1.compareTo(v2)); + assertEquals(-1, v1.compareTo(v3)); + assertEquals(1, v3.compareTo(v1)); + assertEquals(-1, v1.compareTo(v4)); + assertEquals(1, v4.compareTo(v1)); + assertEquals(-1, v1.compareTo(v5)); + assertEquals(1, v5.compareTo(v1)); + + assertTrue(v2.isInRange(v1, v5)); + assertTrue(v3.isInRange(v1, v5)); + assertTrue(v4.isInRange(v1, v5)); + assertFalse(v5.isInRange(v1, v5)); + assertFalse(v1.isInRange(v3, v5)); + assertFalse(v5.isInRange(v2, v4)); + + assertTrue(v2.isAtLeast(v1)); + assertTrue(v3.isAtLeast(v1)); + assertTrue(v4.isAtLeast(v1)); + assertTrue(v5.isAtLeast(v1)); + assertFalse(v1.isAtLeast(v3)); + assertFalse(v1.isAtLeast(v4)); + assertFalse(v1.isAtLeast(v5)); + } } diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java b/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java index 69cb5f81a7..1925b55945 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java @@ -26,7 +26,78 @@ import java.util.regex.Pattern; * Utilities for device information. */ public class DeviceInfoUtils { - private static Pair getVersionFromString(String version) { + /** + * Class for a three-part kernel version number. + */ + public static class KVersion { + public final int major; + public final int minor; + public final int sub; + + public KVersion(int major, int minor, int sub) { + this.major = major; + this.minor = minor; + this.sub = sub; + } + + /** + * Compares with other version numerically. + * + * @param other the other version to compare + * @return the value 0 if this == other; + * a value less than 0 if this < other and + * a value greater than 0 if this > other. + */ + public int compareTo(final KVersion other) { + int res = Integer.compare(this.major, other.major); + if (res == 0) { + res = Integer.compare(this.minor, other.minor); + } + if (res == 0) { + res = Integer.compare(this.sub, other.sub); + } + return res; + } + + /** + * At least satisfied with the given version. + * + * @param from the start version to compare + * @return return true if this version is at least satisfied with the given version. + * otherwise, return false. + */ + public boolean isAtLeast(final KVersion from) { + return compareTo(from) >= 0; + } + + /** + * Falls within the given range [from, to). + * + * @param from the start version to compare + * @param to the end version to compare + * @return return true if this version falls within the given range. + * otherwise, return false. + */ + public boolean isInRange(final KVersion from, final KVersion to) { + return isAtLeast(from) && !isAtLeast(to); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof KVersion)) return false; + KVersion that = (KVersion) o; + return this.major == that.major + && this.minor == that.minor + && this.sub == that.sub; + } + }; + + /** + * Get a two-part kernel version number (major and minor) from a given string. + * + * TODO: use class KVersion. + */ + private static Pair getMajorMinorVersion(String version) { // Only gets major and minor number of the version string. final Pattern versionPattern = Pattern.compile("^(\\d+)(\\.(\\d+))?.*"); final Matcher m = versionPattern.matcher(version); @@ -49,10 +120,12 @@ public class DeviceInfoUtils { * @return the value 0 if s1 == s2; * a value less than 0 if s1 < s2 and * a value greater than 0 if s1 > s2. + * + * TODO: use class KVersion. */ public static int compareMajorMinorVersion(final String s1, final String s2) { - final Pair v1 = getVersionFromString(s1); - final Pair v2 = getVersionFromString(s2); + final Pair v1 = getMajorMinorVersion(s1); + final Pair v2 = getMajorMinorVersion(s2); if (v1.first == v2.first) { return Integer.compare(v1.second, v2.second); @@ -60,4 +133,28 @@ public class DeviceInfoUtils { return Integer.compare(v1.first, v2.first); } } + + /** + * Get a three-part kernel version number (major, minor and subminor) from a given string. + * Any version string must at least have major and minor number. If the subminor number can't + * be parsed from string. Assign zero as subminor number. Invalid version is treated as + * version 0.0.0. + */ + public static KVersion getMajorMinorSubminorVersion(final String version) { + // The kernel version is a three-part version number (major, minor and subminor). Get + // the three-part version numbers and discard the remaining stuff if any. + // For example: + // 4.19.220-g500ede0aed22-ab8272303 --> 4.19.220 + // 5.17-rc6-g52099515ca00-ab8032400 --> 5.17.0 + final Pattern versionPattern = Pattern.compile("^(\\d+)\\.(\\d+)(\\.(\\d+))?.*"); + final Matcher m = versionPattern.matcher(version); + if (m.matches()) { + final int major = Integer.parseInt(m.group(1)); + final int minor = Integer.parseInt(m.group(2)); + final int sub = TextUtils.isEmpty(m.group(4)) ? 0 : Integer.parseInt(m.group(4)); + return new KVersion(major, minor, sub); + } else { + return new KVersion(0, 0, 0); + } + } } From 70cd8e7de8f43e5571b5bf7ef9bc3cc407426e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 27 May 2022 15:03:57 +0000 Subject: [PATCH 453/777] synchronizeKernelRCU - update comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: N/A, comment only Signed-of-by: Maciej Żenczykowski Change-Id: I839a457fdb8f5b95f60cb9cd41983fbcf3792768 --- staticlibs/native/bpf_headers/include/bpf/BpfUtils.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index 7801c3ef07..3f0689686a 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -60,6 +60,9 @@ static inline int synchronizeKernelRCU() { // This is a temporary hack for network stats map swap on devices running // 4.9 kernels. The kernel code of socket release on pf_key socket will // explicitly call synchronize_rcu() which is exactly what we need. + // + // Linux 4.14/4.19/5.4/5.10/5.15 (and 5.18) still have this same behaviour. + // see net/key/af_key.c: pfkey_release() -> synchronize_rcu() int pfSocket = socket(AF_KEY, SOCK_RAW | SOCK_CLOEXEC, PF_KEY_V2); if (pfSocket < 0) { From 9a276e68f8769b86763ea574ce0bffc37d60f305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 27 May 2022 19:38:15 +0000 Subject: [PATCH 454/777] Fix parsing of kernel version 5.18-rc1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Bug: 234125620 Signed-off-by: Maciej Żenczykowski Change-Id: I624927cacd2722f4fc61ef419de74254cecdd77b --- .../native/bpf_headers/include/bpf/BpfUtils.h | 15 +++++---------- staticlibs/native/tcutils/kernelversion.h | 18 +++++------------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index 3f0689686a..4429164ee5 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -97,17 +97,12 @@ static inline int setrlimitForTest() { static inline unsigned uncachedKernelVersion() { struct utsname buf; - int ret = uname(&buf); - if (ret) return 0; - - unsigned kver_major; - unsigned kver_minor; - unsigned kver_sub; - char unused; - ret = sscanf(buf.release, "%u.%u.%u%c", &kver_major, &kver_minor, &kver_sub, &unused); - // Check the device kernel version - if (ret < 3) return 0; + if (uname(&buf)) return 0; + unsigned kver_major = 0; + unsigned kver_minor = 0; + unsigned kver_sub = 0; + (void)sscanf(buf.release, "%u.%u.%u", &kver_major, &kver_minor, &kver_sub); return KVER(kver_major, kver_minor, kver_sub); } diff --git a/staticlibs/native/tcutils/kernelversion.h b/staticlibs/native/tcutils/kernelversion.h index 492444ad74..9aab31d4a1 100644 --- a/staticlibs/native/tcutils/kernelversion.h +++ b/staticlibs/native/tcutils/kernelversion.h @@ -34,20 +34,12 @@ namespace android { static inline unsigned uncachedKernelVersion() { struct utsname buf; - int ret = uname(&buf); - if (ret) - return 0; - - unsigned kver_major; - unsigned kver_minor; - unsigned kver_sub; - char discard; - ret = sscanf(buf.release, "%u.%u.%u%c", &kver_major, &kver_minor, &kver_sub, - &discard); - // Check the device kernel version - if (ret < 3) - return 0; + if (uname(&buf)) return 0; + unsigned kver_major = 0; + unsigned kver_minor = 0; + unsigned kver_sub = 0; + (void)sscanf(buf.release, "%u.%u.%u", &kver_major, &kver_minor, &kver_sub); return KVER(kver_major, kver_minor, kver_sub); } From 6d76eba0c788b4b01df4257f15b4ac98fe626074 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Mon, 9 May 2022 21:07:40 +0800 Subject: [PATCH 455/777] Move DeviceInfoUtilsTest from NetworkStack to frameworks/lib/net Test: atest com.android.testutils.DeviceInfoUtilsTest Change-Id: Ib45dea951980eae0c1576d37842477192539a740 (cherry picked from commit 9f26c843618aad57a27e2eff976c2ff521739fac) Merged-In: Ib45dea951980eae0c1576d37842477192539a740 --- .../testutils/DeviceInfoUtilsTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java diff --git a/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java b/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java new file mode 100644 index 0000000000..f99700a6f4 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java @@ -0,0 +1,45 @@ +/* + * 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 com.android.testutils; + +import static org.junit.Assert.assertEquals; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +@SmallTest +public final class DeviceInfoUtilsTest { + /** + * Verifies that version string compare logic returns expected result for various cases. + * Note that only major and minor number are compared. + */ + @Test + public void testMajorMinorVersionCompare() { + assertEquals(0, DeviceInfoUtils.compareMajorMinorVersion("4.8.1", "4.8")); + assertEquals(1, DeviceInfoUtils.compareMajorMinorVersion("4.9", "4.8.1")); + assertEquals(1, DeviceInfoUtils.compareMajorMinorVersion("5.0", "4.8")); + assertEquals(1, DeviceInfoUtils.compareMajorMinorVersion("5", "4.8")); + assertEquals(0, DeviceInfoUtils.compareMajorMinorVersion("5", "5.0")); + assertEquals(1, DeviceInfoUtils.compareMajorMinorVersion("5-beta1", "4.8")); + assertEquals(0, DeviceInfoUtils.compareMajorMinorVersion("4.8.0.0", "4.8")); + assertEquals(0, DeviceInfoUtils.compareMajorMinorVersion("4.8-RC1", "4.8")); + assertEquals(0, DeviceInfoUtils.compareMajorMinorVersion("4.8", "4.8")); + assertEquals(-1, DeviceInfoUtils.compareMajorMinorVersion("3.10", "4.8.0")); + assertEquals(-1, DeviceInfoUtils.compareMajorMinorVersion("4.7.10.10", "4.8")); + } +} From d999b13980454be0c862255df71ba784f671f5cb Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Fri, 27 May 2022 19:38:41 +0000 Subject: [PATCH 456/777] DeviceInfoUtils: add class and helper for three-part version number Add a class Version and string helper for handling a three-part kernel version number. Test: atest com.android.testutils.DeviceInfoUtilsTest Bug: 232332847 Original change: https://android-review.googlesource.com/c/platform/frameworks/libs/net/+/2108204 Merged-In: I0f229e935bd8332ef2ef93fc910a576df9c054ae Change-Id: I70fedb33582a2f157b93ad0ab5be8f305feb3b21 Signed-off-by: Nucca Chen (cherry picked from commit 3a7e53b03034b71985e905915d3eeb07d80b77c7) --- .../testutils/DeviceInfoUtilsTest.java | 64 +++++++++++ .../android/testutils/DeviceInfoUtils.java | 103 +++++++++++++++++- 2 files changed, 164 insertions(+), 3 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java b/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java index f99700a6f4..6f603d50da 100644 --- a/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java @@ -17,6 +17,9 @@ package com.android.testutils; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; import androidx.test.filters.SmallTest; @@ -42,4 +45,65 @@ public final class DeviceInfoUtilsTest { assertEquals(-1, DeviceInfoUtils.compareMajorMinorVersion("3.10", "4.8.0")); assertEquals(-1, DeviceInfoUtils.compareMajorMinorVersion("4.7.10.10", "4.8")); } + + @Test + public void testGetMajorMinorSubminorVersion() throws Exception { + final DeviceInfoUtils.KVersion expected = new DeviceInfoUtils.KVersion(4, 19, 220); + assertEquals(expected, DeviceInfoUtils.getMajorMinorSubminorVersion("4.19.220")); + assertEquals(expected, DeviceInfoUtils.getMajorMinorSubminorVersion("4.19.220.50")); + assertEquals(expected, DeviceInfoUtils.getMajorMinorSubminorVersion( + "4.19.220-g500ede0aed22-ab8272303")); + + final DeviceInfoUtils.KVersion expected2 = new DeviceInfoUtils.KVersion(5, 17, 0); + assertEquals(expected2, DeviceInfoUtils.getMajorMinorSubminorVersion("5.17")); + assertEquals(expected2, DeviceInfoUtils.getMajorMinorSubminorVersion("5.17.")); + assertEquals(expected2, DeviceInfoUtils.getMajorMinorSubminorVersion("5.17.beta")); + assertEquals(expected2, DeviceInfoUtils.getMajorMinorSubminorVersion( + "5.17-rc6-g52099515ca00-ab8032400")); + + final DeviceInfoUtils.KVersion invalid = new DeviceInfoUtils.KVersion(0, 0, 0); + assertEquals(invalid, DeviceInfoUtils.getMajorMinorSubminorVersion("")); + assertEquals(invalid, DeviceInfoUtils.getMajorMinorSubminorVersion("4")); + assertEquals(invalid, DeviceInfoUtils.getMajorMinorSubminorVersion("4.")); + assertEquals(invalid, DeviceInfoUtils.getMajorMinorSubminorVersion("4-beta")); + assertEquals(invalid, DeviceInfoUtils.getMajorMinorSubminorVersion("1.x.1")); + assertEquals(invalid, DeviceInfoUtils.getMajorMinorSubminorVersion("x.1.1")); + } + + @Test + public void testVersion() throws Exception { + final DeviceInfoUtils.KVersion v1 = new DeviceInfoUtils.KVersion(4, 8, 1); + final DeviceInfoUtils.KVersion v2 = new DeviceInfoUtils.KVersion(4, 8, 1); + final DeviceInfoUtils.KVersion v3 = new DeviceInfoUtils.KVersion(4, 8, 2); + final DeviceInfoUtils.KVersion v4 = new DeviceInfoUtils.KVersion(4, 9, 1); + final DeviceInfoUtils.KVersion v5 = new DeviceInfoUtils.KVersion(5, 8, 1); + + assertEquals(v1, v2); + assertNotEquals(v1, v3); + assertNotEquals(v1, v4); + assertNotEquals(v1, v5); + + assertEquals(0, v1.compareTo(v2)); + assertEquals(-1, v1.compareTo(v3)); + assertEquals(1, v3.compareTo(v1)); + assertEquals(-1, v1.compareTo(v4)); + assertEquals(1, v4.compareTo(v1)); + assertEquals(-1, v1.compareTo(v5)); + assertEquals(1, v5.compareTo(v1)); + + assertTrue(v2.isInRange(v1, v5)); + assertTrue(v3.isInRange(v1, v5)); + assertTrue(v4.isInRange(v1, v5)); + assertFalse(v5.isInRange(v1, v5)); + assertFalse(v1.isInRange(v3, v5)); + assertFalse(v5.isInRange(v2, v4)); + + assertTrue(v2.isAtLeast(v1)); + assertTrue(v3.isAtLeast(v1)); + assertTrue(v4.isAtLeast(v1)); + assertTrue(v5.isAtLeast(v1)); + assertFalse(v1.isAtLeast(v3)); + assertFalse(v1.isAtLeast(v4)); + assertFalse(v1.isAtLeast(v5)); + } } diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java b/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java index 69cb5f81a7..1925b55945 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java @@ -26,7 +26,78 @@ import java.util.regex.Pattern; * Utilities for device information. */ public class DeviceInfoUtils { - private static Pair getVersionFromString(String version) { + /** + * Class for a three-part kernel version number. + */ + public static class KVersion { + public final int major; + public final int minor; + public final int sub; + + public KVersion(int major, int minor, int sub) { + this.major = major; + this.minor = minor; + this.sub = sub; + } + + /** + * Compares with other version numerically. + * + * @param other the other version to compare + * @return the value 0 if this == other; + * a value less than 0 if this < other and + * a value greater than 0 if this > other. + */ + public int compareTo(final KVersion other) { + int res = Integer.compare(this.major, other.major); + if (res == 0) { + res = Integer.compare(this.minor, other.minor); + } + if (res == 0) { + res = Integer.compare(this.sub, other.sub); + } + return res; + } + + /** + * At least satisfied with the given version. + * + * @param from the start version to compare + * @return return true if this version is at least satisfied with the given version. + * otherwise, return false. + */ + public boolean isAtLeast(final KVersion from) { + return compareTo(from) >= 0; + } + + /** + * Falls within the given range [from, to). + * + * @param from the start version to compare + * @param to the end version to compare + * @return return true if this version falls within the given range. + * otherwise, return false. + */ + public boolean isInRange(final KVersion from, final KVersion to) { + return isAtLeast(from) && !isAtLeast(to); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof KVersion)) return false; + KVersion that = (KVersion) o; + return this.major == that.major + && this.minor == that.minor + && this.sub == that.sub; + } + }; + + /** + * Get a two-part kernel version number (major and minor) from a given string. + * + * TODO: use class KVersion. + */ + private static Pair getMajorMinorVersion(String version) { // Only gets major and minor number of the version string. final Pattern versionPattern = Pattern.compile("^(\\d+)(\\.(\\d+))?.*"); final Matcher m = versionPattern.matcher(version); @@ -49,10 +120,12 @@ public class DeviceInfoUtils { * @return the value 0 if s1 == s2; * a value less than 0 if s1 < s2 and * a value greater than 0 if s1 > s2. + * + * TODO: use class KVersion. */ public static int compareMajorMinorVersion(final String s1, final String s2) { - final Pair v1 = getVersionFromString(s1); - final Pair v2 = getVersionFromString(s2); + final Pair v1 = getMajorMinorVersion(s1); + final Pair v2 = getMajorMinorVersion(s2); if (v1.first == v2.first) { return Integer.compare(v1.second, v2.second); @@ -60,4 +133,28 @@ public class DeviceInfoUtils { return Integer.compare(v1.first, v2.first); } } + + /** + * Get a three-part kernel version number (major, minor and subminor) from a given string. + * Any version string must at least have major and minor number. If the subminor number can't + * be parsed from string. Assign zero as subminor number. Invalid version is treated as + * version 0.0.0. + */ + public static KVersion getMajorMinorSubminorVersion(final String version) { + // The kernel version is a three-part version number (major, minor and subminor). Get + // the three-part version numbers and discard the remaining stuff if any. + // For example: + // 4.19.220-g500ede0aed22-ab8272303 --> 4.19.220 + // 5.17-rc6-g52099515ca00-ab8032400 --> 5.17.0 + final Pattern versionPattern = Pattern.compile("^(\\d+)\\.(\\d+)(\\.(\\d+))?.*"); + final Matcher m = versionPattern.matcher(version); + if (m.matches()) { + final int major = Integer.parseInt(m.group(1)); + final int minor = Integer.parseInt(m.group(2)); + final int sub = TextUtils.isEmpty(m.group(4)) ? 0 : Integer.parseInt(m.group(4)); + return new KVersion(major, minor, sub); + } else { + return new KVersion(0, 0, 0); + } + } } From db5d69ec49e77af2536ae6c6950889e85d2f74da Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 27 May 2022 23:50:25 +0900 Subject: [PATCH 457/777] Add an annotation to skip tests if the APK has target SDK > 31. This skips a test if the APK it's running in targets an SDK above 31. This allows us to add such tests to CtsNetTestCases, which is currently targeting SDK 33. By using the annotation as an include-annotation filter in AndroidTestTemplate.xml, this makes it very easy to create a clone of CtsNetTestCases that targets SDK 31 and which only runs tests annotated with this annotation. Thus, CtsNetTestCases and CtsNetTestCasesLatestSdk will run all tests that pass if target SDK is 33, and CtsNetTestCasesMaxTargetSdk31 will only run the tests that requires target SDK 31. See other CL in topic. Bug: 233553525 Test: atest CtsNetTestCasesMaxTargetSdk31:android.net.LinkPropertiesTest Test: atest CtsNetTestCasesLatestSdk:android.net.LinkPropertiesTest Change-Id: Ib5df3bbc659d6a737a846fdf57cddee002e4e9ae --- .../com/android/testutils/DevSdkIgnoreRule.kt | 28 +++++++++++++++---- .../filters/CtsNetTestCasesMaxTargetSdk31.kt | 22 +++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/filters/CtsNetTestCasesMaxTargetSdk31.kt diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt index 8b58e7171c..2d2f5a6b83 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt @@ -17,16 +17,21 @@ package com.android.testutils import android.os.Build +import androidx.test.InstrumentationRegistry import com.android.modules.utils.build.SdkLevel import kotlin.test.fail import org.junit.Assume.assumeTrue import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement +import java.util.regex.Pattern // TODO: Remove it when Build.VERSION_CODES.SC_V2 is available const val SC_V2 = 32 +private val MAX_TARGET_SDK_ANNOTATION_RE = Pattern.compile("MaxTargetSdk([0-9]+)$") +private val targetSdk = InstrumentationRegistry.getContext().applicationInfo.targetSdkVersion + /** * Returns true if the development SDK version of the device is in the provided range. * @@ -67,6 +72,14 @@ private fun isDevSdkUpTo(maxInclusive: Int): Boolean { } } +private fun getMaxTargetSdk(description: Description): Int? { + return description.annotations.firstNotNullOfOrNull { + MAX_TARGET_SDK_ANNOTATION_RE.matcher(it::class.simpleName).let { m -> + if (m.find()) m.group(1).toIntOrNull() else null + } + } +} + /** * A test rule to ignore tests based on the development SDK level. * @@ -108,11 +121,16 @@ class DevSdkIgnoreRule @JvmOverloads constructor( val ignoreAfter = description.getAnnotation(IgnoreAfter::class.java) val ignoreUpTo = description.getAnnotation(IgnoreUpTo::class.java) - val message = "Skipping test for build ${Build.VERSION.CODENAME} " + + val devSdkMessage = "Skipping test for build ${Build.VERSION.CODENAME} " + "with SDK ${Build.VERSION.SDK_INT}" - assumeTrue(message, isDevSdkInRange(ignoreClassUpTo, ignoreClassAfter)) - assumeTrue(message, isDevSdkInRange(ignoreUpTo?.value, ignoreAfter?.value)) - base.evaluate() + assumeTrue(devSdkMessage, isDevSdkInRange(ignoreClassUpTo, ignoreClassAfter)) + assumeTrue(devSdkMessage, isDevSdkInRange(ignoreUpTo?.value, ignoreAfter?.value)) + + val maxTargetSdk = getMaxTargetSdk(description) + if (maxTargetSdk != null) { + assumeTrue("Skipping test, target SDK $targetSdk greater than $maxTargetSdk", + targetSdk <= maxTargetSdk) + } } } -} \ No newline at end of file +} diff --git a/staticlibs/testutils/devicetests/com/android/testutils/filters/CtsNetTestCasesMaxTargetSdk31.kt b/staticlibs/testutils/devicetests/com/android/testutils/filters/CtsNetTestCasesMaxTargetSdk31.kt new file mode 100644 index 0000000000..be0103d643 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/filters/CtsNetTestCasesMaxTargetSdk31.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2020 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 com.android.testutils.filters + +/** + * Only run this test in the CtsNetTestCasesMaxTargetSdk31 suite. + */ +annotation class CtsNetTestCasesMaxTargetSdk31(val reason: String) From 0ceeb7c6d89dd3b5a479310988b0558890dfe1cb Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Mon, 30 May 2022 12:01:49 +0000 Subject: [PATCH 458/777] Remove unused filegroup The library in frameworks/base now uses the java_library defined here. Whilst here, also mark the library as available to wifi. Test: m com.android.wifi Change-Id: I36047413c749df3cabb7b284444a6f60494d3bb1 --- staticlibs/Android.bp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index e0b75c5c77..857b7c2e4e 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -260,24 +260,15 @@ java_library { ], lint: { strict_updatability_linting: true }, } -filegroup { - name: "net-utils-services-common-srcs", + +java_library { + name: "net-utils-services-common", srcs: [ "device/android/net/NetworkFactory.java", "device/android/net/NetworkFactoryImpl.java", "device/android/net/NetworkFactoryLegacyImpl.java", "device/android/net/NetworkFactoryShim.java", ], - visibility: [ - "//frameworks/base/services/net", - ], -} - -java_library { - name: "net-utils-services-common", - srcs: [ - ":net-utils-services-common-srcs", - ], sdk_version: "module_current", min_sdk_version: "30", static_libs: [ @@ -292,6 +283,7 @@ java_library { "//apex_available:platform", "com.android.bluetooth", "com.android.tethering", + "com.android.wifi", ], visibility: [ // TODO: remove after NetworkStatsService moves to the module. From 7e5409ac03c481585295b5ccb0d6f5144037047a Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Tue, 31 May 2022 14:40:42 +0900 Subject: [PATCH 459/777] Make FdEventsReader#isRunning method as protected. This allows subclasses of FdEventsReader can access isRunning() method directly without maintaining its own mechanism to check if the instance of FdEventsReader is still running. Bug: 232680956 Bug: 233191218 Test: m Change-Id: Iaaa07328f9804580cc2e413b5a50c0d69d8cfb2f --- .../device/com/android/net/module/util/FdEventsReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/device/com/android/net/module/util/FdEventsReader.java b/staticlibs/device/com/android/net/module/util/FdEventsReader.java index 71ae13d80d..ecf8e77c24 100644 --- a/staticlibs/device/com/android/net/module/util/FdEventsReader.java +++ b/staticlibs/device/com/android/net/module/util/FdEventsReader.java @@ -211,7 +211,7 @@ public abstract class FdEventsReader { return true; } - private boolean isRunning() { + protected boolean isRunning() { return (mFd != null) && mFd.valid(); } From df92fd903d7433edcd516a3009c36f282321079b Mon Sep 17 00:00:00 2001 From: Mark Chien Date: Tue, 31 May 2022 08:33:58 +0000 Subject: [PATCH 460/777] Make net-utils-device-common-bpf only available for module and tests net-utils-device-common-bpf is design for connectivity module only, change the visibility to avoid someone outside of the module use it inadvertently. Bug: 234160319 Change-Id: I3c7c48b60414f19bad8be0bda38ea5af3dc99c86 Test: TH --- staticlibs/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index e0b75c5c77..1d0f49ba9a 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -127,7 +127,6 @@ java_library { "//frameworks/libs/net/common/testutils:__subpackages__", "//packages/modules/Connectivity:__subpackages__", "//packages/modules/NetworkStack:__subpackages__", - "//frameworks/base/services/core", ], libs: [ "androidx.annotation_annotation", From 1db4a793b1cf08b7f72c5b45696aa1f7f8b703f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 31 May 2022 03:30:38 -0700 Subject: [PATCH 461/777] BpfMap: introduce resetMap(type, entries, flags) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit to replace less safe uses of BpfMap.reset(create(type, keysize, valuesize, entries, flags)) Meant to be used in tests only. Bug: Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I869f1f935bcf5d00702c42bc46d6094ea552addc --- .../native/bpf_headers/include/bpf/BpfMap.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h index bdffc0f0bb..d07d61045a 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h @@ -102,6 +102,23 @@ class BpfMap { // Function that tries to get map from a pinned path. base::Result init(const char* path); +#ifdef TEST_BPF_MAP + // due to Android SELinux limitations which prevent map creation by anyone besides the bpfloader + // this should only ever be used by test code, it is equivalent to: + // .reset(createMap(type, keysize, valuesize, max_entries, map_flags) + // TODO: derive map_flags from BpfMap vs BpfMapRO + base::Result resetMap(bpf_map_type map_type, uint32_t max_entries, uint32_t map_flags = 0) { + int map_fd = createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags); + if (map_fd < 0) { + auto err = ErrnoErrorf("Unable to create map."); + mMapFd.reset(); + return err; + }; + mMapFd.reset(map_fd); + return {}; + } +#endif + // Iterate through the map and handle each key retrieved based on the filter // without modification of map content. base::Result iterate( From d59b7e067a50c214642a079d287a18f3e3620495 Mon Sep 17 00:00:00 2001 From: markchien Date: Tue, 7 Sep 2021 19:17:55 +0800 Subject: [PATCH 462/777] Support initTestNetwork with LinkProperties This is the follow CL to fix the comment from https://android-review.googlesource.com/c/platform/frameworks/libs/net/+/1810276/3/common/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt#45 TestNetworkService only default configure interface name, link addresses, and routing. To support specify some configuration (e.g. dns server) which TestNetworkService doesn't default configuration, extend iniTestNetwork pass LinkProperties. Bug: 183166581 Test: atest EthernetTetheringTest atest ConnectivityManagerTest atest TetheringModuleTest atest CaptivePortalLoginActivityTest Change-Id: I560d95516159fa05007057614ac47591fbb3a08c --- .../android/testutils/TestNetworkTracker.kt | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt index 40731eae2f..bdea6c7242 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt @@ -23,6 +23,7 @@ import android.net.LinkAddress import android.net.Network import android.net.NetworkCapabilities import android.net.NetworkRequest +import android.net.LinkProperties import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.os.Binder @@ -32,6 +33,7 @@ import java.util.concurrent.TimeUnit /** * Create a test network based on a TUN interface with a LinkAddress. + * TODO: remove this function after fixing all the callers. * * This method will block until the test network is available. Requires * [android.Manifest.permission.CHANGE_NETWORK_STATE] and @@ -42,11 +44,13 @@ fun initTestNetwork( interfaceAddr: LinkAddress, setupTimeoutMs: Long = 10_000L ): TestNetworkTracker { - return initTestNetwork(context, listOf(interfaceAddr), setupTimeoutMs) + val lp = LinkProperties() + lp.addLinkAddress(interfaceAddr) + return initTestNetwork(context, lp, setupTimeoutMs) } /** - * Create a test network based on a TUN interface with giving LinkAddress list. + * Create a test network based on a TUN interface * * This method will block until the test network is available. Requires * [android.Manifest.permission.CHANGE_NETWORK_STATE] and @@ -54,13 +58,14 @@ fun initTestNetwork( */ fun initTestNetwork( context: Context, - linkAddrs: List, + lp: LinkProperties, setupTimeoutMs: Long = 10_000L ): TestNetworkTracker { val tnm = context.getSystemService(TestNetworkManager::class.java) - val iface = if (isAtLeastS()) tnm.createTunInterface(linkAddrs) - else tnm.createTunInterface(linkAddrs.toTypedArray()) - return TestNetworkTracker(context, iface, tnm, setupTimeoutMs) + val iface = if (isAtLeastS()) tnm.createTunInterface(lp.getLinkAddresses()) + else tnm.createTunInterface(lp.getLinkAddresses().toTypedArray()) + lp.setInterfaceName(iface.interfaceName) + return TestNetworkTracker(context, iface, tnm, lp, setupTimeoutMs) } /** @@ -72,6 +77,7 @@ class TestNetworkTracker internal constructor( val context: Context, val iface: TestNetworkInterface, val tnm: TestNetworkManager, + val lp: LinkProperties, setupTimeoutMs: Long ) { private val cm = context.getSystemService(ConnectivityManager::class.java) @@ -98,7 +104,7 @@ class TestNetworkTracker internal constructor( cm.requestNetwork(networkRequest, networkCallback) try { - tnm.setupTestNetwork(iface.interfaceName, binder) + tnm.setupTestNetwork(lp, true /* isMetered */, binder) network = networkFuture.get(setupTimeoutMs, TimeUnit.MILLISECONDS) } catch (e: Throwable) { teardown() @@ -112,4 +118,4 @@ class TestNetworkTracker internal constructor( cm.unregisterNetworkCallback(networkCallback) tnm.teardownTestNetwork(network) } -} \ No newline at end of file +} From 86ef95c0b3413c569be2c83bbf65eaeb84f25b57 Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 8 Sep 2021 22:10:25 +0800 Subject: [PATCH 463/777] Add some ipv6 packet utils 1. Allow build icmpv6 packet without ethernet header. 2. Add util for building icmpv6 echo reply. Bug: 183166581 Test: atest EthernetTetheringTest Change-Id: I79eb78c8ae4859749f5a5d8d0dc240025d8784e2 --- .../android/net/module/util/Ipv6Utils.java | 51 ++++++++++++++----- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/Ipv6Utils.java b/staticlibs/device/com/android/net/module/util/Ipv6Utils.java index fe7c89bc05..d5382215c3 100644 --- a/staticlibs/device/com/android/net/module/util/Ipv6Utils.java +++ b/staticlibs/device/com/android/net/module/util/Ipv6Utils.java @@ -20,6 +20,7 @@ import static android.system.OsConstants.IPPROTO_ICMPV6; import static com.android.net.module.util.IpUtils.icmpv6Checksum; import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REPLY_TYPE; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION; @@ -45,29 +46,23 @@ import java.nio.ByteOrder; */ public class Ipv6Utils { /** - * Build a generic ICMPv6 packet(e.g., packet used in the neighbor discovery protocol). + * Build a generic ICMPv6 packet without Ethernet header. */ - public static ByteBuffer buildIcmpv6Packet(final MacAddress srcMac, final MacAddress dstMac, - final Inet6Address srcIp, final Inet6Address dstIp, short type, short code, - final ByteBuffer... options) { - final int etherHeaderLen = Struct.getSize(EthernetHeader.class); + public static ByteBuffer buildIcmpv6Packet(final Inet6Address srcIp, final Inet6Address dstIp, + short type, short code, final ByteBuffer... options) { final int ipv6HeaderLen = Struct.getSize(Ipv6Header.class); final int icmpv6HeaderLen = Struct.getSize(Icmpv6Header.class); int payloadLen = 0; for (ByteBuffer option: options) { payloadLen += option.limit(); } - final ByteBuffer packet = ByteBuffer.allocate(etherHeaderLen + ipv6HeaderLen - + icmpv6HeaderLen + payloadLen); - final EthernetHeader ethHeader = - new EthernetHeader(dstMac, srcMac, (short) ETHER_TYPE_IPV6); + final ByteBuffer packet = ByteBuffer.allocate(ipv6HeaderLen + icmpv6HeaderLen + payloadLen); final Ipv6Header ipv6Header = new Ipv6Header((int) 0x60000000 /* version, traffic class, flowlabel */, icmpv6HeaderLen + payloadLen /* payload length */, (byte) IPPROTO_ICMPV6 /* next header */, (byte) 0xff /* hop limit */, srcIp, dstIp); final Icmpv6Header icmpv6Header = new Icmpv6Header(type, code, (short) 0 /* checksum */); - ethHeader.writeToByteBuffer(packet); ipv6Header.writeToByteBuffer(packet); icmpv6Header.writeToByteBuffer(packet); for (ByteBuffer option : options) { @@ -79,11 +74,31 @@ public class Ipv6Utils { packet.flip(); // Populate the ICMPv6 checksum field. - packet.putShort(etherHeaderLen + ipv6HeaderLen + 2, icmpv6Checksum(packet, - etherHeaderLen /* ipOffset */, - (int) (etherHeaderLen + ipv6HeaderLen) /* transportOffset */, + packet.putShort(ipv6HeaderLen + 2, icmpv6Checksum(packet, 0 /* ipOffset */, + ipv6HeaderLen /* transportOffset */, (short) (icmpv6HeaderLen + payloadLen) /* transportLen */)); return packet; + + } + + /** + * Build a generic ICMPv6 packet(e.g., packet used in the neighbor discovery protocol). + */ + public static ByteBuffer buildIcmpv6Packet(final MacAddress srcMac, final MacAddress dstMac, + final Inet6Address srcIp, final Inet6Address dstIp, short type, short code, + final ByteBuffer... options) { + final ByteBuffer payload = buildIcmpv6Packet(srcIp, dstIp, type, code, options); + + final int etherHeaderLen = Struct.getSize(EthernetHeader.class); + final ByteBuffer packet = ByteBuffer.allocate(etherHeaderLen + payload.limit()); + final EthernetHeader ethHeader = + new EthernetHeader(dstMac, srcMac, (short) ETHER_TYPE_IPV6); + + ethHeader.writeToByteBuffer(packet); + packet.put(payload); + packet.flip(); + + return packet; } /** @@ -159,4 +174,14 @@ public class Ipv6Utils { return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, (byte) ICMPV6_ECHO_REQUEST_TYPE /* type */, (byte) 0 /* code */, payload); } + + /** + * Build an ICMPv6 Echo Reply packet without ethernet header. + */ + public static ByteBuffer buildEchoReplyPacket(final Inet6Address srcIp, + final Inet6Address dstIp) { + final ByteBuffer payload = ByteBuffer.allocate(4); // ID and Sequence number may be zero. + return buildIcmpv6Packet(srcIp, dstIp, (byte) ICMPV6_ECHO_REPLY_TYPE /* type */, + (byte) 0 /* code */, payload); + } } From cb76be76a2870cd8c00ba5eb2c9447f6fcbb2d71 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 27 May 2022 23:50:25 +0900 Subject: [PATCH 464/777] Add an annotation to skip tests if the APK has target SDK > 31. This skips a test if the APK it's running in targets an SDK above 31. This allows us to add such tests to CtsNetTestCases, which is currently targeting SDK 33. By using the annotation as an include-annotation filter in AndroidTestTemplate.xml, this makes it very easy to create a clone of CtsNetTestCases that targets SDK 31 and which only runs tests annotated with this annotation. Thus, CtsNetTestCases and CtsNetTestCasesLatestSdk will run all tests that pass if target SDK is 33, and CtsNetTestCasesMaxTargetSdk31 will only run the tests that requires target SDK 31. See other CL in topic. Bug: 233553525 Test: atest CtsNetTestCasesMaxTargetSdk31:android.net.LinkPropertiesTest Test: atest CtsNetTestCasesLatestSdk:android.net.LinkPropertiesTest Change-Id: Ib5df3bbc659d6a737a846fdf57cddee002e4e9ae (cherry picked from commit 8459c69a22cf4aae0c3cce59efc05f66d564da70) Merged-In: Ib5df3bbc659d6a737a846fdf57cddee002e4e9ae --- .../com/android/testutils/DevSdkIgnoreRule.kt | 28 +++++++++++++++---- .../filters/CtsNetTestCasesMaxTargetSdk31.kt | 22 +++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/filters/CtsNetTestCasesMaxTargetSdk31.kt diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt index 8b58e7171c..2d2f5a6b83 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt @@ -17,16 +17,21 @@ package com.android.testutils import android.os.Build +import androidx.test.InstrumentationRegistry import com.android.modules.utils.build.SdkLevel import kotlin.test.fail import org.junit.Assume.assumeTrue import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement +import java.util.regex.Pattern // TODO: Remove it when Build.VERSION_CODES.SC_V2 is available const val SC_V2 = 32 +private val MAX_TARGET_SDK_ANNOTATION_RE = Pattern.compile("MaxTargetSdk([0-9]+)$") +private val targetSdk = InstrumentationRegistry.getContext().applicationInfo.targetSdkVersion + /** * Returns true if the development SDK version of the device is in the provided range. * @@ -67,6 +72,14 @@ private fun isDevSdkUpTo(maxInclusive: Int): Boolean { } } +private fun getMaxTargetSdk(description: Description): Int? { + return description.annotations.firstNotNullOfOrNull { + MAX_TARGET_SDK_ANNOTATION_RE.matcher(it::class.simpleName).let { m -> + if (m.find()) m.group(1).toIntOrNull() else null + } + } +} + /** * A test rule to ignore tests based on the development SDK level. * @@ -108,11 +121,16 @@ class DevSdkIgnoreRule @JvmOverloads constructor( val ignoreAfter = description.getAnnotation(IgnoreAfter::class.java) val ignoreUpTo = description.getAnnotation(IgnoreUpTo::class.java) - val message = "Skipping test for build ${Build.VERSION.CODENAME} " + + val devSdkMessage = "Skipping test for build ${Build.VERSION.CODENAME} " + "with SDK ${Build.VERSION.SDK_INT}" - assumeTrue(message, isDevSdkInRange(ignoreClassUpTo, ignoreClassAfter)) - assumeTrue(message, isDevSdkInRange(ignoreUpTo?.value, ignoreAfter?.value)) - base.evaluate() + assumeTrue(devSdkMessage, isDevSdkInRange(ignoreClassUpTo, ignoreClassAfter)) + assumeTrue(devSdkMessage, isDevSdkInRange(ignoreUpTo?.value, ignoreAfter?.value)) + + val maxTargetSdk = getMaxTargetSdk(description) + if (maxTargetSdk != null) { + assumeTrue("Skipping test, target SDK $targetSdk greater than $maxTargetSdk", + targetSdk <= maxTargetSdk) + } } } -} \ No newline at end of file +} diff --git a/staticlibs/testutils/devicetests/com/android/testutils/filters/CtsNetTestCasesMaxTargetSdk31.kt b/staticlibs/testutils/devicetests/com/android/testutils/filters/CtsNetTestCasesMaxTargetSdk31.kt new file mode 100644 index 0000000000..be0103d643 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/filters/CtsNetTestCasesMaxTargetSdk31.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2020 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 com.android.testutils.filters + +/** + * Only run this test in the CtsNetTestCasesMaxTargetSdk31 suite. + */ +annotation class CtsNetTestCasesMaxTargetSdk31(val reason: String) From 39e1e8844c5c47edd21acadb74f3ac03b3b2b727 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Wed, 1 Jun 2022 12:19:51 +0800 Subject: [PATCH 465/777] Ipv6UtilsTest: testBuildEchoReplyPacket Bug: 183166581 Test: atest NetworkStaticLibTests Change-Id: I2cd3a4142f3457cdf99547500ab2b93f8f96c314 --- .../android/net/module/util/Ipv6UtilsTest.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/Ipv6UtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/Ipv6UtilsTest.java index 03a1ec9f1a..4866a489f3 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/Ipv6UtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/Ipv6UtilsTest.java @@ -131,6 +131,21 @@ public class Ipv6UtilsTest { assertEquals(0, icmpv6.code); } + @Test + public void testBuildEchoReplyPacket() { + final ByteBuffer b = Ipv6Utils.buildEchoReplyPacket(LINK_LOCAL, ALL_NODES); + + Ipv6Header ipv6 = Struct.parse(Ipv6Header.class, b); + assertEquals(255, ipv6.hopLimit); + assertEquals(OsConstants.IPPROTO_ICMPV6, ipv6.nextHeader); + assertEquals(LINK_LOCAL, ipv6.srcIp); + assertEquals(ALL_NODES, ipv6.dstIp); + + Icmpv6Header icmpv6 = Struct.parse(Icmpv6Header.class, b); + assertEquals(NetworkStackConstants.ICMPV6_ECHO_REPLY_TYPE, icmpv6.type); + assertEquals(0, icmpv6.code); + } + private void assertPioEquals(PrefixInformationOption pio, String prefix, byte flags, long valid, long preferred) { assertEquals(NetworkStackConstants.ICMPV6_ND_OPTION_PIO, pio.type); From d76ea5ecea50da74e778980c1970784b722f796a Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Tue, 31 May 2022 14:40:42 +0900 Subject: [PATCH 466/777] Make FdEventsReader#isRunning method as protected. This allows subclasses of FdEventsReader can access isRunning() method directly without maintaining its own mechanism to check if the instance of FdEventsReader is still running. Bug: 232680956 Bug: 233191218 Test: m Merged-In: Iaaa07328f9804580cc2e413b5a50c0d69d8cfb2f Change-Id: Iaaa07328f9804580cc2e413b5a50c0d69d8cfb2f --- .../device/com/android/net/module/util/FdEventsReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/device/com/android/net/module/util/FdEventsReader.java b/staticlibs/device/com/android/net/module/util/FdEventsReader.java index 71ae13d80d..ecf8e77c24 100644 --- a/staticlibs/device/com/android/net/module/util/FdEventsReader.java +++ b/staticlibs/device/com/android/net/module/util/FdEventsReader.java @@ -211,7 +211,7 @@ public abstract class FdEventsReader { return true; } - private boolean isRunning() { + protected boolean isRunning() { return (mFd != null) && mFd.valid(); } From fad7ea4b71959f9341417eda666a1d9fa15efbc0 Mon Sep 17 00:00:00 2001 From: Mark Chien Date: Tue, 31 May 2022 08:33:58 +0000 Subject: [PATCH 467/777] Make net-utils-device-common-bpf only available for module and tests net-utils-device-common-bpf is design for connectivity module only, change the visibility to avoid someone outside of the module use it inadvertently. Bug: 234160319 Change-Id: I3c7c48b60414f19bad8be0bda38ea5af3dc99c86 Test: TH (cherry picked from commit 72cd1a9ef29d2b908f8ad066b84b4a0f17cc2de7) Merged-In: I3c7c48b60414f19bad8be0bda38ea5af3dc99c86 --- staticlibs/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index e0b75c5c77..1d0f49ba9a 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -127,7 +127,6 @@ java_library { "//frameworks/libs/net/common/testutils:__subpackages__", "//packages/modules/Connectivity:__subpackages__", "//packages/modules/NetworkStack:__subpackages__", - "//frameworks/base/services/core", ], libs: [ "androidx.annotation_annotation", From 1a31e3e68ead2cdd6018f34c8aeddf17704b778a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 31 May 2022 05:13:28 -0700 Subject: [PATCH 468/777] BpfMap: simplify .init() mMapFd assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this way is more obviously not calling dup_with_cloexec Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I4e1ce3b0a42ccea638332ae451e291e025d57895 --- staticlibs/native/bpf_headers/include/bpf/BpfMap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h index d07d61045a..86c0756ed3 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h @@ -196,7 +196,7 @@ class BpfMap { template base::Result BpfMap::init(const char* path) { - mMapFd = base::unique_fd(mapRetrieveRW(path)); + mMapFd.reset(mapRetrieveRW(path)); if (mMapFd == -1) { return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path); } From ed448e4640116904fd9e15defb491fb47d3579b6 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 2 Jun 2022 05:37:44 +0000 Subject: [PATCH 469/777] Run tests using DevSdkIgnoreRule Tests using DevSdkIgnoreRule are currently not being run at all, as the call to base.evaluate() was removed. Bug: 233553525 Bug: 234680138 Change-Id: Ice2d1c85f5b886b1fcd5214046ae554d6c66134b Test: atest --- .../devicetests/com/android/testutils/DevSdkIgnoreRule.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt index 2d2f5a6b83..6a073eae1f 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt @@ -131,6 +131,7 @@ class DevSdkIgnoreRule @JvmOverloads constructor( assumeTrue("Skipping test, target SDK $targetSdk greater than $maxTargetSdk", targetSdk <= maxTargetSdk) } + base.evaluate() } } } From 4fcbeb783b5f57e7d61a98a722a7435e25023adb Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 2 Jun 2022 05:37:44 +0000 Subject: [PATCH 470/777] Run tests using DevSdkIgnoreRule Tests using DevSdkIgnoreRule are currently not being run at all, as the call to base.evaluate() was removed. Bug: 233553525 Bug: 234680138 Ignore-AOSP-First: fix urgent test breakage Change-Id: Ice2d1c85f5b886b1fcd5214046ae554d6c66134b Test: atest --- .../devicetests/com/android/testutils/DevSdkIgnoreRule.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt index 2d2f5a6b83..6a073eae1f 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt @@ -131,6 +131,7 @@ class DevSdkIgnoreRule @JvmOverloads constructor( assumeTrue("Skipping test, target SDK $targetSdk greater than $maxTargetSdk", targetSdk <= maxTargetSdk) } + base.evaluate() } } } From 4f9a9c76a4fb89f19a464b174b412e2eb00ee0ed Mon Sep 17 00:00:00 2001 From: tom hsu Date: Wed, 25 May 2022 20:43:54 +0800 Subject: [PATCH 471/777] Add a test BroadCastReceiver to receive carrier Config - Add a timeout mechaism to wait for the intent of carrierconfigchange. - Add a abstract method for the condition implementation for developer. Bug: 225092753 Test: atest passed. Change-Id: Ica95c0d5bdb1c10ad8dca0f3670a9dade32bcfee --- .../testutils/TestCarrierConfigReceiver.java | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/TestCarrierConfigReceiver.java diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestCarrierConfigReceiver.java b/staticlibs/testutils/devicetests/com/android/testutils/TestCarrierConfigReceiver.java new file mode 100644 index 0000000000..ffd88fd038 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestCarrierConfigReceiver.java @@ -0,0 +1,148 @@ +/* + * 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 com.android.testutils; + +import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED; + +import static com.android.testutils.TestPermissionUtil.runAsShell; + +import static org.junit.Assert.assertTrue; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** A receiver to receive carrier config and can be awaiting the result of config change. */ +public class TestCarrierConfigReceiver extends BroadcastReceiver { + // CountDownLatch used to wait for this BroadcastReceiver to be notified of a CarrierConfig + // change. This latch will be counted down if a broadcast indicates this package has carrier + // configs, or if an Exception occurs in #onReceive. + private final CountDownLatch mLatch = new CountDownLatch(1); + private final int mSubId; + private final int mTimeoutMs; + private final PersistableBundle mRequestedConfig; + private final Matcher mMatcher; + private final Context mContext; + private final CarrierConfigManager mCarrierConfigManager; + + private volatile PersistableBundle mReceivedConfigs; + private volatile Exception mOnReceiveException; + + /** A interface for doing the carrier config match between requested and received one.*/ + public interface Matcher { + /** + * Called when a broadcast is received in order to determine whether the + * broadcast matches expectations. + * + * - If this method returns true, waitForCarrierConfigChanged returns. + * - If this method returns false, the broadcast will be ignored and + * waitForCarrierConfigChanged will continue to wait. If this method throws an exception, + * the exception will be stored and re-thrown by waitForCarrierConfigChanged. + */ + boolean matchesBroadcast(PersistableBundle config) throws Exception; + } + + public TestCarrierConfigReceiver( + Context context, + int subId, + int timeoutMs, + PersistableBundle requestedConfig, + Matcher matcher) { + mContext = context; + mSubId = subId; + mTimeoutMs = timeoutMs; + mRequestedConfig = requestedConfig; + mMatcher = matcher; + mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); + } + + @Override + public void onReceive(Context context, Intent intent) { + if (!CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) { + // Ignores this incorrect broadcast. + return; + } + + int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + if (mSubId != subId) { + // Ignores this broadcast for the wrong subId. + return; + } + mReceivedConfigs = getCarrierConfigs(subId); + + if (!CarrierConfigManager.isConfigForIdentifiedCarrier(mReceivedConfigs)) { + // Configs are not for an identified carrier (meaning they are defaults) - ignore + return; + } + + try { + if (mMatcher.matchesBroadcast(mReceivedConfigs)) { + mLatch.countDown(); + } + } catch (Exception e) { + // Throw an Exception - cache it and allow waitForCarrierConfigChanged() to throw it + mOnReceiveException = e; + mLatch.countDown(); + } + } + + private PersistableBundle getCarrierConfigs(int subId) { + return runAsShell(android.Manifest.permission.READ_PHONE_STATE, + () -> mCarrierConfigManager.getConfigForSubId(subId)); + } + + private void waitForCarrierConfigChanged() throws Exception { + try { + assertTrue("No matching carrier config broadcast received after " + mTimeoutMs + + " milliseconds.", mLatch.await(mTimeoutMs, TimeUnit.MILLISECONDS)); + // If latch is unlocked and mOnReceiveException is assigned, + // it shall throw the exception. + if (mOnReceiveException != null) { + throw mOnReceiveException; + } + } finally { + mContext.unregisterReceiver(this); + } + } + + /** + * Override the carrier config and waiting for the carrier config change. + * @return A PersistentBundle with received carrier configs. + * @throws Exception Once timout happened, it may throw a timout exception. + */ + public PersistableBundle overrideCarrierConfigForTest() throws Exception { + IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_CARRIER_CONFIG_CHANGED); + mContext.registerReceiver(this, filter); + runAsShell(android.Manifest.permission.MODIFY_PHONE_STATE, + () -> { + mCarrierConfigManager.overrideConfig(mSubId, mRequestedConfig); + mCarrierConfigManager.notifyConfigChangedForSubId(mSubId); + }); + + waitForCarrierConfigChanged(); + return mReceivedConfigs; + } +} From 926748435df11fb1e52df92d94d4e513b8ee5830 Mon Sep 17 00:00:00 2001 From: Chiachang Date: Wed, 11 May 2022 05:39:15 +0000 Subject: [PATCH 472/777] Add IPPrefix.contains() Add helper methods to check whether the specified prefix is entirely contained in this prefix, or the specified address is contained in this prefix. Bug: 184750836 Test: atest IPPrefixTest Change-Id: I838510b347ac5741c589ee8f3983111209155588 (cherry picked from commit abe2e7fab4702113df60511f4642a6277321eb20) Merged-In: I838510b347ac5741c589ee8f3983111209155588 --- .../libnetdutils/InternetAddressesTest.cpp | 187 ++++++++++++++++++ .../include/netdutils/InternetAddresses.h | 6 + 2 files changed, 193 insertions(+) diff --git a/staticlibs/netd/libnetdutils/InternetAddressesTest.cpp b/staticlibs/netd/libnetdutils/InternetAddressesTest.cpp index f75fa769ee..9e37d11f7e 100644 --- a/staticlibs/netd/libnetdutils/InternetAddressesTest.cpp +++ b/staticlibs/netd/libnetdutils/InternetAddressesTest.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include "netdutils/InternetAddresses.h" @@ -438,6 +439,192 @@ TEST(IPPrefixTest, TruncationOther) { } } +TEST(IPPrefixTest, containsPrefix) { + const struct { + const char* prefix; + const char* otherPrefix; + const bool expected; + std::string asParameters() const { + return fmt::format("prefix={}, other={}, expect={}", prefix, otherPrefix, expected); + } + } testExpectations[] = { + {"192.0.0.0/8", "192.0.0.0/8", true}, + {"192.1.0.0/16", "192.1.0.0/16", true}, + {"192.1.2.0/24", "192.1.2.0/24", true}, + {"192.1.2.3/32", "192.1.2.3/32", true}, + {"0.0.0.0/0", "192.0.0.0/8", true}, + {"0.0.0.0/0", "192.1.0.0/16", true}, + {"0.0.0.0/0", "192.1.2.0/24", true}, + {"0.0.0.0/0", "192.1.2.3/32", true}, + {"192.0.0.0/8", "192.1.0.0/16", true}, + {"192.0.0.0/8", "192.1.2.0/24", true}, + {"192.0.0.0/8", "192.1.2.5/32", true}, + {"192.1.0.0/16", "192.1.2.0/24", true}, + {"192.1.0.0/16", "192.1.3.6/32", true}, + {"192.5.6.0/24", "192.5.6.7/32", true}, + {"192.1.2.3/32", "192.1.2.0/24", false}, + {"192.1.2.3/32", "192.1.0.0/16", false}, + {"192.1.2.3/32", "192.0.0.0/8", false}, + {"192.1.2.3/32", "0.0.0.0/0", false}, + {"192.1.2.0/24", "192.1.0.0/16", false}, + {"192.1.2.0/24", "192.0.0.0/8", false}, + {"192.1.2.0/24", "0.0.0.0/0", false}, + {"192.9.0.0/16", "192.0.0.0/8", false}, + {"192.9.0.0/16", "0.0.0.0/0", false}, + {"192.0.0.0/8", "0.0.0.0/0", false}, + {"192.0.0.0/8", "191.0.0.0/8", false}, + {"191.0.0.0/8", "192.0.0.0/8", false}, + {"192.8.0.0/16", "192.7.0.0/16", false}, + {"192.7.0.0/16", "192.8.0.0/16", false}, + {"192.8.6.0/24", "192.7.5.0/24", false}, + {"192.7.5.0/24", "192.8.6.0/24", false}, + {"192.8.6.100/32", "192.8.6.200/32", false}, + {"192.8.6.200/32", "192.8.6.100/32", false}, + {"192.0.0.0/8", "192.0.0.0/12", true}, + {"192.0.0.0/12", "192.0.0.0/8", false}, + {"2001::/16", "2001::/16", true}, + {"2001:db8::/32", "2001:db8::/32", true}, + {"2001:db8:cafe::/48", "2001:db8:cafe::/48", true}, + {"2001:db8:cafe:d00d::/64", "2001:db8:cafe:d00d::/64", true}, + {"2001:db8:cafe:d00d:fec0::/80", "2001:db8:cafe:d00d:fec0::/80", true}, + {"2001:db8:cafe:d00d:fec0:de::/96", "2001:db8:cafe:d00d:fec0:de::/96", true}, + {"2001:db8:cafe:d00d:fec0:de:ac::/112", "2001:db8:cafe:d00d:fec0:de:ac::/112", true}, + {"2001:db8::cafe:0:1/128", "2001:db8::cafe:0:1/128", true}, + {"2001::/16", "2001:db8::/32", true}, + {"2001::/16", "2001:db8:cafe::/48", true}, + {"2001::/16", "2001:db8:cafe:d00d::/64", true}, + {"2001::/16", "2001:db8:cafe:d00d:fec0::/80", true}, + {"2001::/16", "2001:db8:cafe:d00d:fec0:de::/96", true}, + {"2001::/16", "2001:db8:cafe:d00d:fec0:de:ac::/112", true}, + {"2001::/16", "2001:db8:cafe:d00d:fec0:de:ac:dd/128", true}, + {"::/0", "2001::/16", true}, + {"::/0", "2001:db8::/32", true}, + {"::/0", "2001:db8:cafe::/48", true}, + {"::/0", "2001:db8:cafe:d00d::/64", true}, + {"::/0", "2001:db8:cafe:d00d:fec0::/80", true}, + {"::/0", "2001:db8:cafe:d00d:fec0:de::/96", true}, + {"::/0", "2001:db8:cafe:d00d:fec0:de:ac::/112", true}, + {"::/0", "2001:db8:cafe:d00d:fec0:de:ac:dd/128", true}, + {"2001:db8::dd/128", "2001::/16", false}, + {"2001:db8::dd/128", "2001:db8::/32", false}, + {"2001:db8::dd/128", "2001:db8:cafe::/48", false}, + {"2001:db8::dd/128", "2001:db8:cafe:d00d::/64", false}, + {"2001:db8::dd/128", "2001:db8:cafe:d00d:fec0::/80", false}, + {"2001:db8::dd/128", "2001:db8:cafe:d00d:fec0:de::/96", false}, + {"2001:db8::dd/128", "2001:db8:cafe:d00d:fec0:de:ac::/112", false}, + {"2001:db7::/32", "2001:db8::/32", false}, + {"2001:db8::/32", "2001:db7::/32", false}, + {"2001:db8:caff::/48", "2001:db8:cafe::/48", false}, + {"2001:db8:cafe::/48", "2001:db8:caff::/48", false}, + {"2001:db8:cafe:a00d::/64", "2001:db8:cafe:d00d::/64", false}, + {"2001:db8:cafe:d00d::/64", "2001:db8:cafe:a00d::/64", false}, + {"2001:db8:cafe:d00d:fec1::/80", "2001:db8:cafe:d00d:fec0::/80", false}, + {"2001:db8:cafe:d00d:fec0::/80", "2001:db8:cafe:d00d:fec1::/80", false}, + {"2001:db8:cafe:d00d:fec0:dd::/96", "2001:db8:cafe:d00d:fec0:ae::/96", false}, + {"2001:db8:cafe:d00d:fec0:ae::/96", "2001:db8:cafe:d00d:fec0:dd::/96", false}, + {"2001:db8:cafe:d00d:fec0:de:aa::/112", "2001:db8:cafe:d00d:fec0:de:ac::/112", false}, + {"2001:db8:cafe:d00d:fec0:de:ac::/112", "2001:db8:cafe:d00d:fec0:de:aa::/112", false}, + {"2001:db8::cafe:0:123/128", "2001:db8::cafe:0:456/128", false}, + {"2001:db8::cafe:0:456/128", "2001:db8::cafe:0:123/128", false}, + {"2001:db8::/32", "2001:db8::/64", true}, + {"2001:db8::/64", "2001:db8::/32", false}, + {"::/0", "0.0.0.0/0", false}, + {"::/0", "1.0.0.0/8", false}, + {"::/0", "1.2.0.0/16", false}, + {"::/0", "1.2.3.0/24", false}, + {"::/0", "1.2.3.4/32", false}, + {"2001::/16", "1.2.3.4/32", false}, + {"2001::db8::/32", "1.2.3.4/32", false}, + {"2001:db8:cafe::/48", "1.2.3.4/32", false}, + {"2001:db8:cafe:d00d::/64", "1.2.3.4/32", false}, + {"2001:db8:cafe:d00d:fec0::/80", "1.2.3.4/32", false}, + {"2001:db8:cafe:d00d:fec0:ae::/96", "1.2.3.4/32", false}, + {"2001:db8:cafe:d00d:fec0:de:aa::/112", "1.2.3.4/32", false}, + {"0.0.0.0/0", "::/0", false}, + {"0.0.0.0/0", "2001::/16", false}, + {"0.0.0.0/0", "2001::db8::/32", false}, + {"0.0.0.0/0", "2001:db8:cafe::/48", false}, + {"0.0.0.0/0", "2001:db8:cafe:d00d::/64", false}, + {"0.0.0.0/0", "2001:db8:cafe:d00d:fec0::/80", false}, + {"0.0.0.0/0", "2001:db8:cafe:d00d:fec0:ae::/96", false}, + {"0.0.0.0/0", "2001:db8:cafe:d00d:fec0:de:aa::/112", false}, + {"1.2.3.4/32", "2001:db8:cafe:d00d:fec0:de:aa::/112", false}, + {"1.2.3.0/24", "2001:db8:cafe:d00d:fec0:de:aa::/112", false}, + {"1.2.0.0/16", "2001:db8:cafe:d00d:fec0:de:aa::/112", false}, + {"1.0.0.0/8", "2001:db8:cafe:d00d:fec0:de:aa::/112", false}, + }; + + for (const auto& expectation : testExpectations) { + SCOPED_TRACE(expectation.asParameters()); + IPPrefix a = IPPrefix::forString(expectation.prefix); + IPPrefix b = IPPrefix::forString(expectation.otherPrefix); + EXPECT_EQ(expectation.expected, a.contains(b)); + } +} + +TEST(IPPrefixTest, containsAddress) { + const struct { + const char* prefix; + const char* address; + const bool expected; + std::string asParameters() const { + return fmt::format("prefix={}, address={}, expect={}", prefix, address, expected); + } + } testExpectations[] = { + {"0.0.0.0/0", "255.255.255.255", true}, + {"0.0.0.0/0", "1.2.3.4", true}, + {"0.0.0.0/0", "1.2.3.0", true}, + {"0.0.0.0/0", "1.2.0.0", true}, + {"0.0.0.0/0", "1.0.0.0", true}, + {"0.0.0.0/0", "0.0.0.0", true}, + {"0.0.0.0/0", "2001:4868:4860::8888", false}, + {"0.0.0.0/0", "::/0", false}, + {"192.0.2.0/23", "192.0.2.0", true}, + {"192.0.2.0/23", "192.0.2.43", true}, + {"192.0.2.0/23", "192.0.3.21", true}, + {"192.0.2.0/23", "192.0.0.21", false}, + {"192.0.2.0/23", "8.8.8.8", false}, + {"192.0.2.0/23", "2001:4868:4860::8888", false}, + {"192.0.2.0/23", "::/0", false}, + {"1.2.3.4/32", "1.2.3.4", true}, + {"1.2.3.4/32", "1.2.3.5", false}, + {"10.0.0.0/8", "10.2.0.0", true}, + {"10.0.0.0/8", "10.2.3.5", true}, + {"10.0.0.0/8", "10.0.0.0", true}, + {"10.0.0.0/8", "10.255.255.254", true}, + {"10.0.0.0/8", "11.0.0.0", false}, + {"::/0", "2001:db8:f000::ace:d00c", true}, + {"::/0", "2002:db8:f00::ace:d00d", true}, + {"::/0", "2001:db7:f00::ace:d00e", true}, + {"::/0", "2001:db8:f01::bad:d00d", true}, + {"::/0", "::", true}, + {"::/0", "0.0.0.0", false}, + {"::/0", "1.2.3.4", false}, + {"2001:db8:f00::ace:d00d/127", "2001:db8:f00::ace:d00c", true}, + {"2001:db8:f00::ace:d00d/127", "2001:db8:f00::ace:d00d", true}, + {"2001:db8:f00::ace:d00d/127", "2001:db8:f00::ace:d00e", false}, + {"2001:db8:f00::ace:d00d/127", "2001:db8:f00::bad:d00d", false}, + {"2001:db8:f00::ace:d00d/127", "2001:4868:4860::8888", false}, + {"2001:db8:f00::ace:d00d/127", "8.8.8.8", false}, + {"2001:db8:f00::ace:d00d/127", "0.0.0.0", false}, + {"2001:db8:f00::ace:d00d/128", "2001:db8:f00::ace:d00d", true}, + {"2001:db8:f00::ace:d00d/128", "2001:db8:f00::ace:d00c", false}, + {"2001::/16", "2001::", true}, + {"2001::/16", "2001:db8:f00::ace:d00d", true}, + {"2001::/16", "2001:db8:f00::bad:d00d", true}, + {"2001::/16", "2001::abc", true}, + {"2001::/16", "2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff", true}, + {"2001::/16", "2000::", false}, + }; + + for (const auto& expectation : testExpectations) { + SCOPED_TRACE(expectation.asParameters()); + IPPrefix a = IPPrefix::forString(expectation.prefix); + IPAddress b = IPAddress::forString(expectation.address); + EXPECT_EQ(expectation.expected, a.contains(b)); + } +} + TEST(IPPrefixTest, GamutOfOperators) { const std::vector> kExpectations{ {EQ, IPPrefix(), IPPrefix()}, diff --git a/staticlibs/netd/libnetdutils/include/netdutils/InternetAddresses.h b/staticlibs/netd/libnetdutils/include/netdutils/InternetAddresses.h index d5cbe2b466..d10cec7d5d 100644 --- a/staticlibs/netd/libnetdutils/include/netdutils/InternetAddresses.h +++ b/staticlibs/netd/libnetdutils/include/netdutils/InternetAddresses.h @@ -221,6 +221,12 @@ class IPPrefix { in_addr addr4() const noexcept { return mData.ip.v4; } in6_addr addr6() const noexcept { return mData.ip.v6; } constexpr int length() const noexcept { return mData.cidrlen; } + bool contains(const IPPrefix& other) { + return length() <= other.length() && IPPrefix(other.ip(), length()).ip() == ip(); + } + bool contains(const IPAddress& other) { + return IPPrefix(other, length()).ip() == ip(); + } bool isUninitialized() const noexcept; std::string toString() const noexcept; From 5c5fae7a8b2b7d31758aed46dec62f6c54636af1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 25 May 2022 12:58:31 -0700 Subject: [PATCH 473/777] BpfMap key/value access size verification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (beginning there of) Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ie7cf8cd51b4e272fc76a281df6231ed27955ed3f --- .../native/bpf_headers/include/bpf/BpfMap.h | 41 +++++++++++++++---- .../include/BpfSyscallWrappers.h | 30 ++++++++++++++ 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h index 86c0756ed3..a7720eabf5 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h @@ -49,16 +49,20 @@ class BpfMap { protected: // flag must be within BPF_OBJ_FLAG_MASK, ie. 0, BPF_F_RDONLY, BPF_F_WRONLY BpfMap(const char* pathname, uint32_t flags) { - int map_fd = mapRetrieve(pathname, flags); - if (map_fd >= 0) mMapFd.reset(map_fd); + mMapFd.reset(mapRetrieve(pathname, flags)); + if (mMapFd < 0) abort(); + if (isAtLeastKernelVersion(4, 14, 0)) { + if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); + if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort(); + } } public: explicit BpfMap(const char* pathname) : BpfMap(pathname, 0) {} BpfMap(bpf_map_type map_type, uint32_t max_entries, uint32_t map_flags = 0) { - int map_fd = createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags); - if (map_fd >= 0) mMapFd.reset(map_fd); + mMapFd.reset(createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags)); + if (mMapFd < 0) abort(); } base::Result getFirstKey() const { @@ -100,14 +104,16 @@ class BpfMap { } // Function that tries to get map from a pinned path. - base::Result init(const char* path); + [[clang::reinitializes]] base::Result init(const char* path); #ifdef TEST_BPF_MAP // due to Android SELinux limitations which prevent map creation by anyone besides the bpfloader // this should only ever be used by test code, it is equivalent to: // .reset(createMap(type, keysize, valuesize, max_entries, map_flags) // TODO: derive map_flags from BpfMap vs BpfMapRO - base::Result resetMap(bpf_map_type map_type, uint32_t max_entries, uint32_t map_flags = 0) { + [[clang::reinitializes]] base::Result resetMap(bpf_map_type map_type, + uint32_t max_entries, + uint32_t map_flags = 0) { int map_fd = createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags); if (map_fd < 0) { auto err = ErrnoErrorf("Unable to create map."); @@ -152,14 +158,23 @@ class BpfMap { // Move assignment operator BpfMap& operator=(BpfMap&& other) noexcept { - mMapFd = std::move(other.mMapFd); - other.reset(-1); + if (this != &other) { + mMapFd = std::move(other.mMapFd); + other.reset(); + } return *this; } void reset(base::unique_fd fd) = delete; - void reset(int fd) { mMapFd.reset(fd); } + [[clang::reinitializes]] void reset(int fd = -1) { + mMapFd.reset(fd); + if ((fd >= 0) && isAtLeastKernelVersion(4, 14, 0)) { + if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); + if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort(); + if (bpfGetFdMapFlags(mMapFd) != 0) abort(); // TODO: fix for BpfMapRO + } + } bool isValid() const { return mMapFd != -1; } @@ -200,6 +215,14 @@ base::Result BpfMap::init(const char* path) { if (mMapFd == -1) { return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path); } + if (isAtLeastKernelVersion(4, 14, 0)) { + // Normally we should return an error here instead of calling abort, + // but this cannot happen at runtime without a massive code bug (K/V type mismatch) + // and as such it's better to just blow the system up and let the developer fix it. + // Crashes are much more likely to be noticed than logs and missing functionality. + if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); + if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort(); + } return {}; } diff --git a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h index abf83daa29..4b29c4487a 100644 --- a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h +++ b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h @@ -150,6 +150,36 @@ inline int detachSingleProgram(bpf_attach_type type, const BPF_FD_TYPE prog_fd, }); } +// requires 4.14+ kernel + +#define DEFINE_BPF_GET_FD_INFO(NAME, FIELD) \ +inline int bpfGetFd ## NAME(const BPF_FD_TYPE map_fd) { \ + struct bpf_map_info map_info = {}; \ + union bpf_attr attr = { .info = { \ + .bpf_fd = BPF_FD_TO_U32(map_fd), \ + .info_len = sizeof(map_info), \ + .info = ptr_to_u64(&map_info), \ + }}; \ + int rv = bpf(BPF_OBJ_GET_INFO_BY_FD, attr); \ + if (rv) return rv; \ + if (attr.info.info_len < offsetof(bpf_map_info, FIELD) + sizeof(map_info.FIELD)) { \ + errno = EOPNOTSUPP; \ + return -1; \ + }; \ + return map_info.FIELD; \ +} + +// All 6 of these fields are already present in Linux v4.14 (even ACK 4.14-P) +// while BPF_OBJ_GET_INFO_BY_FD is not implemented at all in v4.9 (even ACK 4.9-Q) +DEFINE_BPF_GET_FD_INFO(MapType, type) // int bpfGetFdMapType(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD_INFO(MapId, id) // int bpfGetFdMapId(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD_INFO(KeySize, key_size) // int bpfGetFdKeySize(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD_INFO(ValueSize, value_size) // int bpfGetFdValueSize(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD_INFO(MaxEntries, max_entries) // int bpfGetFdMaxEntries(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD_INFO(MapFlags, map_flags) // int bpfGetFdMapFlags(const BPF_FD_TYPE map_fd) + +#undef DEFINE_BPF_GET_FD_INFO + } // namespace bpf } // namespace android From 639aa948265991dbb89520adf77908bc97dc10ec Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 6 Jun 2022 18:08:55 +0900 Subject: [PATCH 474/777] Fix TestNetworkTracker on Q setupTestNetwork only supports the LinkProperties argument starting from R. Keep overloads that specify only LinkAddresses and mark the LinkAddress initTestNetwork version as requiring R. Bug: 234879676 Test: atest CaptivePortalLoginTests on a Q device Change-Id: I66c0ad9663bffb0ec2659d67c2ca6f4d167e15a6 --- .../android/testutils/TestNetworkTracker.kt | 63 +++++++++++++++---- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt index bdea6c7242..5ae2439d9e 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt @@ -27,14 +27,18 @@ import android.net.LinkProperties import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.os.Binder +import android.os.Build +import androidx.annotation.RequiresApi +import com.android.modules.utils.build.SdkLevel.isAtLeastR import com.android.modules.utils.build.SdkLevel.isAtLeastS import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit +import kotlin.test.assertTrue /** * Create a test network based on a TUN interface with a LinkAddress. - * TODO: remove this function after fixing all the callers. * + * TODO: remove this function after fixing all the callers to use a list of LinkAddresses. * This method will block until the test network is available. Requires * [android.Manifest.permission.CHANGE_NETWORK_STATE] and * [android.Manifest.permission.MANAGE_TEST_NETWORKS]. @@ -44,9 +48,22 @@ fun initTestNetwork( interfaceAddr: LinkAddress, setupTimeoutMs: Long = 10_000L ): TestNetworkTracker { - val lp = LinkProperties() - lp.addLinkAddress(interfaceAddr) - return initTestNetwork(context, lp, setupTimeoutMs) + return initTestNetwork(context, listOf(interfaceAddr), setupTimeoutMs) +} + +/** + * Create a test network based on a TUN interface with a LinkAddress list. + * + * This method will block until the test network is available. Requires + * [android.Manifest.permission.CHANGE_NETWORK_STATE] and + * [android.Manifest.permission.MANAGE_TEST_NETWORKS]. + */ +fun initTestNetwork( + context: Context, + linkAddrs: List, + setupTimeoutMs: Long = 10_000L +): TestNetworkTracker { + return initTestNetwork(context, linkAddrs, lp = null, setupTimeoutMs = setupTimeoutMs) } /** @@ -55,17 +72,32 @@ fun initTestNetwork( * This method will block until the test network is available. Requires * [android.Manifest.permission.CHANGE_NETWORK_STATE] and * [android.Manifest.permission.MANAGE_TEST_NETWORKS]. + * + * This is only usable starting from R as [TestNetworkManager] has no support for specifying + * LinkProperties on Q. */ +@RequiresApi(Build.VERSION_CODES.R) fun initTestNetwork( context: Context, lp: LinkProperties, setupTimeoutMs: Long = 10_000L +): TestNetworkTracker { + return initTestNetwork(context, lp.linkAddresses, lp, setupTimeoutMs) +} + +private fun initTestNetwork( + context: Context, + linkAddrs: List, + lp: LinkProperties?, + setupTimeoutMs: Long = 10_000L ): TestNetworkTracker { val tnm = context.getSystemService(TestNetworkManager::class.java) - val iface = if (isAtLeastS()) tnm.createTunInterface(lp.getLinkAddresses()) - else tnm.createTunInterface(lp.getLinkAddresses().toTypedArray()) - lp.setInterfaceName(iface.interfaceName) - return TestNetworkTracker(context, iface, tnm, lp, setupTimeoutMs) + val iface = if (isAtLeastS()) tnm.createTunInterface(linkAddrs) + else tnm.createTunInterface(linkAddrs.toTypedArray()) + val lpWithIface = if (lp == null) null else LinkProperties(lp).apply { + interfaceName = iface.interfaceName + } + return TestNetworkTracker(context, iface, tnm, lpWithIface, setupTimeoutMs) } /** @@ -77,7 +109,7 @@ class TestNetworkTracker internal constructor( val context: Context, val iface: TestNetworkInterface, val tnm: TestNetworkManager, - val lp: LinkProperties, + val lp: LinkProperties?, setupTimeoutMs: Long ) { private val cm = context.getSystemService(ConnectivityManager::class.java) @@ -103,11 +135,16 @@ class TestNetworkTracker internal constructor( } cm.requestNetwork(networkRequest, networkCallback) - try { - tnm.setupTestNetwork(lp, true /* isMetered */, binder) - network = networkFuture.get(setupTimeoutMs, TimeUnit.MILLISECONDS) + network = try { + if (lp != null) { + assertTrue(isAtLeastR(), "Cannot specify TestNetwork LinkProperties before R") + tnm.setupTestNetwork(lp, true /* isMetered */, binder) + } else { + tnm.setupTestNetwork(iface.interfaceName, binder) + } + networkFuture.get(setupTimeoutMs, TimeUnit.MILLISECONDS) } catch (e: Throwable) { - teardown() + cm.unregisterNetworkCallback(networkCallback) throw e } From e420f4550474d9121bd0a596158aca0388139d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 31 May 2022 03:30:38 -0700 Subject: [PATCH 475/777] BpfMap: introduce resetMap(type, entries, flags) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit to replace less safe uses of BpfMap.reset(create(type, keysize, valuesize, entries, flags)) Meant to be used in tests only. Bug: 235286176 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I869f1f935bcf5d00702c42bc46d6094ea552addc (cherry picked from commit d2dec08c73b2bc1dd2a3969ccb504a59e9cb223f) Merged-In: I869f1f935bcf5d00702c42bc46d6094ea552addc --- .../native/bpf_headers/include/bpf/BpfMap.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h index bdffc0f0bb..d07d61045a 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h @@ -102,6 +102,23 @@ class BpfMap { // Function that tries to get map from a pinned path. base::Result init(const char* path); +#ifdef TEST_BPF_MAP + // due to Android SELinux limitations which prevent map creation by anyone besides the bpfloader + // this should only ever be used by test code, it is equivalent to: + // .reset(createMap(type, keysize, valuesize, max_entries, map_flags) + // TODO: derive map_flags from BpfMap vs BpfMapRO + base::Result resetMap(bpf_map_type map_type, uint32_t max_entries, uint32_t map_flags = 0) { + int map_fd = createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags); + if (map_fd < 0) { + auto err = ErrnoErrorf("Unable to create map."); + mMapFd.reset(); + return err; + }; + mMapFd.reset(map_fd); + return {}; + } +#endif + // Iterate through the map and handle each key retrieved based on the filter // without modification of map content. base::Result iterate( From ecb17d3fd62f6ea7117a7d1f098034288072f224 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Sat, 4 Jun 2022 20:21:37 +0900 Subject: [PATCH 476/777] Add handlePacketReadError method in FdEventsReader. This method allows the subclasses of FdEventsReader to decide whether it should stop reading packet and unregister the fd immediately or just ignore when some specific error other than EAGAIN or EINTR happens such as ENOBUFS. Bug: 232680956 Test: m Change-Id: I19ee9390e78dcd0140e45fed75a1a36942450407 --- .../net/module/util/FdEventsReader.java | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/FdEventsReader.java b/staticlibs/device/com/android/net/module/util/FdEventsReader.java index ecf8e77c24..4825992f39 100644 --- a/staticlibs/device/com/android/net/module/util/FdEventsReader.java +++ b/staticlibs/device/com/android/net/module/util/FdEventsReader.java @@ -69,6 +69,7 @@ import java.io.IOException; * @param the type of the buffer used to read data. */ public abstract class FdEventsReader { + private static final String TAG = FdEventsReader.class.getSimpleName(); private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR; private static final int UNREGISTER_THIS_FD = 0; @@ -166,6 +167,18 @@ public abstract class FdEventsReader { */ protected void handlePacket(@NonNull BufferType recvbuf, int length) {} + /** + * Called by the subclasses of FdEventsReader, decide whether it should stop reading packet or + * just ignore the specific error other than EAGAIN or EINTR. + * + * @return {@code true} if this FdEventsReader should stop reading from the socket. + * {@code false} if it should continue. + */ + protected boolean handleReadError(@NonNull ErrnoException e) { + logError("readPacket error: ", e); + return true; // by default, stop reading on any error. + } + /** * Called by the main loop to log errors. In some cases |e| may be null. */ @@ -234,8 +247,10 @@ public abstract class FdEventsReader { } else if (e.errno == OsConstants.EINTR) { continue; } else { - if (isRunning()) logError("readPacket error: ", e); - break; + if (!isRunning()) break; + final boolean shouldStop = handleReadError(e); + if (shouldStop) break; + continue; } } catch (Exception e) { if (isRunning()) logError("readPacket error: ", e); @@ -246,7 +261,7 @@ public abstract class FdEventsReader { handlePacket(mBuffer, bytesRead); } catch (Exception e) { logError("handlePacket error: ", e); - Log.wtf(FdEventsReader.class.getSimpleName(), "Error handling packet", e); + Log.wtf(TAG, "Error handling packet", e); } } From 158d6ce06dfe0b74ed5f352d096846acaaaff6fd Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Sat, 4 Jun 2022 20:21:37 +0900 Subject: [PATCH 477/777] Add handlePacketReadError method in FdEventsReader. This method allows the subclasses of FdEventsReader to decide whether it should stop reading packet and unregister the fd immediately or just ignore when some specific error other than EAGAIN or EINTR happens such as ENOBUFS. Bug: 232680956 Test: m Merged-In: I19ee9390e78dcd0140e45fed75a1a36942450407 Change-Id: I19ee9390e78dcd0140e45fed75a1a36942450407 --- .../net/module/util/FdEventsReader.java | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/FdEventsReader.java b/staticlibs/device/com/android/net/module/util/FdEventsReader.java index ecf8e77c24..4825992f39 100644 --- a/staticlibs/device/com/android/net/module/util/FdEventsReader.java +++ b/staticlibs/device/com/android/net/module/util/FdEventsReader.java @@ -69,6 +69,7 @@ import java.io.IOException; * @param the type of the buffer used to read data. */ public abstract class FdEventsReader { + private static final String TAG = FdEventsReader.class.getSimpleName(); private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR; private static final int UNREGISTER_THIS_FD = 0; @@ -166,6 +167,18 @@ public abstract class FdEventsReader { */ protected void handlePacket(@NonNull BufferType recvbuf, int length) {} + /** + * Called by the subclasses of FdEventsReader, decide whether it should stop reading packet or + * just ignore the specific error other than EAGAIN or EINTR. + * + * @return {@code true} if this FdEventsReader should stop reading from the socket. + * {@code false} if it should continue. + */ + protected boolean handleReadError(@NonNull ErrnoException e) { + logError("readPacket error: ", e); + return true; // by default, stop reading on any error. + } + /** * Called by the main loop to log errors. In some cases |e| may be null. */ @@ -234,8 +247,10 @@ public abstract class FdEventsReader { } else if (e.errno == OsConstants.EINTR) { continue; } else { - if (isRunning()) logError("readPacket error: ", e); - break; + if (!isRunning()) break; + final boolean shouldStop = handleReadError(e); + if (shouldStop) break; + continue; } } catch (Exception e) { if (isRunning()) logError("readPacket error: ", e); @@ -246,7 +261,7 @@ public abstract class FdEventsReader { handlePacket(mBuffer, bytesRead); } catch (Exception e) { logError("handlePacket error: ", e); - Log.wtf(FdEventsReader.class.getSimpleName(), "Error handling packet", e); + Log.wtf(TAG, "Error handling packet", e); } } From 023ad6a0878496ab0f54bb6ec52eddd29f5af2f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 9 Jun 2022 22:33:34 +0000 Subject: [PATCH 478/777] fix sign of error to be positive when passed to strerror() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we see: E TcUtils : NLMSG_ERROR message return error: -2 E ConnectivityService: TcUtils.tcFilterAddDevIngressPolice(ifaceIndex=6, PRIO_POLICE, ETH_P_ALL, rateInBytesPerSecond=2500000, bpfProgPath=/sys/fs/bpf/netd_shared/prog_netd_schedact_ingress_account) failure: E ConnectivityService: java.io.IOException: com_android_net_module_util_TcUtils_tcFilterAddDevIngressPolice error: : Unknown error -2 Bug: 231495412 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ib49171e13d06082a37cbb12def1285d8875b5279 --- .../bpfmapjni/com_android_net_module_util_TcUtils.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp index 073a46f1fa..cb06afbda3 100644 --- a/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp +++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_TcUtils.cpp @@ -34,7 +34,7 @@ static jboolean com_android_net_module_util_TcUtils_isEthernet(JNIEnv *env, int error = isEthernet(interface.c_str(), result); if (error) { throwIOException( - env, "com_android_net_module_util_TcUtils_isEthernet error: ", error); + env, "com_android_net_module_util_TcUtils_isEthernet error: ", -error); } // result is not touched when error is returned; leave false. return result; @@ -50,7 +50,7 @@ static void com_android_net_module_util_TcUtils_tcFilterAddDevBpf( if (error) { throwIOException( env, - "com_android_net_module_util_TcUtils_tcFilterAddDevBpf error: ", error); + "com_android_net_module_util_TcUtils_tcFilterAddDevBpf error: ", -error); } } @@ -68,7 +68,7 @@ static void com_android_net_module_util_TcUtils_tcFilterAddDevIngressPolice( throwIOException(env, "com_android_net_module_util_TcUtils_" "tcFilterAddDevIngressPolice error: ", - error); + -error); } } @@ -80,7 +80,7 @@ static void com_android_net_module_util_TcUtils_tcFilterDelDev( if (error) { throwIOException( env, - "com_android_net_module_util_TcUtils_tcFilterDelDev error: ", error); + "com_android_net_module_util_TcUtils_tcFilterDelDev error: ", -error); } } @@ -92,7 +92,7 @@ static void com_android_net_module_util_TcUtils_tcQdiscAddDevClsact(JNIEnv *env, if (error) { throwIOException( env, - "com_android_net_module_util_TcUtils_tcQdiscAddDevClsact error: ", error); + "com_android_net_module_util_TcUtils_tcQdiscAddDevClsact error: ", -error); } } From 09ccd22097486c40bd305f7939ae8cf8327b5cdc Mon Sep 17 00:00:00 2001 From: Mark Chien Date: Fri, 10 Jun 2022 06:41:56 +0000 Subject: [PATCH 479/777] Revert "Add a test BroadCastReceiver to receive carrier Config" Revert "[Tethering] Add MTS method to TetheringManagerTest." Revert submission 2046446-tethering_entitlement_MTS Reason for revert: This test never pass. Now tethering module release is blocked by MTS fail. TH don't catch this probably because b/234680138 cause this test don't actually run at the moment. Reverted Changes: Ica95c0d5b:Add a test BroadCastReceiver to receive carrier Co... I5f758fe0c:[Tethering] Add MTS method to TetheringManagerTest... Change-Id: I2606b105ad955958b555dcd7d03f5371e49cd22a --- .../testutils/TestCarrierConfigReceiver.java | 148 ------------------ 1 file changed, 148 deletions(-) delete mode 100644 staticlibs/testutils/devicetests/com/android/testutils/TestCarrierConfigReceiver.java diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestCarrierConfigReceiver.java b/staticlibs/testutils/devicetests/com/android/testutils/TestCarrierConfigReceiver.java deleted file mode 100644 index ffd88fd038..0000000000 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestCarrierConfigReceiver.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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 com.android.testutils; - -import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED; - -import static com.android.testutils.TestPermissionUtil.runAsShell; - -import static org.junit.Assert.assertTrue; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.PersistableBundle; -import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionManager; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** A receiver to receive carrier config and can be awaiting the result of config change. */ -public class TestCarrierConfigReceiver extends BroadcastReceiver { - // CountDownLatch used to wait for this BroadcastReceiver to be notified of a CarrierConfig - // change. This latch will be counted down if a broadcast indicates this package has carrier - // configs, or if an Exception occurs in #onReceive. - private final CountDownLatch mLatch = new CountDownLatch(1); - private final int mSubId; - private final int mTimeoutMs; - private final PersistableBundle mRequestedConfig; - private final Matcher mMatcher; - private final Context mContext; - private final CarrierConfigManager mCarrierConfigManager; - - private volatile PersistableBundle mReceivedConfigs; - private volatile Exception mOnReceiveException; - - /** A interface for doing the carrier config match between requested and received one.*/ - public interface Matcher { - /** - * Called when a broadcast is received in order to determine whether the - * broadcast matches expectations. - * - * - If this method returns true, waitForCarrierConfigChanged returns. - * - If this method returns false, the broadcast will be ignored and - * waitForCarrierConfigChanged will continue to wait. If this method throws an exception, - * the exception will be stored and re-thrown by waitForCarrierConfigChanged. - */ - boolean matchesBroadcast(PersistableBundle config) throws Exception; - } - - public TestCarrierConfigReceiver( - Context context, - int subId, - int timeoutMs, - PersistableBundle requestedConfig, - Matcher matcher) { - mContext = context; - mSubId = subId; - mTimeoutMs = timeoutMs; - mRequestedConfig = requestedConfig; - mMatcher = matcher; - mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); - } - - @Override - public void onReceive(Context context, Intent intent) { - if (!CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) { - // Ignores this incorrect broadcast. - return; - } - - int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - if (mSubId != subId) { - // Ignores this broadcast for the wrong subId. - return; - } - mReceivedConfigs = getCarrierConfigs(subId); - - if (!CarrierConfigManager.isConfigForIdentifiedCarrier(mReceivedConfigs)) { - // Configs are not for an identified carrier (meaning they are defaults) - ignore - return; - } - - try { - if (mMatcher.matchesBroadcast(mReceivedConfigs)) { - mLatch.countDown(); - } - } catch (Exception e) { - // Throw an Exception - cache it and allow waitForCarrierConfigChanged() to throw it - mOnReceiveException = e; - mLatch.countDown(); - } - } - - private PersistableBundle getCarrierConfigs(int subId) { - return runAsShell(android.Manifest.permission.READ_PHONE_STATE, - () -> mCarrierConfigManager.getConfigForSubId(subId)); - } - - private void waitForCarrierConfigChanged() throws Exception { - try { - assertTrue("No matching carrier config broadcast received after " + mTimeoutMs - + " milliseconds.", mLatch.await(mTimeoutMs, TimeUnit.MILLISECONDS)); - // If latch is unlocked and mOnReceiveException is assigned, - // it shall throw the exception. - if (mOnReceiveException != null) { - throw mOnReceiveException; - } - } finally { - mContext.unregisterReceiver(this); - } - } - - /** - * Override the carrier config and waiting for the carrier config change. - * @return A PersistentBundle with received carrier configs. - * @throws Exception Once timout happened, it may throw a timout exception. - */ - public PersistableBundle overrideCarrierConfigForTest() throws Exception { - IntentFilter filter = new IntentFilter(); - filter.addAction(ACTION_CARRIER_CONFIG_CHANGED); - mContext.registerReceiver(this, filter); - runAsShell(android.Manifest.permission.MODIFY_PHONE_STATE, - () -> { - mCarrierConfigManager.overrideConfig(mSubId, mRequestedConfig); - mCarrierConfigManager.notifyConfigChangedForSubId(mSubId); - }); - - waitForCarrierConfigChanged(); - return mReceivedConfigs; - } -} From 0d19b66c9696a19540b0449c8e28213f1215260c Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 10 Jun 2022 22:51:15 +0900 Subject: [PATCH 480/777] Fix DevSdkIgnoreRule target SDK annotation processing. The code added to DevSdkIgnoreRule to process the max target SDK annotations in aosp/2110064 was incorrect. It is trying to match the annotation name, but ::class.simpleName returns something like Proxy$3, not the actual name of the annotation. Use annotationClass.simpleName instead, which actually works. This was not caught in aosp/2110064 because it contained an even worse error which broke DevSdkIgnoreRule completely. That was fixed in aosp/2114653. Bug: 233553525 Test: LinkPropertiesTest#testExcludedRoutesDisabled passes on user build Change-Id: If9220e5ef00fafea556604b251b2106d15d063f8 --- .../devicetests/com/android/testutils/DevSdkIgnoreRule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt index 6a073eae1f..3fcf801152 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt @@ -74,7 +74,7 @@ private fun isDevSdkUpTo(maxInclusive: Int): Boolean { private fun getMaxTargetSdk(description: Description): Int? { return description.annotations.firstNotNullOfOrNull { - MAX_TARGET_SDK_ANNOTATION_RE.matcher(it::class.simpleName).let { m -> + MAX_TARGET_SDK_ANNOTATION_RE.matcher(it.annotationClass.simpleName).let { m -> if (m.find()) m.group(1).toIntOrNull() else null } } From 0b2781b5ecd863d417adc04c60023c48e2cc55ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 10 Jun 2022 18:59:54 +0000 Subject: [PATCH 481/777] add ALOGW/ALOGI/ALOGD to logging.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I99c7892f10f89a81e0c18838328aa7f945a3817a --- staticlibs/native/tcutils/logging.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/staticlibs/native/tcutils/logging.h b/staticlibs/native/tcutils/logging.h index 70604b30af..7ed8f66a5c 100644 --- a/staticlibs/native/tcutils/logging.h +++ b/staticlibs/native/tcutils/logging.h @@ -32,4 +32,25 @@ static inline void ALOGE(const char *fmt...) { va_end(args); } +static inline void ALOGW(const char *fmt...) { + va_list args; + va_start(args, fmt); + __android_log_vprint(ANDROID_LOG_WARN, LOG_TAG, fmt, args); + va_end(args); +} + +static inline void ALOGI(const char *fmt...) { + va_list args; + va_start(args, fmt); + __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, fmt, args); + va_end(args); +} + +static inline void ALOGD(const char *fmt...) { + va_list args; + va_start(args, fmt); + __android_log_vprint(ANDROID_LOG_DEBUG, LOG_TAG, fmt, args); + va_end(args); +} + } From e8dceddeec89515ee0ea53e6ad3d92bb5d63d623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 9 Jun 2022 23:27:32 +0000 Subject: [PATCH 482/777] enable NETLINK_EXT_ACK extended error reporting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (we don't yet do anything with it, but at least in strace we should now see more detailed errors from the kernel) Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I6a34a0e7e866bbde41daef23870ad90dceee6ded --- staticlibs/native/tcutils/tcutils.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/staticlibs/native/tcutils/tcutils.cpp b/staticlibs/native/tcutils/tcutils.cpp index 144a4c940a..4101885f6d 100644 --- a/staticlibs/native/tcutils/tcutils.cpp +++ b/staticlibs/native/tcutils/tcutils.cpp @@ -386,6 +386,12 @@ int sendAndProcessNetlinkResponse(const void *req, int len) { return -error; } + if (setsockopt(fd, SOL_NETLINK, NETLINK_EXT_ACK, &on, sizeof(on))) { + int error = errno; + ALOGW("setsockopt(fd, SOL_NETLINK, NETLINK_EXT_ACK, 1): %d", error); + // will fail on 4.9 kernels so don't: return -error; + } + // this is needed to get valid strace netlink parsing, it allocates the pid if (bind(fd, (const struct sockaddr *)&KERNEL_NLADDR, sizeof(KERNEL_NLADDR))) { From 823fe5bbda0a2d13896135bf22dd2d9fd6ba7421 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 10 Jun 2022 22:51:15 +0900 Subject: [PATCH 483/777] Fix DevSdkIgnoreRule target SDK annotation processing. The code added to DevSdkIgnoreRule to process the max target SDK annotations in aosp/2110064 was incorrect. It is trying to match the annotation name, but ::class.simpleName returns something like Proxy$3, not the actual name of the annotation. Use annotationClass.simpleName instead, which actually works. This was not caught in aosp/2110064 because it contained an even worse error which broke DevSdkIgnoreRule completely. That was fixed in aosp/2114653. Bug: 233553525 Test: LinkPropertiesTest#testExcludedRoutesDisabled passes on user build Change-Id: If9220e5ef00fafea556604b251b2106d15d063f8 (cherry picked from commit 3af9b34bad03ac0a7ad061bac64a1ace9e1aac7a) Merged-In: If9220e5ef00fafea556604b251b2106d15d063f8 --- .../devicetests/com/android/testutils/DevSdkIgnoreRule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt index 6a073eae1f..3fcf801152 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt @@ -74,7 +74,7 @@ private fun isDevSdkUpTo(maxInclusive: Int): Boolean { private fun getMaxTargetSdk(description: Description): Int? { return description.annotations.firstNotNullOfOrNull { - MAX_TARGET_SDK_ANNOTATION_RE.matcher(it::class.simpleName).let { m -> + MAX_TARGET_SDK_ANNOTATION_RE.matcher(it.annotationClass.simpleName).let { m -> if (m.find()) m.group(1).toIntOrNull() else null } } From cf4b58f98f9da41c2e89d46d6c78bd777710b800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Mon, 13 Jun 2022 17:38:12 -0700 Subject: [PATCH 484/777] BpfMap - add BpfMapRO.init() support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Really we need to fix the inheritance to make BpfMapRO the parent class of BpfMap: but that's a far more difficult thing to do, so in the short term we punt like this. This makes BpfMapRO a little bit more usable, and allows a slow transition across the codebase... Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I1c5112db70e9e523c113cba536fbe19422b4d3f3 --- .../native/bpf_headers/include/bpf/BpfMap.h | 47 ++++++++++++------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h index 0054753b04..afb6fdf6a0 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h @@ -103,8 +103,29 @@ class BpfMap { return {}; } + protected: + [[clang::reinitializes]] base::Result init(const char* path, int fd) { + mMapFd.reset(fd); + if (mMapFd == -1) { + return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path); + } + if (isAtLeastKernelVersion(4, 14, 0)) { + // Normally we should return an error here instead of calling abort, + // but this cannot happen at runtime without a massive code bug (K/V type mismatch) + // and as such it's better to just blow the system up and let the developer fix it. + // Crashes are much more likely to be noticed than logs and missing functionality. + if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); + if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort(); + } + return {}; + } + + public: // Function that tries to get map from a pinned path. - [[clang::reinitializes]] base::Result init(const char* path); + [[clang::reinitializes]] base::Result init(const char* path) { + return init(path, mapRetrieveRW(path)); + } + #ifdef BPF_MAP_MAKE_VISIBLE_FOR_TESTING // due to Android SELinux limitations which prevent map creation by anyone besides the bpfloader @@ -209,23 +230,6 @@ class BpfMap { base::unique_fd mMapFd; }; -template -base::Result BpfMap::init(const char* path) { - mMapFd.reset(mapRetrieveRW(path)); - if (mMapFd == -1) { - return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path); - } - if (isAtLeastKernelVersion(4, 14, 0)) { - // Normally we should return an error here instead of calling abort, - // but this cannot happen at runtime without a massive code bug (K/V type mismatch) - // and as such it's better to just blow the system up and let the developer fix it. - // Crashes are much more likely to be noticed than logs and missing functionality. - if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); - if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort(); - } - return {}; -} - template base::Result BpfMap::iterate( const std::function(const Key& key, const BpfMap& map)>& @@ -292,8 +296,15 @@ base::Result BpfMap::iterateWithValue( template class BpfMapRO : public BpfMap { public: + BpfMapRO() {}; + explicit BpfMapRO(const char* pathname) : BpfMap(pathname, BPF_F_RDONLY) {} + + // Function that tries to get map from a pinned path. + [[clang::reinitializes]] base::Result init(const char* path) { + return BpfMap::init(path, mapRetrieveRO(path)); + } }; } // namespace bpf From 4b1b4090de2a1de2c474359e2a011a51bbde385a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Mon, 13 Jun 2022 18:33:27 -0700 Subject: [PATCH 485/777] TEST_BPF_MAP -> BPF_MAP_MAKE_VISIBLE_FOR_TESTING MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per request of Lorenzo on: https://googleplex-android-review.git.corp.google.com/c/platform/frameworks/libs/net/+/18694820 https://googleplex-android-review.git.corp.google.com/c/platform/packages/modules/Connectivity/+/18695355 Although he'd suggested 'BPF_MAP_TEST_ONLY', but I think this is even clearer. Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ie1185a61e80abe94e19903f6aa66bb1ad29ce2f4 --- staticlibs/native/bpf_headers/include/bpf/BpfMap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h index a7720eabf5..0054753b04 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h @@ -106,7 +106,7 @@ class BpfMap { // Function that tries to get map from a pinned path. [[clang::reinitializes]] base::Result init(const char* path); -#ifdef TEST_BPF_MAP +#ifdef BPF_MAP_MAKE_VISIBLE_FOR_TESTING // due to Android SELinux limitations which prevent map creation by anyone besides the bpfloader // this should only ever be used by test code, it is equivalent to: // .reset(createMap(type, keysize, valuesize, max_entries, map_flags) From 8e74aa9aa43d16ce3ac1d7d8845622240f3be765 Mon Sep 17 00:00:00 2001 From: chiachangwang Date: Tue, 14 Jun 2022 11:01:40 +0000 Subject: [PATCH 486/777] Add mockService method. Add a mockService method to support the common usage that requires mocking the system service from with a mock context. Bug: 231373589 Test: atest FrameworksNetTests Change-Id: Id17af4027a019834c1779be550f4329b1edd6809 --- .../com/android/testutils/ContextUtils.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ContextUtils.kt b/staticlibs/testutils/devicetests/com/android/testutils/ContextUtils.kt index 814a75b4c3..936b568292 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/ContextUtils.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/ContextUtils.kt @@ -53,3 +53,15 @@ fun mockContextAsUser(context: Context, functor: ((Context, UserHandle) -> Unit) asUserContext }.`when`(context).createContextAsUser(any(UserHandle::class.java), anyInt() /* flags */) } + +/** + * Helper function to mock the desired system service. + * + * @param context the mock context to set up the getSystemService and getSystemServiceName. + * @param clazz the system service class that intents to mock. + * @param service the system service name that intents to mock. + */ +fun mockService(context: Context, clazz: Class, name: String, service: T) { + doReturn(service).`when`(context).getSystemService(name) + doReturn(name).`when`(context).getSystemServiceName(clazz) +} \ No newline at end of file From 908a34fe478e6d4d5f911f3b0662807967d12b52 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 15 Jun 2022 19:51:36 +0900 Subject: [PATCH 487/777] Sync up the latest change in NetworkMonitor. There are two copies of NetlinkMonitor, one resides inside NetworkStack module and it's shared with Tethering module via filegroup, the other one is in frameworks/libs/net. Since this class is shared among of modules we should just maintain it in frameworks/libs/net and remove the duplicated one from NetworkStack module. Sync up the latest change in NetworkMonitor made in NetworkStack. Bug: 235901424 Test: m Change-Id: Ia221f35cfd6764a3e106873e476258cd3298a75a --- .../net/module/util/ip/NetlinkMonitor.java | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/staticlibs/device/com/android/net/module/util/ip/NetlinkMonitor.java b/staticlibs/device/com/android/net/module/util/ip/NetlinkMonitor.java index 85898761ab..942aaf1267 100644 --- a/staticlibs/device/com/android/net/module/util/ip/NetlinkMonitor.java +++ b/staticlibs/device/com/android/net/module/util/ip/NetlinkMonitor.java @@ -18,6 +18,7 @@ package com.android.net.module.util.ip; import static android.net.util.SocketUtils.makeNetlinkSocketAddress; import static android.system.OsConstants.AF_NETLINK; +import static android.system.OsConstants.ENOBUFS; import static android.system.OsConstants.SOCK_DGRAM; import static android.system.OsConstants.SOCK_NONBLOCK; import static android.system.OsConstants.SOL_SOCKET; @@ -102,7 +103,11 @@ public class NetlinkMonitor extends PacketReader { try { fd = Os.socket(AF_NETLINK, SOCK_DGRAM | SOCK_NONBLOCK, mFamily); if (mSockRcvbufSize != DEFAULT_SOCKET_RECV_BUFSIZE) { - Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, mSockRcvbufSize); + try { + Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, mSockRcvbufSize); + } catch (ErrnoException e) { + Log.wtf(mTag, "Failed to set SO_RCVBUF to " + mSockRcvbufSize, e); + } } Os.bind(fd, makeNetlinkSocketAddress(0, mBindGroups)); NetlinkSocket.connectToKernel(fd); @@ -148,6 +153,32 @@ public class NetlinkMonitor extends PacketReader { } } + @Override + protected void logError(String msg, Exception e) { + mLog.e(msg, e); + } + + // Ignoring ENOBUFS may miss any important netlink messages, there are some messages which + // cannot be recovered by dumping current state once missed since kernel doesn't keep state + // for it. In addition, dumping current state will not result in any RTM_DELxxx messages, so + // reconstructing current state from a dump will be difficult. However, for those netlink + // messages don't cause any state changes, e.g. RTM_NEWLINK with current link state, maybe + // it's okay to ignore them, because these netlink messages won't cause any changes on the + // LinkProperties. Given the above trade-offs, try to ignore ENOBUFS and that's similar to + // what netd does today. + // + // TODO: log metrics when ENOBUFS occurs, or even force a disconnect, it will help see how + // often this error occurs on fields with the associated socket receive buffer size. + @Override + protected boolean handleReadError(ErrnoException e) { + logError("readPacket error: ", e); + if (e.errno == ENOBUFS) { + Log.wtf(mTag, "Errno: ENOBUFS"); + return false; + } + return true; + } + // TODO: move NetworkStackUtils to frameworks/libs/net for NetworkStackUtils#closeSocketQuietly. private void closeSocketQuietly(FileDescriptor fd) { try { From 747ba67de634628e36ab7842604248cc3c3ff691 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 15 Jun 2022 23:39:12 +0900 Subject: [PATCH 488/777] Add an int constant for CLAT_MARK and freeze INetd v10. Test: m Bug: 235778483 Change-Id: I45a0bd6be39022a913bc6cff8216df0b6559cd4b --- staticlibs/netd/Android.bp | 14 +- .../aidl_api/netd_aidl_interface/10/.hash | 1 + .../10/android/net/INetd.aidl | 222 ++++++++++++++++++ .../net/INetdUnsolicitedEventListener.aidl | 48 ++++ .../net/InterfaceConfigurationParcel.aidl | 42 ++++ .../10/android/net/MarkMaskParcel.aidl | 39 +++ .../10/android/net/NativeNetworkConfig.aidl | 44 ++++ .../10/android/net/NativeNetworkType.aidl | 39 +++ .../10/android/net/NativeVpnType.aidl | 41 ++++ .../10/android/net/RouteInfoParcel.aidl | 40 ++++ .../10/android/net/TetherConfigParcel.aidl | 39 +++ .../android/net/TetherOffloadRuleParcel.aidl | 44 ++++ .../10/android/net/TetherStatsParcel.aidl | 43 ++++ .../10/android/net/UidRangeParcel.aidl | 40 ++++ .../net/netd/aidl/NativeUidRangeConfig.aidl | 41 ++++ .../current/android/net/INetd.aidl | 1 + staticlibs/netd/binder/android/net/INetd.aidl | 5 + 17 files changed, 738 insertions(+), 5 deletions(-) create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeNetworkConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeNetworkType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeVpnType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/netd/aidl/NativeUidRangeConfig.aidl diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index cfa9bbb3d9..a648941a36 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -21,7 +21,7 @@ java_library { sdk_version: "system_current", min_sdk_version: "29", static_libs: [ - "netd_aidl_interface-V9-java", + "netd_aidl_interface-V10-java", ], apex_available: [ "//apex_available:platform", // used from services.net @@ -44,7 +44,7 @@ cc_library_static { cc_library_static { name: "netd_aidl_interface-lateststable-ndk", whole_static_libs: [ - "netd_aidl_interface-V9-ndk", + "netd_aidl_interface-V10-ndk", ], apex_available: [ "com.android.resolv", @@ -57,18 +57,18 @@ cc_library_static { cc_library_static { name: "netd_aidl_interface-lateststable-cpp", whole_static_libs: [ - "netd_aidl_interface-V9-cpp", + "netd_aidl_interface-V10-cpp", ], } cc_defaults { name: "netd_aidl_interface_lateststable_cpp_static", - static_libs: ["netd_aidl_interface-V9-cpp"], + static_libs: ["netd_aidl_interface-V10-cpp"], } cc_defaults { name: "netd_aidl_interface_lateststable_cpp_shared", - shared_libs: ["netd_aidl_interface-V9-cpp"], + shared_libs: ["netd_aidl_interface-V10-cpp"], } aidl_interface { @@ -153,6 +153,10 @@ aidl_interface { version: "9", imports: [], }, + { + version: "10", + imports: [], + }, ], diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/10/.hash new file mode 100644 index 0000000000..6ec3613559 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/.hash @@ -0,0 +1 @@ +3943383e838f39851675e3640fcdf27b42f8c9fc diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/INetd.aidl new file mode 100644 index 0000000000..e671fdb781 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/INetd.aidl @@ -0,0 +1,222 @@ +/** + * Copyright (c) 2016, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreatePhysical(int netId, int permission); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + void networkCreate(in android.net.NativeNetworkConfig config); + void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int CLAT_MARK = -559038041; + const int LOCAL_NET_ID = 99; + const int DUMMY_NET_ID = 51; + const int UNREACHABLE_NET_ID = 52; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + /** + * @deprecated use FIREWALL_ALLOWLIST. + */ + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_ALLOWLIST = 0; + /** + * @deprecated use FIREWALL_DENYLIST. + */ + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_DENYLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const int FIREWALL_CHAIN_RESTRICTED = 4; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..31775dfd11 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2018, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..1869d8d49e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..8ea20d118f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/MarkMaskParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeNetworkConfig.aidl new file mode 100644 index 0000000000..77d814b825 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeNetworkConfig.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeNetworkConfig { + int netId; + android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL; + int permission; + boolean secure; + android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM; + boolean excludeLocalRoutes = false; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeNetworkType.aidl new file mode 100644 index 0000000000..06c8979d51 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeNetworkType.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeNetworkType { + PHYSICAL = 0, + VIRTUAL = 1, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeVpnType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeVpnType.aidl new file mode 100644 index 0000000000..8a8be83958 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeVpnType.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeVpnType { + SERVICE = 1, + PLATFORM = 2, + LEGACY = 3, + OEM = 4, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5ef95e67ca --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/RouteInfoParcel.aidl @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2020, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..7b39c22e4e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherConfigParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..983e9860ea --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..5f1b722690 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherStatsParcel.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..72e987a2af --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/UidRangeParcel.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/netd/aidl/NativeUidRangeConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/netd/aidl/NativeUidRangeConfig.aidl new file mode 100644 index 0000000000..9bb679f1c1 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/netd/aidl/NativeUidRangeConfig.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.netd.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeUidRangeConfig { + int netId; + android.net.UidRangeParcel[] uidRanges; + int subPriority; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl index c780a59ee7..e671fdb781 100644 --- a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl @@ -181,6 +181,7 @@ interface INetd { const int PENALTY_POLICY_ACCEPT = 1; const int PENALTY_POLICY_LOG = 2; const int PENALTY_POLICY_REJECT = 3; + const int CLAT_MARK = -559038041; const int LOCAL_NET_ID = 99; const int DUMMY_NET_ID = 51; const int UNREACHABLE_NET_ID = 52; diff --git a/staticlibs/netd/binder/android/net/INetd.aidl b/staticlibs/netd/binder/android/net/INetd.aidl index ad469f8165..8bf8e5b9d6 100644 --- a/staticlibs/netd/binder/android/net/INetd.aidl +++ b/staticlibs/netd/binder/android/net/INetd.aidl @@ -569,6 +569,11 @@ interface INetd { */ void clatdStop(in @utf8InCpp String ifName); + /** + * Packet mark that identifies non-offloaded ingress clat packets. + */ + const int CLAT_MARK = 0xdeadc1a7; + /** * Get status of IP forwarding * From 25efa313dffb6e67a6c5655e7e565063999c54be Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 15 Jun 2022 23:42:49 +0900 Subject: [PATCH 489/777] Delete netd_aidl_interface-lateststable-cpp. This is now unused. Test: m Change-Id: I30130526f2ef25c7ede64417fec03422d04319a7 --- staticlibs/netd/Android.bp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index a648941a36..79bde9b56c 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -53,14 +53,6 @@ cc_library_static { min_sdk_version: "29", } -// TODO: delete this one when AOSP is no longer auto-merge to git_sc-mainline-prod. -cc_library_static { - name: "netd_aidl_interface-lateststable-cpp", - whole_static_libs: [ - "netd_aidl_interface-V10-cpp", - ], -} - cc_defaults { name: "netd_aidl_interface_lateststable_cpp_static", static_libs: ["netd_aidl_interface-V10-cpp"], From 1bbc5cf7a2b651ea411198827b62e296196bccdc Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Tue, 26 Apr 2022 19:10:45 +0800 Subject: [PATCH 490/777] Freeze netd_aidl_interface V9 Deprecate APIs which were moved the implementation to mainline module. - clatdStart (since T) - clatdStop (since T) - tetherOffloadRuleAdd (since S) - tetherOffloadRuleRemove (since S) - tetherOffloadGetStats (since S) - tetherOffloadSetInterfaceQuota (since S) - tetherOffloadGetAndClearStats (since S) Bug: 212345928 Test: cd system/netd; atest Change-Id: I7916512c7174a7b50833036bc89df37a266ca67e (cherry picked from commit 7b29319fcfeed3f9423fd583da705bf35ed34126) Merged-In: I7916512c7174a7b50833036bc89df37a266ca67e --- staticlibs/netd/Android.bp | 58 +++-- .../netd/aidl_api/netd_aidl_interface/9/.hash | 1 + .../9/android/net/INetd.aidl | 221 ++++++++++++++++++ .../net/INetdUnsolicitedEventListener.aidl | 48 ++++ .../net/InterfaceConfigurationParcel.aidl | 42 ++++ .../9/android/net/MarkMaskParcel.aidl | 39 ++++ .../9/android/net/NativeNetworkConfig.aidl | 44 ++++ .../9/android/net/NativeNetworkType.aidl | 39 ++++ .../9/android/net/NativeVpnType.aidl | 41 ++++ .../9/android/net/RouteInfoParcel.aidl | 40 ++++ .../9/android/net/TetherConfigParcel.aidl | 39 ++++ .../android/net/TetherOffloadRuleParcel.aidl | 44 ++++ .../9/android/net/TetherStatsParcel.aidl | 43 ++++ .../9/android/net/UidRangeParcel.aidl | 40 ++++ .../net/netd/aidl/NativeUidRangeConfig.aidl | 41 ++++ .../current/android/net/INetd.aidl | 21 ++ staticlibs/netd/binder/android/net/INetd.aidl | 16 +- 17 files changed, 802 insertions(+), 15 deletions(-) create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeNetworkConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeNetworkType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeVpnType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/netd/aidl/NativeUidRangeConfig.aidl diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index 6bc7c01400..cfa9bbb3d9 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -21,7 +21,7 @@ java_library { sdk_version: "system_current", min_sdk_version: "29", static_libs: [ - "netd_aidl_interface-V8-java", + "netd_aidl_interface-V9-java", ], apex_available: [ "//apex_available:platform", // used from services.net @@ -44,7 +44,7 @@ cc_library_static { cc_library_static { name: "netd_aidl_interface-lateststable-ndk", whole_static_libs: [ - "netd_aidl_interface-V8-ndk", + "netd_aidl_interface-V9-ndk", ], apex_available: [ "com.android.resolv", @@ -57,18 +57,18 @@ cc_library_static { cc_library_static { name: "netd_aidl_interface-lateststable-cpp", whole_static_libs: [ - "netd_aidl_interface-V8-cpp", + "netd_aidl_interface-V9-cpp", ], } cc_defaults { name: "netd_aidl_interface_lateststable_cpp_static", - static_libs: ["netd_aidl_interface-V8-cpp"], + static_libs: ["netd_aidl_interface-V9-cpp"], } cc_defaults { name: "netd_aidl_interface_lateststable_cpp_shared", - shared_libs: ["netd_aidl_interface-V8-cpp"], + shared_libs: ["netd_aidl_interface-V9-cpp"], } aidl_interface { @@ -116,16 +116,46 @@ aidl_interface { min_sdk_version: "29", }, }, - versions: [ - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", + versions_with_info: [ + { + version: "1", + imports: [], + }, + { + version: "2", + imports: [], + }, + { + version: "3", + imports: [], + }, + { + version: "4", + imports: [], + }, + { + version: "5", + imports: [], + }, + { + version: "6", + imports: [], + }, + { + version: "7", + imports: [], + }, + { + version: "8", + imports: [], + }, + { + version: "9", + imports: [], + }, + ], + } java_library { diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/9/.hash new file mode 100644 index 0000000000..94dd240d92 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/.hash @@ -0,0 +1 @@ +2bffe06ea8c13f35f90b86d6dfd1a2b4c4d4daf5 diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/INetd.aidl new file mode 100644 index 0000000000..c780a59ee7 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/INetd.aidl @@ -0,0 +1,221 @@ +/** + * Copyright (c) 2016, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreatePhysical(int netId, int permission); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + void networkCreate(in android.net.NativeNetworkConfig config); + void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int LOCAL_NET_ID = 99; + const int DUMMY_NET_ID = 51; + const int UNREACHABLE_NET_ID = 52; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + /** + * @deprecated use FIREWALL_ALLOWLIST. + */ + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_ALLOWLIST = 0; + /** + * @deprecated use FIREWALL_DENYLIST. + */ + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_DENYLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const int FIREWALL_CHAIN_RESTRICTED = 4; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..31775dfd11 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2018, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..1869d8d49e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..8ea20d118f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/MarkMaskParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeNetworkConfig.aidl new file mode 100644 index 0000000000..77d814b825 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeNetworkConfig.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeNetworkConfig { + int netId; + android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL; + int permission; + boolean secure; + android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM; + boolean excludeLocalRoutes = false; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeNetworkType.aidl new file mode 100644 index 0000000000..06c8979d51 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeNetworkType.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeNetworkType { + PHYSICAL = 0, + VIRTUAL = 1, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeVpnType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeVpnType.aidl new file mode 100644 index 0000000000..8a8be83958 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/NativeVpnType.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeVpnType { + SERVICE = 1, + PLATFORM = 2, + LEGACY = 3, + OEM = 4, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5ef95e67ca --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/RouteInfoParcel.aidl @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2020, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..7b39c22e4e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherConfigParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..983e9860ea --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..5f1b722690 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/TetherStatsParcel.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..72e987a2af --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/UidRangeParcel.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/netd/aidl/NativeUidRangeConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/netd/aidl/NativeUidRangeConfig.aidl new file mode 100644 index 0000000000..9bb679f1c1 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/9/android/net/netd/aidl/NativeUidRangeConfig.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.netd.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeUidRangeConfig { + int netId; + android.net.UidRangeParcel[] uidRanges; + int subPriority; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl index ec03d86b6c..c780a59ee7 100644 --- a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl @@ -76,7 +76,13 @@ interface INetd { void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); void strictUidCleartextPenalty(int uid, int policyPenalty); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ void clatdStop(in @utf8InCpp String ifName); boolean ipfwdEnabled(); @utf8InCpp String[] ipfwdGetRequesterList(); @@ -139,10 +145,25 @@ interface INetd { void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ android.net.TetherStatsParcel[] tetherOffloadGetStats(); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); void networkCreate(in android.net.NativeNetworkConfig config); void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); diff --git a/staticlibs/netd/binder/android/net/INetd.aidl b/staticlibs/netd/binder/android/net/INetd.aidl index d6398c1222..ad469f8165 100644 --- a/staticlibs/netd/binder/android/net/INetd.aidl +++ b/staticlibs/netd/binder/android/net/INetd.aidl @@ -548,6 +548,8 @@ interface INetd { /** * Start clatd * + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd + * control plane moved to the mainline module starting in T. See ClatCoordinator. * @param ifName interface name to start clatd * @param nat64Prefix the NAT64 prefix, e.g., "2001:db8:64::/96". * @return a string, the IPv6 address that will be used for 464xlat. @@ -559,6 +561,8 @@ interface INetd { /** * Stop clatd * + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd + * control plane moved to the mainline module starting in T. See ClatCoordinator. * @param ifName interface name to stop clatd * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. @@ -1283,6 +1287,8 @@ interface INetd { * Currently, only downstream /128 IPv6 entries are supported. An existing rule will be updated * if the input interface and destination prefix match. Otherwise, a new rule will be created. * + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline + * module accesses the BPF map directly starting in S. See BpfCoordinator. * @param rule The rule to add or update. * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. @@ -1296,6 +1302,8 @@ interface INetd { * if the destination IP address and the source interface match. It is not an error if there is * no matching rule to delete. * + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline + * module accesses the BPF map directly starting in S. See BpfCoordinator. * @param rule The rule to delete. * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. @@ -1305,6 +1313,8 @@ interface INetd { /** * Return BPF tethering offload statistics. * + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline + * module accesses the BPF map directly starting in S. See BpfCoordinator. * @return an array of TetherStatsParcel's, where each entry contains the upstream interface * index and its tethering statistics since tethering was first started. * There will only ever be one entry for a given interface index. @@ -1316,9 +1326,11 @@ interface INetd { /** * Set a per-interface quota for tethering offload. * + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline + * module accesses the BPF map directly starting in S. See BpfCoordinator. * @param ifIndex Index of upstream interface * @param quotaBytes The quota defined as the number of bytes, starting from zero and counting - * from *now*. A value of QUOTA_UNLIMITED (-1) indicates there is no limit. + * from *now*. A value of QUOTA_UNLIMITED (-1) indicates there is no limit. * @throws ServiceSpecificException in case of failure, with an error code indicating the * cause of the failure. */ @@ -1334,6 +1346,8 @@ interface INetd { * The stats and limit for a given upstream interface must be initialized (using * tetherOffloadSetInterfaceQuota) before any offload will occur on that interface. * + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline + * module accesses the BPF map directly starting in S. See BpfCoordinator. * @param ifIndex Index of upstream interface. * @return TetherStatsParcel, which contains the given upstream interface index and its * tethering statistics since tethering was first started on that upstream interface. From df13115f17a63b2556f8bd188ea178dbe72b84dc Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 15 Jun 2022 23:39:12 +0900 Subject: [PATCH 491/777] Add an int constant for CLAT_MARK and freeze INetd v10. Test: m Bug: 235778483 Change-Id: I45a0bd6be39022a913bc6cff8216df0b6559cd4b (cherry picked from commit 80664c52df2cf24fa4332084586324fd4a93de81) Merged-In: I45a0bd6be39022a913bc6cff8216df0b6559cd4b --- staticlibs/netd/Android.bp | 14 +- .../aidl_api/netd_aidl_interface/10/.hash | 1 + .../10/android/net/INetd.aidl | 222 ++++++++++++++++++ .../net/INetdUnsolicitedEventListener.aidl | 48 ++++ .../net/InterfaceConfigurationParcel.aidl | 42 ++++ .../10/android/net/MarkMaskParcel.aidl | 39 +++ .../10/android/net/NativeNetworkConfig.aidl | 44 ++++ .../10/android/net/NativeNetworkType.aidl | 39 +++ .../10/android/net/NativeVpnType.aidl | 41 ++++ .../10/android/net/RouteInfoParcel.aidl | 40 ++++ .../10/android/net/TetherConfigParcel.aidl | 39 +++ .../android/net/TetherOffloadRuleParcel.aidl | 44 ++++ .../10/android/net/TetherStatsParcel.aidl | 43 ++++ .../10/android/net/UidRangeParcel.aidl | 40 ++++ .../net/netd/aidl/NativeUidRangeConfig.aidl | 41 ++++ .../current/android/net/INetd.aidl | 1 + staticlibs/netd/binder/android/net/INetd.aidl | 5 + 17 files changed, 738 insertions(+), 5 deletions(-) create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeNetworkConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeNetworkType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeVpnType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/netd/aidl/NativeUidRangeConfig.aidl diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index cfa9bbb3d9..a648941a36 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -21,7 +21,7 @@ java_library { sdk_version: "system_current", min_sdk_version: "29", static_libs: [ - "netd_aidl_interface-V9-java", + "netd_aidl_interface-V10-java", ], apex_available: [ "//apex_available:platform", // used from services.net @@ -44,7 +44,7 @@ cc_library_static { cc_library_static { name: "netd_aidl_interface-lateststable-ndk", whole_static_libs: [ - "netd_aidl_interface-V9-ndk", + "netd_aidl_interface-V10-ndk", ], apex_available: [ "com.android.resolv", @@ -57,18 +57,18 @@ cc_library_static { cc_library_static { name: "netd_aidl_interface-lateststable-cpp", whole_static_libs: [ - "netd_aidl_interface-V9-cpp", + "netd_aidl_interface-V10-cpp", ], } cc_defaults { name: "netd_aidl_interface_lateststable_cpp_static", - static_libs: ["netd_aidl_interface-V9-cpp"], + static_libs: ["netd_aidl_interface-V10-cpp"], } cc_defaults { name: "netd_aidl_interface_lateststable_cpp_shared", - shared_libs: ["netd_aidl_interface-V9-cpp"], + shared_libs: ["netd_aidl_interface-V10-cpp"], } aidl_interface { @@ -153,6 +153,10 @@ aidl_interface { version: "9", imports: [], }, + { + version: "10", + imports: [], + }, ], diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/10/.hash new file mode 100644 index 0000000000..6ec3613559 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/.hash @@ -0,0 +1 @@ +3943383e838f39851675e3640fcdf27b42f8c9fc diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/INetd.aidl new file mode 100644 index 0000000000..e671fdb781 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/INetd.aidl @@ -0,0 +1,222 @@ +/** + * Copyright (c) 2016, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreatePhysical(int netId, int permission); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + void networkCreate(in android.net.NativeNetworkConfig config); + void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int CLAT_MARK = -559038041; + const int LOCAL_NET_ID = 99; + const int DUMMY_NET_ID = 51; + const int UNREACHABLE_NET_ID = 52; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + /** + * @deprecated use FIREWALL_ALLOWLIST. + */ + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_ALLOWLIST = 0; + /** + * @deprecated use FIREWALL_DENYLIST. + */ + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_DENYLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const int FIREWALL_CHAIN_RESTRICTED = 4; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..31775dfd11 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2018, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..1869d8d49e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..8ea20d118f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/MarkMaskParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeNetworkConfig.aidl new file mode 100644 index 0000000000..77d814b825 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeNetworkConfig.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeNetworkConfig { + int netId; + android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL; + int permission; + boolean secure; + android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM; + boolean excludeLocalRoutes = false; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeNetworkType.aidl new file mode 100644 index 0000000000..06c8979d51 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeNetworkType.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeNetworkType { + PHYSICAL = 0, + VIRTUAL = 1, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeVpnType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeVpnType.aidl new file mode 100644 index 0000000000..8a8be83958 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/NativeVpnType.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeVpnType { + SERVICE = 1, + PLATFORM = 2, + LEGACY = 3, + OEM = 4, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5ef95e67ca --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/RouteInfoParcel.aidl @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2020, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..7b39c22e4e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherConfigParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..983e9860ea --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..5f1b722690 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/TetherStatsParcel.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..72e987a2af --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/UidRangeParcel.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/netd/aidl/NativeUidRangeConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/netd/aidl/NativeUidRangeConfig.aidl new file mode 100644 index 0000000000..9bb679f1c1 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/10/android/net/netd/aidl/NativeUidRangeConfig.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.netd.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeUidRangeConfig { + int netId; + android.net.UidRangeParcel[] uidRanges; + int subPriority; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl index c780a59ee7..e671fdb781 100644 --- a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl @@ -181,6 +181,7 @@ interface INetd { const int PENALTY_POLICY_ACCEPT = 1; const int PENALTY_POLICY_LOG = 2; const int PENALTY_POLICY_REJECT = 3; + const int CLAT_MARK = -559038041; const int LOCAL_NET_ID = 99; const int DUMMY_NET_ID = 51; const int UNREACHABLE_NET_ID = 52; diff --git a/staticlibs/netd/binder/android/net/INetd.aidl b/staticlibs/netd/binder/android/net/INetd.aidl index ad469f8165..8bf8e5b9d6 100644 --- a/staticlibs/netd/binder/android/net/INetd.aidl +++ b/staticlibs/netd/binder/android/net/INetd.aidl @@ -569,6 +569,11 @@ interface INetd { */ void clatdStop(in @utf8InCpp String ifName); + /** + * Packet mark that identifies non-offloaded ingress clat packets. + */ + const int CLAT_MARK = 0xdeadc1a7; + /** * Get status of IP forwarding * From 788015bfe44b73327979b8074488c002ba6767ee Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 16 Jun 2022 07:03:04 +0000 Subject: [PATCH 492/777] Revert "Delete netd_aidl_interface-lateststable-cpp." This reverts commit c6f9d5dc8f4b486c30e178a55ebf98c415bd3562. Reason for revert: broke build in tm-mainline-prod Bug: 236205815 Change-Id: I4dd1660c58e0acba0d6a036d590355bcbcd85f0f --- staticlibs/netd/Android.bp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index 79bde9b56c..a648941a36 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -53,6 +53,14 @@ cc_library_static { min_sdk_version: "29", } +// TODO: delete this one when AOSP is no longer auto-merge to git_sc-mainline-prod. +cc_library_static { + name: "netd_aidl_interface-lateststable-cpp", + whole_static_libs: [ + "netd_aidl_interface-V10-cpp", + ], +} + cc_defaults { name: "netd_aidl_interface_lateststable_cpp_static", static_libs: ["netd_aidl_interface-V10-cpp"], From 2efccc5a0e014bc51768498f52a870c50462e3a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 16 Jun 2022 10:57:13 -0700 Subject: [PATCH 493/777] BpfMap.h - hide dangerous stuff behind #ifdef BPF_MAP_MAKE_VISIBLE_FOR_TESTING MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit while we're at it: - replace 'unique_fd != -1' with unique_fd.ok() which is a test for fd.get() >= 0 and is thus effectively equivalent - make use of the fact that unique_fd.reset() takes care to save errno. (see impl. in //system/libbase/include/android-base/unique_fd.h ) Bug: 236285127 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I6fb7bf28a2265ad84baa3c552b39c620cb3875fe --- staticlibs/native/bpf_headers/BpfMapTest.cpp | 1 + .../native/bpf_headers/include/bpf/BpfMap.h | 43 +++++++++++++------ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/staticlibs/native/bpf_headers/BpfMapTest.cpp b/staticlibs/native/bpf_headers/BpfMapTest.cpp index d0737b0f78..10afe8603f 100644 --- a/staticlibs/native/bpf_headers/BpfMapTest.cpp +++ b/staticlibs/native/bpf_headers/BpfMapTest.cpp @@ -33,6 +33,7 @@ #include #include +#define BPF_MAP_MAKE_VISIBLE_FOR_TESTING #include "bpf/BpfMap.h" #include "bpf/BpfUtils.h" diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h index afb6fdf6a0..297b20017b 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h @@ -46,11 +46,15 @@ class BpfMap { public: BpfMap() {}; + // explicitly force no copy constructor, since it would need to dup the fd + // (later on, for testing, we still make available a copy assignment operator) + BpfMap(const BpfMap&) = delete; + protected: // flag must be within BPF_OBJ_FLAG_MASK, ie. 0, BPF_F_RDONLY, BPF_F_WRONLY BpfMap(const char* pathname, uint32_t flags) { mMapFd.reset(mapRetrieve(pathname, flags)); - if (mMapFd < 0) abort(); + if (!mMapFd.ok()) abort(); if (isAtLeastKernelVersion(4, 14, 0)) { if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort(); @@ -60,10 +64,14 @@ class BpfMap { public: explicit BpfMap(const char* pathname) : BpfMap(pathname, 0) {} +#ifdef BPF_MAP_MAKE_VISIBLE_FOR_TESTING + // All bpf maps should be created by the bpfloader, so this constructor + // is reserved for tests BpfMap(bpf_map_type map_type, uint32_t max_entries, uint32_t map_flags = 0) { mMapFd.reset(createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags)); - if (mMapFd < 0) abort(); + if (!mMapFd.ok()) abort(); } +#endif base::Result getFirstKey() const { Key firstKey; @@ -106,7 +114,7 @@ class BpfMap { protected: [[clang::reinitializes]] base::Result init(const char* path, int fd) { mMapFd.reset(fd); - if (mMapFd == -1) { + if (!mMapFd.ok()) { return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path); } if (isAtLeastKernelVersion(4, 14, 0)) { @@ -135,13 +143,8 @@ class BpfMap { [[clang::reinitializes]] base::Result resetMap(bpf_map_type map_type, uint32_t max_entries, uint32_t map_flags = 0) { - int map_fd = createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags); - if (map_fd < 0) { - auto err = ErrnoErrorf("Unable to create map."); - mMapFd.reset(); - return err; - }; - mMapFd.reset(map_fd); + mMapFd.reset(createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags)); + if (!mMapFd.ok()) return ErrnoErrorf("Unable to create map."); return {}; } #endif @@ -171,11 +174,15 @@ class BpfMap { const base::unique_fd& getMap() const { return mMapFd; }; - // Copy assignment operator +#ifdef BPF_MAP_MAKE_VISIBLE_FOR_TESTING + // Copy assignment operator - due to need for fd duping, should not be used in non-test code. BpfMap& operator=(const BpfMap& other) { if (this != &other) mMapFd.reset(fcntl(other.mMapFd.get(), F_DUPFD_CLOEXEC, 0)); return *this; } +#else + BpfMap& operator=(const BpfMap&) = delete; +#endif // Move assignment operator BpfMap& operator=(BpfMap&& other) noexcept { @@ -188,7 +195,12 @@ class BpfMap { void reset(base::unique_fd fd) = delete; - [[clang::reinitializes]] void reset(int fd = -1) { +#ifdef BPF_MAP_MAKE_VISIBLE_FOR_TESTING + // Note that unique_fd.reset() carefully saves and restores the errno, + // and BpfMap.reset() won't touch the errno if passed in fd is negative either, + // hence you can do something like BpfMap.reset(systemcall()) and then + // check BpfMap.isValid() and look at errno and see why systemcall() failed. + [[clang::reinitializes]] void reset(int fd) { mMapFd.reset(fd); if ((fd >= 0) && isAtLeastKernelVersion(4, 14, 0)) { if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); @@ -196,8 +208,13 @@ class BpfMap { if (bpfGetFdMapFlags(mMapFd) != 0) abort(); // TODO: fix for BpfMapRO } } +#endif - bool isValid() const { return mMapFd != -1; } + [[clang::reinitializes]] void reset() { + mMapFd.reset(); + } + + bool isValid() const { return mMapFd.ok(); } base::Result clear() { while (true) { From ce723aa546d5215fca4b192ce83d766c259cf2c1 Mon Sep 17 00:00:00 2001 From: "Nate(Qiang) Jiang" Date: Wed, 1 Jun 2022 21:28:32 +0000 Subject: [PATCH 494/777] Make netd-client and net-utils-services-common visible to Wifi module Bug: 172457099 Test: N/A Change-Id: I50d4502ad2e5515217d70fb5e106fba01da8d68f --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 2fc4142a7c..31a726255b 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -290,6 +290,7 @@ java_library { "//packages/modules/Connectivity/service", "//packages/modules/Connectivity/tests:__subpackages__", "//packages/modules/Bluetooth/android/app", + "//packages/modules/Wifi/service:__subpackages__", ], lint: { strict_updatability_linting: true }, } From 983b52cdcc1dddb5444c12e02ef7f385e2ad5da9 Mon Sep 17 00:00:00 2001 From: "Nate(Qiang) Jiang" Date: Wed, 1 Jun 2022 21:28:32 +0000 Subject: [PATCH 495/777] Make netd-client and net-utils-services-common visible to Wifi module Bug: 172457099 Test: N/A Change-Id: I50d4502ad2e5515217d70fb5e106fba01da8d68f --- staticlibs/client-libs/Android.bp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/staticlibs/client-libs/Android.bp b/staticlibs/client-libs/Android.bp index 5cc011e5f6..cabfa06919 100644 --- a/staticlibs/client-libs/Android.bp +++ b/staticlibs/client-libs/Android.bp @@ -9,7 +9,8 @@ java_library { min_sdk_version: "29", apex_available: [ "//apex_available:platform", - "com.android.tethering" + "com.android.tethering", + "com.android.wifi" ], visibility: [ "//packages/modules/Connectivity:__subpackages__", @@ -17,6 +18,7 @@ java_library { "//frameworks/base/packages:__subpackages__", "//frameworks/libs/net/client-libs/tests:__subpackages__", "//frameworks/libs/net/common:__subpackages__", + "//packages/modules/Wifi/service:__subpackages__" ], libs: ["androidx.annotation_annotation"], static_libs: [ From 57873a9558b0a4c703d3f6079341568bab171019 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Thu, 16 Jun 2022 15:31:33 -0700 Subject: [PATCH 496/777] Sync frameworks/libs/net version of SharedLog There are two versions of SharedLog after it was copied in aosp/1849358. Moving forward, this is the version of the class that will be kept. I also checked SharedLogTest and it those are both in sync. Test: m Bug: 235901424 Change-Id: Id0899286d582be1478dc3e4a407c190ea2ffd71a --- .../com/android/net/module/util/SharedLog.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/SharedLog.java b/staticlibs/device/com/android/net/module/util/SharedLog.java index 37c6f6dc23..17b061e6ed 100644 --- a/staticlibs/device/com/android/net/module/util/SharedLog.java +++ b/staticlibs/device/com/android/net/module/util/SharedLog.java @@ -26,6 +26,7 @@ import java.io.PrintWriter; import java.time.LocalDateTime; import java.util.ArrayDeque; import java.util.Deque; +import java.util.Iterator; import java.util.StringJoiner; @@ -94,6 +95,15 @@ public class SharedLog { mLocalLog.dump(writer); } + /** + * Reverse dump the contents of this log. + * + *

This method may be called on any thread. + */ + public void reverseDump(PrintWriter writer) { + mLocalLog.reverseDump(writer); + } + ////// // Methods that both log an entry and emit it to the system log. ////// @@ -228,5 +238,12 @@ public class SharedLog { pw.println(s); } } + + synchronized void reverseDump(PrintWriter pw) { + final Iterator itr = mLog.descendingIterator(); + while (itr.hasNext()) { + pw.println(itr.next()); + } + } } } From 05eb2d093cb11e63cafa96a84368f1ce11d33c15 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 17 Jun 2022 15:09:50 +0900 Subject: [PATCH 497/777] Refuse to adopt shell permissions if they were already adopted. This does not work because when the permissions are dropped, all previously-adopted permissions will be dropped as well. Attempts to do so will likely result in hard-to-understand test failures. On S+, where we can detect this, fail with a clear error message. Test: treehugger Bug: 225092753 Change-Id: I1587ab77f885c595f0b9168c6739303c6227218e --- .../android/testutils/TestPermissionUtil.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestPermissionUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestPermissionUtil.kt index f557f1865b..a4dbd9ada9 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestPermissionUtil.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestPermissionUtil.kt @@ -19,6 +19,7 @@ package com.android.testutils import androidx.test.platform.app.InstrumentationRegistry +import com.android.modules.utils.build.SdkLevel import com.android.testutils.ExceptionUtils.ThrowingRunnable import com.android.testutils.ExceptionUtils.ThrowingSupplier @@ -31,6 +32,23 @@ import com.android.testutils.ExceptionUtils.ThrowingSupplier */ fun runAsShell(vararg permissions: String, task: () -> T): T { val autom = InstrumentationRegistry.getInstrumentation().uiAutomation + + // Calls to adoptShellPermissionIdentity do not nest, and dropShellPermissionIdentity drops all + // permissions. Thus, nesting calls will almost certainly cause test bugs, On S+, where we can + // detect this, refuse to do it. + // + // TODO: when R is deprecated, we could try to make this work instead. + // - Get the list of previously-adopted permissions. + // - Adopt the union of the previously-adopted and newly-requested permissions. + // - Run the task. + // - Adopt the previously-adopted permissions, dropping the ones just adopted. + // + // This would allow tests (and utility classes, such as the TestCarrierConfigReceiver attempted + // in aosp/2106007) to call runAsShell even within a test that has already adopted permissions. + if (SdkLevel.isAtLeastS() && !autom.getAdoptedShellPermissions().isNullOrEmpty()) { + throw IllegalStateException("adoptShellPermissionIdentity calls must not be nested") + } + autom.adoptShellPermissionIdentity(*permissions) try { return task() From d4e612b1e7c694d69985e380f2b783da2ffe7a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 3 Jun 2022 15:52:43 -0700 Subject: [PATCH 498/777] support per-map/prog selinux context and cross .o map sharing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tested by making the map struct conditional on #define V18, and only #defining that in the top line of netd.c, this results in: $ objdump -s -j size_of_bpf_map_def out/target/product/vsoc_x86_64/apex/com.android.tethering/etc/bpf/net_shared/clatd.o out/target/product/vsoc_x86_64/apex/com.android.tethering/etc/bpf/net_shared/clatd.o: file format elf64-little Contents of section size_of_bpf_map_def: 0000 30000000 00000000 0....... $ objdump -s -j size_of_bpf_prog_def out/target/product/vsoc_x86_64/apex/com.android.tethering/etc/bpf/net_shared/clatd.o out/target/product/vsoc_x86_64/apex/com.android.tethering/etc/bpf/net_shared/clatd.o: file format elf64-little Contents of section size_of_bpf_prog_def: 0000 1c000000 00000000 ........ $ objdump -s -j size_of_bpf_map_def out/target/product/vsoc_x86_64/apex/com.android.tethering/etc/bpf/netd_shared/netd.o out/target/product/vsoc_x86_64/apex/com.android.tethering/etc/bpf/netd_shared/netd.o: file format elf64-little Contents of section size_of_bpf_map_def: 0000 74000000 00000000 t....... $ objdump -s -j size_of_bpf_prog_def out/target/product/vsoc_x86_64/apex/com.android.tethering/etc/bpf/netd_shared/netd.o out/target/product/vsoc_x86_64/apex/com.android.tethering/etc/bpf/netd_shared/netd.o: file format elf64-little Contents of section size_of_bpf_prog_def: 0000 5c000000 00000000 \....... $ echo $[0x00000030] $[0x00000074] 48 116 $ echo $[0x0000001c] $[0x0000005c] 28 92 and it still successfully boots. So the struct extension infrastructure works as desired. Bug: 218408035 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I8b55769e69dbf9580e844f2a50d48651fd9a0cff --- .../bpf_headers/include/bpf/bpf_map_def.h | 53 ++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h index 13716681c3..8bad98aa45 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h @@ -111,6 +111,15 @@ _Static_assert(__alignof__(unsigned long long) == 8, "__alignof__ unsigned long // BPF wants 8, but 32-bit x86 wants 4 //_Static_assert(_Alignof(unsigned long long) == 8, "_Alignof unsigned long long != 8"); +// Length of strings (incl. selinux_context and pin_subdir) +// in the bpf_map_def and bpf_prog_def structs. +// +// WARNING: YOU CANNOT *EVER* CHANGE THESE +// as this would affect the structure size in backwards incompatible ways +// and break mainline module loading on older Android T devices +#define BPF_SELINUX_CONTEXT_CHAR_ARRAY_SIZE 32 +#define BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE 32 + /* * Map structure to be used by Android eBPF C programs. The Android eBPF loader * uses this structure from eBPF object to create maps at boot time. @@ -142,14 +151,41 @@ struct bpf_map_def { unsigned int bpfloader_min_ver; // if missing, defaults to 0, ie. v0.0 unsigned int bpfloader_max_ver; // if missing, defaults to 0x10000, ie. v1.0 - // The following fields were added in version 0.2 + // The following fields were added in version 0.2 (S) // kernelVersion() must be >= min_kver and < max_kver unsigned int min_kver; unsigned int max_kver; + +#ifdef V18 + // The following fields were added in version 0.18 (T) + // + // These are fixed length strings, padded with null bytes + // + // Warning: supported values depend on .o location + // (additionally a newer Android OS and/or bpfloader may support more values) + // + // overrides default selinux context (which is based on pin subdir) + char selinux_context[BPF_SELINUX_CONTEXT_CHAR_ARRAY_SIZE]; + // + // overrides default prefix (which is based on .o location) + char pin_subdir[BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE]; + + bool shared; // use empty string as 'file' component of pin path - allows cross .o map sharing + char pad0[3]; // manually pad up to 4 byte alignment, may be used for extensions in the future +#endif }; +#ifdef V18 +_Static_assert(sizeof(((struct bpf_map_def *)0)->selinux_context) == 32, "must be 32 bytes"); +_Static_assert(sizeof(((struct bpf_map_def *)0)->pin_subdir) == 32, "must be 32 bytes"); +#endif + // This needs to be updated whenever the above structure definition is expanded. +#ifdef V18 +_Static_assert(sizeof(struct bpf_map_def) == 116, "sizeof struct bpf_map_def != 116"); +#else _Static_assert(sizeof(struct bpf_map_def) == 48, "sizeof struct bpf_map_def != 48"); +#endif _Static_assert(__alignof__(struct bpf_map_def) == 4, "__alignof__ struct bpf_map_def != 4"); _Static_assert(_Alignof(struct bpf_map_def) == 4, "_Alignof struct bpf_map_def != 4"); @@ -168,10 +204,23 @@ struct bpf_prog_def { unsigned int bpfloader_min_ver; // if missing, defaults to 0, ie. v0.0 unsigned int bpfloader_max_ver; // if missing, defaults to 0x10000, ie. v1.0 - // No new fields in version 0.2 +#ifdef V18 + // The following fields were added in version 0.18, see description up above in bpf_map_def + char selinux_context[BPF_SELINUX_CONTEXT_CHAR_ARRAY_SIZE]; + char pin_subdir[BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE]; +#endif }; +#ifdef V18 +_Static_assert(sizeof(((struct bpf_prog_def *)0)->selinux_context) == 32, "must be 32 bytes"); +_Static_assert(sizeof(((struct bpf_prog_def *)0)->pin_subdir) == 32, "must be 32 bytes"); +#endif + // This needs to be updated whenever the above structure definition is expanded. +#ifdef V18 +_Static_assert(sizeof(struct bpf_prog_def) == 92, "sizeof struct bpf_prog_def != 92"); +#else _Static_assert(sizeof(struct bpf_prog_def) == 28, "sizeof struct bpf_prog_def != 28"); +#endif _Static_assert(__alignof__(struct bpf_prog_def) == 4, "__alignof__ struct bpf_prog_def != 4"); _Static_assert(_Alignof(struct bpf_prog_def) == 4, "_Alignof struct bpf_prog_def != 4"); From 53a144ea2eaac4893e38ace832ff3c33446d564f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 16 Jun 2022 23:11:54 -0700 Subject: [PATCH 499/777] actually enable the use of new fields added in previous commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (split in two to facilitate manual testing) Bug: 218408035 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ifc00ed168231615819b88b232155e1fe6f9a8c71 --- .../bpf_headers/include/bpf/bpf_helpers.h | 49 ++++++++++++------- .../bpf_headers/include/bpf/bpf_map_def.h | 16 ------ 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 4b035b97ef..ae3ad2c91b 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -137,11 +137,12 @@ static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, ____btf_map_##name = { } /* type safe macro to declare a map and related accessor functions */ -#define DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, usr, grp, md) \ +#define DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, \ + selinux, pindir, share) \ const struct bpf_map_def SECTION("maps") the_map = { \ .type = BPF_MAP_TYPE_##TYPE, \ - .key_size = sizeof(TypeOfKey), \ - .value_size = sizeof(TypeOfValue), \ + .key_size = sizeof(KeyType), \ + .value_size = sizeof(ValueType), \ .max_entries = (num_entries), \ .map_flags = 0, \ .uid = (usr), \ @@ -151,34 +152,40 @@ static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER, \ .min_kver = KVER_NONE, \ .max_kver = KVER_INF, \ + .selinux_context = selinux, \ + .pin_subdir = pindir, \ + .shared = share, \ }; \ - BPF_ANNOTATE_KV_PAIR(the_map, TypeOfKey, TypeOfValue); \ + BPF_ANNOTATE_KV_PAIR(the_map, KeyType, ValueType); \ \ - static inline __always_inline __unused TypeOfValue* bpf_##the_map##_lookup_elem( \ - const TypeOfKey* k) { \ + static inline __always_inline __unused ValueType* bpf_##the_map##_lookup_elem( \ + const KeyType* k) { \ return bpf_map_lookup_elem_unsafe(&the_map, k); \ }; \ \ static inline __always_inline __unused int bpf_##the_map##_update_elem( \ - const TypeOfKey* k, const TypeOfValue* v, unsigned long long flags) { \ + const KeyType* k, const ValueType* v, unsigned long long flags) { \ return bpf_map_update_elem_unsafe(&the_map, k, v, flags); \ }; \ \ - static inline __always_inline __unused int bpf_##the_map##_delete_elem(const TypeOfKey* k) { \ + static inline __always_inline __unused int bpf_##the_map##_delete_elem(const KeyType* k) { \ return bpf_map_delete_elem_unsafe(&the_map, k); \ }; -#define DEFINE_BPF_MAP(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \ - DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, AID_ROOT, 0600) +#define DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md) \ + DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, "", "", false) -#define DEFINE_BPF_MAP_GWO(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, gid) \ - DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, gid, 0620) +#define DEFINE_BPF_MAP(the_map, TYPE, KeyType, ValueType, num_entries) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, AID_ROOT, 0600) -#define DEFINE_BPF_MAP_GRO(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, gid) \ - DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, gid, 0640) +#define DEFINE_BPF_MAP_GWO(the_map, TYPE, KeyType, ValueType, num_entries, gid) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, gid, 0620) -#define DEFINE_BPF_MAP_GRW(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, gid) \ - DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, gid, 0660) +#define DEFINE_BPF_MAP_GRO(the_map, TYPE, KeyType, ValueType, num_entries, gid) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, gid, 0640) + +#define DEFINE_BPF_MAP_GRW(the_map, TYPE, KeyType, ValueType, num_entries, gid) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, gid, 0660) static int (*bpf_probe_read)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read; static int (*bpf_probe_read_str)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read_str; @@ -191,8 +198,8 @@ static unsigned long long (*bpf_get_smp_processor_id)(void) = (void*) BPF_FUNC_g static long (*bpf_get_stackid)(void* ctx, void* map, uint64_t flags) = (void*) BPF_FUNC_get_stackid; static long (*bpf_get_current_comm)(void* buf, uint32_t buf_size) = (void*) BPF_FUNC_get_current_comm; -#define DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \ - opt) \ +#define DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, opt, \ + selinux, pindir) \ const struct bpf_prog_def SECTION("progs") the_prog##_def = { \ .uid = (prog_uid), \ .gid = (prog_gid), \ @@ -201,10 +208,16 @@ static long (*bpf_get_current_comm)(void* buf, uint32_t buf_size) = (void*) BPF_ .optional = (opt), \ .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER, \ .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER, \ + .selinux_context = selinux, \ + .pin_subdir = pindir, \ }; \ SECTION(SECTION_NAME) \ int the_prog +#define DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \ + opt) \ + DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, opt, "", "") + // Programs (here used in the sense of functions/sections) marked optional are allowed to fail // to load (for example due to missing kernel patches). // The bpfloader will just ignore these failures and continue processing the next section. diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h index 8bad98aa45..14a0295922 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h @@ -156,7 +156,6 @@ struct bpf_map_def { unsigned int min_kver; unsigned int max_kver; -#ifdef V18 // The following fields were added in version 0.18 (T) // // These are fixed length strings, padded with null bytes @@ -172,20 +171,13 @@ struct bpf_map_def { bool shared; // use empty string as 'file' component of pin path - allows cross .o map sharing char pad0[3]; // manually pad up to 4 byte alignment, may be used for extensions in the future -#endif }; -#ifdef V18 _Static_assert(sizeof(((struct bpf_map_def *)0)->selinux_context) == 32, "must be 32 bytes"); _Static_assert(sizeof(((struct bpf_map_def *)0)->pin_subdir) == 32, "must be 32 bytes"); -#endif // This needs to be updated whenever the above structure definition is expanded. -#ifdef V18 _Static_assert(sizeof(struct bpf_map_def) == 116, "sizeof struct bpf_map_def != 116"); -#else -_Static_assert(sizeof(struct bpf_map_def) == 48, "sizeof struct bpf_map_def != 48"); -#endif _Static_assert(__alignof__(struct bpf_map_def) == 4, "__alignof__ struct bpf_map_def != 4"); _Static_assert(_Alignof(struct bpf_map_def) == 4, "_Alignof struct bpf_map_def != 4"); @@ -204,23 +196,15 @@ struct bpf_prog_def { unsigned int bpfloader_min_ver; // if missing, defaults to 0, ie. v0.0 unsigned int bpfloader_max_ver; // if missing, defaults to 0x10000, ie. v1.0 -#ifdef V18 // The following fields were added in version 0.18, see description up above in bpf_map_def char selinux_context[BPF_SELINUX_CONTEXT_CHAR_ARRAY_SIZE]; char pin_subdir[BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE]; -#endif }; -#ifdef V18 _Static_assert(sizeof(((struct bpf_prog_def *)0)->selinux_context) == 32, "must be 32 bytes"); _Static_assert(sizeof(((struct bpf_prog_def *)0)->pin_subdir) == 32, "must be 32 bytes"); -#endif // This needs to be updated whenever the above structure definition is expanded. -#ifdef V18 _Static_assert(sizeof(struct bpf_prog_def) == 92, "sizeof struct bpf_prog_def != 92"); -#else -_Static_assert(sizeof(struct bpf_prog_def) == 28, "sizeof struct bpf_prog_def != 28"); -#endif _Static_assert(__alignof__(struct bpf_prog_def) == 4, "__alignof__ struct bpf_prog_def != 4"); _Static_assert(_Alignof(struct bpf_prog_def) == 4, "_Alignof struct bpf_prog_def != 4"); From 95488e5ab3c28285358fb0fe8af11430d9722463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 31 May 2022 05:13:28 -0700 Subject: [PATCH 500/777] BpfMap: simplify .init() mMapFd assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this way is more obviously not calling dup_with_cloexec Bug: 218408035 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I4e1ce3b0a42ccea638332ae451e291e025d57895 (cherry picked from commit 703e4682444dcab121f9657dc5c1605a7bcce65e) Merged-In: I4e1ce3b0a42ccea638332ae451e291e025d57895 --- staticlibs/native/bpf_headers/include/bpf/BpfMap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h index d07d61045a..86c0756ed3 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h @@ -196,7 +196,7 @@ class BpfMap { template base::Result BpfMap::init(const char* path) { - mMapFd = base::unique_fd(mapRetrieveRW(path)); + mMapFd.reset(mapRetrieveRW(path)); if (mMapFd == -1) { return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path); } From ed4b6b042ee6841d0281c9002a4f874596c120b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 25 May 2022 12:29:37 -0700 Subject: [PATCH 501/777] cache kernelVersion(), make isAtLeastKernelVersion() cheaper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit not perfect due to this being in a header file, so multiple copies potentially exist, but it's really simple, and works nearly as well. Bug: 218408035 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Id90c6933d57bc12f4dd640c8918fd0885c7474cf (cherry picked from commit 9d481287aa69200a36c997200e71232b77234b0a) Merged-In: Id90c6933d57bc12f4dd640c8918fd0885c7474cf --- staticlibs/native/bpf_headers/include/bpf/BpfUtils.h | 7 ++++++- staticlibs/native/tcutils/kernelversion.h | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index 8f1b9a28ac..7801c3ef07 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -92,7 +92,7 @@ static inline int setrlimitForTest() { #define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c)) -static inline unsigned kernelVersion() { +static inline unsigned uncachedKernelVersion() { struct utsname buf; int ret = uname(&buf); if (ret) return 0; @@ -108,6 +108,11 @@ static inline unsigned kernelVersion() { return KVER(kver_major, kver_minor, kver_sub); } +static inline unsigned kernelVersion() { + static unsigned kver = uncachedKernelVersion(); + return kver; +} + static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) { return kernelVersion() >= KVER(major, minor, sub); } diff --git a/staticlibs/native/tcutils/kernelversion.h b/staticlibs/native/tcutils/kernelversion.h index 3be1ad293f..492444ad74 100644 --- a/staticlibs/native/tcutils/kernelversion.h +++ b/staticlibs/native/tcutils/kernelversion.h @@ -32,7 +32,7 @@ namespace android { -static inline unsigned kernelVersion() { +static inline unsigned uncachedKernelVersion() { struct utsname buf; int ret = uname(&buf); if (ret) @@ -51,6 +51,11 @@ static inline unsigned kernelVersion() { return KVER(kver_major, kver_minor, kver_sub); } +static unsigned kernelVersion() { + static unsigned kver = uncachedKernelVersion(); + return kver; +} + static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) { return kernelVersion() >= KVER(major, minor, sub); From bc2cb19746269588834bafa09ac57a73125455a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 25 May 2022 12:58:31 -0700 Subject: [PATCH 502/777] BpfMap key/value access size verification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (beginning there of) Bug: 218408035 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ie7cf8cd51b4e272fc76a281df6231ed27955ed3f (cherry picked from commit 62315472e581ea119fb8f44d3a03b41a8ca80b3b) Merged-In: Ie7cf8cd51b4e272fc76a281df6231ed27955ed3f --- .../native/bpf_headers/include/bpf/BpfMap.h | 41 +++++++++++++++---- .../include/BpfSyscallWrappers.h | 30 ++++++++++++++ 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h index 86c0756ed3..a7720eabf5 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h @@ -49,16 +49,20 @@ class BpfMap { protected: // flag must be within BPF_OBJ_FLAG_MASK, ie. 0, BPF_F_RDONLY, BPF_F_WRONLY BpfMap(const char* pathname, uint32_t flags) { - int map_fd = mapRetrieve(pathname, flags); - if (map_fd >= 0) mMapFd.reset(map_fd); + mMapFd.reset(mapRetrieve(pathname, flags)); + if (mMapFd < 0) abort(); + if (isAtLeastKernelVersion(4, 14, 0)) { + if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); + if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort(); + } } public: explicit BpfMap(const char* pathname) : BpfMap(pathname, 0) {} BpfMap(bpf_map_type map_type, uint32_t max_entries, uint32_t map_flags = 0) { - int map_fd = createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags); - if (map_fd >= 0) mMapFd.reset(map_fd); + mMapFd.reset(createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags)); + if (mMapFd < 0) abort(); } base::Result getFirstKey() const { @@ -100,14 +104,16 @@ class BpfMap { } // Function that tries to get map from a pinned path. - base::Result init(const char* path); + [[clang::reinitializes]] base::Result init(const char* path); #ifdef TEST_BPF_MAP // due to Android SELinux limitations which prevent map creation by anyone besides the bpfloader // this should only ever be used by test code, it is equivalent to: // .reset(createMap(type, keysize, valuesize, max_entries, map_flags) // TODO: derive map_flags from BpfMap vs BpfMapRO - base::Result resetMap(bpf_map_type map_type, uint32_t max_entries, uint32_t map_flags = 0) { + [[clang::reinitializes]] base::Result resetMap(bpf_map_type map_type, + uint32_t max_entries, + uint32_t map_flags = 0) { int map_fd = createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags); if (map_fd < 0) { auto err = ErrnoErrorf("Unable to create map."); @@ -152,14 +158,23 @@ class BpfMap { // Move assignment operator BpfMap& operator=(BpfMap&& other) noexcept { - mMapFd = std::move(other.mMapFd); - other.reset(-1); + if (this != &other) { + mMapFd = std::move(other.mMapFd); + other.reset(); + } return *this; } void reset(base::unique_fd fd) = delete; - void reset(int fd) { mMapFd.reset(fd); } + [[clang::reinitializes]] void reset(int fd = -1) { + mMapFd.reset(fd); + if ((fd >= 0) && isAtLeastKernelVersion(4, 14, 0)) { + if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); + if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort(); + if (bpfGetFdMapFlags(mMapFd) != 0) abort(); // TODO: fix for BpfMapRO + } + } bool isValid() const { return mMapFd != -1; } @@ -200,6 +215,14 @@ base::Result BpfMap::init(const char* path) { if (mMapFd == -1) { return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path); } + if (isAtLeastKernelVersion(4, 14, 0)) { + // Normally we should return an error here instead of calling abort, + // but this cannot happen at runtime without a massive code bug (K/V type mismatch) + // and as such it's better to just blow the system up and let the developer fix it. + // Crashes are much more likely to be noticed than logs and missing functionality. + if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); + if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort(); + } return {}; } diff --git a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h index abf83daa29..4b29c4487a 100644 --- a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h +++ b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h @@ -150,6 +150,36 @@ inline int detachSingleProgram(bpf_attach_type type, const BPF_FD_TYPE prog_fd, }); } +// requires 4.14+ kernel + +#define DEFINE_BPF_GET_FD_INFO(NAME, FIELD) \ +inline int bpfGetFd ## NAME(const BPF_FD_TYPE map_fd) { \ + struct bpf_map_info map_info = {}; \ + union bpf_attr attr = { .info = { \ + .bpf_fd = BPF_FD_TO_U32(map_fd), \ + .info_len = sizeof(map_info), \ + .info = ptr_to_u64(&map_info), \ + }}; \ + int rv = bpf(BPF_OBJ_GET_INFO_BY_FD, attr); \ + if (rv) return rv; \ + if (attr.info.info_len < offsetof(bpf_map_info, FIELD) + sizeof(map_info.FIELD)) { \ + errno = EOPNOTSUPP; \ + return -1; \ + }; \ + return map_info.FIELD; \ +} + +// All 6 of these fields are already present in Linux v4.14 (even ACK 4.14-P) +// while BPF_OBJ_GET_INFO_BY_FD is not implemented at all in v4.9 (even ACK 4.9-Q) +DEFINE_BPF_GET_FD_INFO(MapType, type) // int bpfGetFdMapType(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD_INFO(MapId, id) // int bpfGetFdMapId(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD_INFO(KeySize, key_size) // int bpfGetFdKeySize(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD_INFO(ValueSize, value_size) // int bpfGetFdValueSize(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD_INFO(MaxEntries, max_entries) // int bpfGetFdMaxEntries(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD_INFO(MapFlags, map_flags) // int bpfGetFdMapFlags(const BPF_FD_TYPE map_fd) + +#undef DEFINE_BPF_GET_FD_INFO + } // namespace bpf } // namespace android From db67d37c2737f27d14c27de596beeeefa2f0df7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 24 May 2022 16:07:16 -0700 Subject: [PATCH 503/777] bpf_helpers.h - add #define's for S/T bpfloader versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (by request from Lorenzo) Bug: 218408035 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I802d2aae8b103375d7cbe0ed5c35f0abf6c04ac9 (cherry picked from commit 974ee86ff71fdfaaa0305d1623efcef1d9a16b21) Merged-In: I802d2aae8b103375d7cbe0ed5c35f0abf6c04ac9 --- .../native/bpf_headers/include/bpf/bpf_helpers.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index ac9f9bcb18..3e26028544 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -19,6 +19,17 @@ * * ******************************************************************************/ +// The actual versions of the bpfloader that shipped in various Android releases + +// Android P/Q/R: BpfLoader was initially part of netd, +// this was later split out into a standalone binary, but was unversioned. + +// Android S / 12 (api level 31) - added 'tethering' mainline eBPF support +#define BPFLOADER_S_VERSION 2u + +// Android T / 13 Beta 3 (api level 33) - added support for 'netd_shared' +#define BPFLOADER_T_BETA3_VERSION 13u + /* For mainline module use, you can #define BPFLOADER_{MIN/MAX}_VER * before #include "bpf_helpers.h" to change which bpfloaders will * process the resulting .o file. From 1362614dad4837aa6ed3cdc4712f22f2caf98ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Mon, 13 Jun 2022 17:38:12 -0700 Subject: [PATCH 504/777] BpfMap - add BpfMapRO.init() support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Really we need to fix the inheritance to make BpfMapRO the parent class of BpfMap: but that's a far more difficult thing to do, so in the short term we punt like this. This makes BpfMapRO a little bit more usable, and allows a slow transition across the codebase... Bug: 218408035 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I1c5112db70e9e523c113cba536fbe19422b4d3f3 (cherry picked from commit b54659706758641a0ff01770644cb189e3959b29) Merged-In: I1c5112db70e9e523c113cba536fbe19422b4d3f3 --- .../native/bpf_headers/include/bpf/BpfMap.h | 47 ++++++++++++------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h index a7720eabf5..2bee2ee4a9 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h @@ -103,8 +103,29 @@ class BpfMap { return {}; } + protected: + [[clang::reinitializes]] base::Result init(const char* path, int fd) { + mMapFd.reset(fd); + if (mMapFd == -1) { + return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path); + } + if (isAtLeastKernelVersion(4, 14, 0)) { + // Normally we should return an error here instead of calling abort, + // but this cannot happen at runtime without a massive code bug (K/V type mismatch) + // and as such it's better to just blow the system up and let the developer fix it. + // Crashes are much more likely to be noticed than logs and missing functionality. + if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); + if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort(); + } + return {}; + } + + public: // Function that tries to get map from a pinned path. - [[clang::reinitializes]] base::Result init(const char* path); + [[clang::reinitializes]] base::Result init(const char* path) { + return init(path, mapRetrieveRW(path)); + } + #ifdef TEST_BPF_MAP // due to Android SELinux limitations which prevent map creation by anyone besides the bpfloader @@ -209,23 +230,6 @@ class BpfMap { base::unique_fd mMapFd; }; -template -base::Result BpfMap::init(const char* path) { - mMapFd.reset(mapRetrieveRW(path)); - if (mMapFd == -1) { - return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path); - } - if (isAtLeastKernelVersion(4, 14, 0)) { - // Normally we should return an error here instead of calling abort, - // but this cannot happen at runtime without a massive code bug (K/V type mismatch) - // and as such it's better to just blow the system up and let the developer fix it. - // Crashes are much more likely to be noticed than logs and missing functionality. - if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); - if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort(); - } - return {}; -} - template base::Result BpfMap::iterate( const std::function(const Key& key, const BpfMap& map)>& @@ -292,8 +296,15 @@ base::Result BpfMap::iterateWithValue( template class BpfMapRO : public BpfMap { public: + BpfMapRO() {}; + explicit BpfMapRO(const char* pathname) : BpfMap(pathname, BPF_F_RDONLY) {} + + // Function that tries to get map from a pinned path. + [[clang::reinitializes]] base::Result init(const char* path) { + return BpfMap::init(path, mapRetrieveRO(path)); + } }; } // namespace bpf From a79814aadea00465758920f3a7dd34cc85dfec9c Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 21 Jun 2022 12:52:10 +0900 Subject: [PATCH 505/777] Fix handling of Throwable in tryTest/catch Throwable could be used as a type argument to catch(), but it would possibly never be caught, because the method only catches Exception. Notably, junit assertions fail with AssertionError, which is not a subclass of Exception. Due to that, tests or utilities like DeviceConfigRule that have failing assertions in catch() would not run the subsequent cleanup steps. Bug: 210377950 Test: atest CleanupTest Change-Id: I54e2922cb466f077ba4d219f8c3c6f885316296c --- .../android/net/module/util/CleanupTest.kt | 19 +++++++++++++++++++ .../com/android/testutils/Cleanup.kt | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt index 649b30e11d..851d09af69 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CleanupTest.kt @@ -174,6 +174,25 @@ class CleanupTest { assertTrue(thrown.suppressedExceptions.isEmpty()) } + @Test + fun testAssertionErrorInCatch() { + var x = 1 + val thrown = assertFailsWith { + tryTest { + x = 2 + throw TestException1() + }.catch { + x = 3 + fail("Test failure in catch") + } cleanup { + assertTrue(x == 3) + x = 4 + } + } + assertTrue(x == 4) + assertTrue(thrown.suppressedExceptions.isEmpty()) + } + @Test fun testMultipleCleanups() { var x = 1 diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt index 45783d82db..3db357b565 100644 --- a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt +++ b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt @@ -90,7 +90,7 @@ inline class TryExpr(val result: Result) { if (originalException !is E) return this return TryExpr(try { Result.success(block(originalException)) - } catch (e: Exception) { + } catch (e: Throwable) { Result.failure(e) }) } From 77fb194ae468ef9cde15501ccb296d4463f81b50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 3 Jun 2022 15:52:43 -0700 Subject: [PATCH 506/777] support per-map/prog selinux context and cross .o map sharing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tested in pieces in aosp/master and it still successfully boots. So the struct extension infrastructure works as desired. This is a sqaush of 2 aosp/master commits: 64005dd91b0cf1722ccd1767f805e0524010920e a5c641141ff74bba025a65451628308c6cbb7e0f Ignore-AOSP-First: squash of 2 aosp/master patches Bug: 218408035 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I7136253086eaccf79cf39e7a0143b425a1019390 --- .../bpf_headers/include/bpf/bpf_helpers.h | 49 ++++++++++++------- .../bpf_headers/include/bpf/bpf_map_def.h | 41 ++++++++++++++-- 2 files changed, 68 insertions(+), 22 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 3e26028544..10686a29f7 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -137,11 +137,12 @@ static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, ____btf_map_##name = { } /* type safe macro to declare a map and related accessor functions */ -#define DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, usr, grp, md) \ +#define DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, \ + selinux, pindir, share) \ const struct bpf_map_def SECTION("maps") the_map = { \ .type = BPF_MAP_TYPE_##TYPE, \ - .key_size = sizeof(TypeOfKey), \ - .value_size = sizeof(TypeOfValue), \ + .key_size = sizeof(KeyType), \ + .value_size = sizeof(ValueType), \ .max_entries = (num_entries), \ .map_flags = 0, \ .uid = (usr), \ @@ -151,34 +152,40 @@ static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER, \ .min_kver = KVER_NONE, \ .max_kver = KVER_INF, \ + .selinux_context = selinux, \ + .pin_subdir = pindir, \ + .shared = share, \ }; \ - BPF_ANNOTATE_KV_PAIR(the_map, TypeOfKey, TypeOfValue); \ + BPF_ANNOTATE_KV_PAIR(the_map, KeyType, ValueType); \ \ - static inline __always_inline __unused TypeOfValue* bpf_##the_map##_lookup_elem( \ - const TypeOfKey* k) { \ + static inline __always_inline __unused ValueType* bpf_##the_map##_lookup_elem( \ + const KeyType* k) { \ return bpf_map_lookup_elem_unsafe(&the_map, k); \ }; \ \ static inline __always_inline __unused int bpf_##the_map##_update_elem( \ - const TypeOfKey* k, const TypeOfValue* v, unsigned long long flags) { \ + const KeyType* k, const ValueType* v, unsigned long long flags) { \ return bpf_map_update_elem_unsafe(&the_map, k, v, flags); \ }; \ \ - static inline __always_inline __unused int bpf_##the_map##_delete_elem(const TypeOfKey* k) { \ + static inline __always_inline __unused int bpf_##the_map##_delete_elem(const KeyType* k) { \ return bpf_map_delete_elem_unsafe(&the_map, k); \ }; -#define DEFINE_BPF_MAP(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \ - DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, AID_ROOT, 0600) +#define DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md) \ + DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, "", "", false) -#define DEFINE_BPF_MAP_GWO(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, gid) \ - DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, gid, 0620) +#define DEFINE_BPF_MAP(the_map, TYPE, KeyType, ValueType, num_entries) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, AID_ROOT, 0600) -#define DEFINE_BPF_MAP_GRO(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, gid) \ - DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, gid, 0640) +#define DEFINE_BPF_MAP_GWO(the_map, TYPE, KeyType, ValueType, num_entries, gid) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, gid, 0620) -#define DEFINE_BPF_MAP_GRW(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, gid) \ - DEFINE_BPF_MAP_UGM(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, AID_ROOT, gid, 0660) +#define DEFINE_BPF_MAP_GRO(the_map, TYPE, KeyType, ValueType, num_entries, gid) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, gid, 0640) + +#define DEFINE_BPF_MAP_GRW(the_map, TYPE, KeyType, ValueType, num_entries, gid) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, gid, 0660) static int (*bpf_probe_read)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read; static int (*bpf_probe_read_str)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read_str; @@ -189,8 +196,8 @@ static unsigned long long (*bpf_get_current_pid_tgid)(void) = (void*) BPF_FUNC_g static unsigned long long (*bpf_get_current_uid_gid)(void) = (void*) BPF_FUNC_get_current_uid_gid; static unsigned long long (*bpf_get_smp_processor_id)(void) = (void*) BPF_FUNC_get_smp_processor_id; -#define DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \ - opt) \ +#define DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, opt, \ + selinux, pindir) \ const struct bpf_prog_def SECTION("progs") the_prog##_def = { \ .uid = (prog_uid), \ .gid = (prog_gid), \ @@ -199,10 +206,16 @@ static unsigned long long (*bpf_get_smp_processor_id)(void) = (void*) BPF_FUNC_g .optional = (opt), \ .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER, \ .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER, \ + .selinux_context = selinux, \ + .pin_subdir = pindir, \ }; \ SECTION(SECTION_NAME) \ int the_prog +#define DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \ + opt) \ + DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, opt, "", "") + // Programs (here used in the sense of functions/sections) marked optional are allowed to fail // to load (for example due to missing kernel patches). // The bpfloader will just ignore these failures and continue processing the next section. diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h index 13716681c3..14a0295922 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h @@ -111,6 +111,15 @@ _Static_assert(__alignof__(unsigned long long) == 8, "__alignof__ unsigned long // BPF wants 8, but 32-bit x86 wants 4 //_Static_assert(_Alignof(unsigned long long) == 8, "_Alignof unsigned long long != 8"); +// Length of strings (incl. selinux_context and pin_subdir) +// in the bpf_map_def and bpf_prog_def structs. +// +// WARNING: YOU CANNOT *EVER* CHANGE THESE +// as this would affect the structure size in backwards incompatible ways +// and break mainline module loading on older Android T devices +#define BPF_SELINUX_CONTEXT_CHAR_ARRAY_SIZE 32 +#define BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE 32 + /* * Map structure to be used by Android eBPF C programs. The Android eBPF loader * uses this structure from eBPF object to create maps at boot time. @@ -142,14 +151,33 @@ struct bpf_map_def { unsigned int bpfloader_min_ver; // if missing, defaults to 0, ie. v0.0 unsigned int bpfloader_max_ver; // if missing, defaults to 0x10000, ie. v1.0 - // The following fields were added in version 0.2 + // The following fields were added in version 0.2 (S) // kernelVersion() must be >= min_kver and < max_kver unsigned int min_kver; unsigned int max_kver; + + // The following fields were added in version 0.18 (T) + // + // These are fixed length strings, padded with null bytes + // + // Warning: supported values depend on .o location + // (additionally a newer Android OS and/or bpfloader may support more values) + // + // overrides default selinux context (which is based on pin subdir) + char selinux_context[BPF_SELINUX_CONTEXT_CHAR_ARRAY_SIZE]; + // + // overrides default prefix (which is based on .o location) + char pin_subdir[BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE]; + + bool shared; // use empty string as 'file' component of pin path - allows cross .o map sharing + char pad0[3]; // manually pad up to 4 byte alignment, may be used for extensions in the future }; +_Static_assert(sizeof(((struct bpf_map_def *)0)->selinux_context) == 32, "must be 32 bytes"); +_Static_assert(sizeof(((struct bpf_map_def *)0)->pin_subdir) == 32, "must be 32 bytes"); + // This needs to be updated whenever the above structure definition is expanded. -_Static_assert(sizeof(struct bpf_map_def) == 48, "sizeof struct bpf_map_def != 48"); +_Static_assert(sizeof(struct bpf_map_def) == 116, "sizeof struct bpf_map_def != 116"); _Static_assert(__alignof__(struct bpf_map_def) == 4, "__alignof__ struct bpf_map_def != 4"); _Static_assert(_Alignof(struct bpf_map_def) == 4, "_Alignof struct bpf_map_def != 4"); @@ -168,10 +196,15 @@ struct bpf_prog_def { unsigned int bpfloader_min_ver; // if missing, defaults to 0, ie. v0.0 unsigned int bpfloader_max_ver; // if missing, defaults to 0x10000, ie. v1.0 - // No new fields in version 0.2 + // The following fields were added in version 0.18, see description up above in bpf_map_def + char selinux_context[BPF_SELINUX_CONTEXT_CHAR_ARRAY_SIZE]; + char pin_subdir[BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE]; }; +_Static_assert(sizeof(((struct bpf_prog_def *)0)->selinux_context) == 32, "must be 32 bytes"); +_Static_assert(sizeof(((struct bpf_prog_def *)0)->pin_subdir) == 32, "must be 32 bytes"); + // This needs to be updated whenever the above structure definition is expanded. -_Static_assert(sizeof(struct bpf_prog_def) == 28, "sizeof struct bpf_prog_def != 28"); +_Static_assert(sizeof(struct bpf_prog_def) == 92, "sizeof struct bpf_prog_def != 92"); _Static_assert(__alignof__(struct bpf_prog_def) == 4, "__alignof__ struct bpf_prog_def != 4"); _Static_assert(_Alignof(struct bpf_prog_def) == 4, "_Alignof struct bpf_prog_def != 4"); From 53eeb697c7d314a968e2c00af101e883073e44b9 Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Wed, 22 Jun 2022 04:18:16 +0000 Subject: [PATCH 507/777] Delete netd_aidl_interface-lateststable-cpp The netd_aidl_interface-lateststable-cpp has been replaced by netd_aidl_interface_lateststable_cpp_static. The dependencies in tm-mainline-prod were removed in ag/18922953. Change-Id: I7eae884f4040f00ac6870dfa338a820cd7217ed0 Test: TH Bug: N/A --- staticlibs/netd/Android.bp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index a648941a36..79bde9b56c 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -53,14 +53,6 @@ cc_library_static { min_sdk_version: "29", } -// TODO: delete this one when AOSP is no longer auto-merge to git_sc-mainline-prod. -cc_library_static { - name: "netd_aidl_interface-lateststable-cpp", - whole_static_libs: [ - "netd_aidl_interface-V10-cpp", - ], -} - cc_defaults { name: "netd_aidl_interface_lateststable_cpp_static", static_libs: ["netd_aidl_interface-V10-cpp"], From de5e402e48622fe2ece92bb79530d25255831210 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 22 Jun 2022 19:10:30 +0900 Subject: [PATCH 508/777] Use UnboundedSdkLevel for DevSdkIgnoreRule UnboundedSdkLevel provides a generic and supported way to check for development SDK level, which makes it unnecessary to update DevSdkIgnoreRule yearly. Also this allows using UDC with DevSdkIgnoreRule / DevSdkIgnoreRunner. Test: Tests using this rule Change-Id: I151df06ce1498ecbf81c01de8884ebbac83cf7d7 --- .../com/android/testutils/CompatUtil.kt | 8 +- .../com/android/testutils/DevSdkIgnoreRule.kt | 85 +++++++++---------- .../android/testutils/DevSdkIgnoreRunner.kt | 2 +- 3 files changed, 44 insertions(+), 51 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/CompatUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/CompatUtil.kt index ff8c668995..82f1d9b967 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/CompatUtil.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/CompatUtil.kt @@ -17,7 +17,7 @@ package com.android.testutils import android.net.NetworkSpecifier -import android.os.Build +import com.android.modules.utils.build.SdkLevel.isAtLeastS /** * Test utility to create [NetworkSpecifier]s on different SDK versions. @@ -26,7 +26,7 @@ object CompatUtil { @JvmStatic fun makeTestNetworkSpecifier(ifName: String): NetworkSpecifier { // Until R, there was no TestNetworkSpecifier, StringNetworkSpecifier was used instead - if (isDevSdkInRange(minExclusive = null, maxInclusive = Build.VERSION_CODES.R)) { + if (!isAtLeastS()) { return makeNetworkSpecifierInternal("android.net.StringNetworkSpecifier", ifName) } // TestNetworkSpecifier is not part of the SDK in some branches using this utility @@ -37,7 +37,7 @@ object CompatUtil { @JvmStatic fun makeEthernetNetworkSpecifier(ifName: String): NetworkSpecifier { // Until R, there was no EthernetNetworkSpecifier, StringNetworkSpecifier was used instead - if (isDevSdkInRange(minExclusive = null, maxInclusive = Build.VERSION_CODES.R)) { + if (!isAtLeastS()) { return makeNetworkSpecifierInternal("android.net.StringNetworkSpecifier", ifName) } // EthernetNetworkSpecifier is not part of the SDK in some branches using this utility @@ -50,4 +50,4 @@ object CompatUtil { return Class.forName(clazz) .getConstructor(String::class.java).newInstance(specifier) as NetworkSpecifier } -} \ No newline at end of file +} diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt index 3fcf801152..21e84dafd5 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt @@ -18,58 +18,41 @@ package com.android.testutils import android.os.Build import androidx.test.InstrumentationRegistry -import com.android.modules.utils.build.SdkLevel -import kotlin.test.fail +import com.android.modules.utils.build.UnboundedSdkLevel import org.junit.Assume.assumeTrue import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement import java.util.regex.Pattern -// TODO: Remove it when Build.VERSION_CODES.SC_V2 is available -const val SC_V2 = 32 +@Deprecated("Use Build.VERSION_CODES", ReplaceWith("Build.VERSION_CODES.S_V2")) +const val SC_V2 = Build.VERSION_CODES.S_V2 private val MAX_TARGET_SDK_ANNOTATION_RE = Pattern.compile("MaxTargetSdk([0-9]+)$") private val targetSdk = InstrumentationRegistry.getContext().applicationInfo.targetSdkVersion +private fun isDevSdkInRange(minExclusive: String?, maxInclusive: String?): Boolean { + return (minExclusive == null || !UnboundedSdkLevel.isAtMost(minExclusive)) && + (maxInclusive == null || UnboundedSdkLevel.isAtMost(maxInclusive)) +} + /** - * Returns true if the development SDK version of the device is in the provided range. + * Returns true if the development SDK version of the device is in the provided annotation range. * - * If the device is not using a release SDK, the development SDK is considered to be higher than - * [Build.VERSION.SDK_INT]. + * If the device is not using a release SDK, the development SDK differs from + * [Build.VERSION.SDK_INT], and is indicated by the device codenames; see [UnboundedSdkLevel]. */ -fun isDevSdkInRange(minExclusive: Int?, maxInclusive: Int?): Boolean { - return (minExclusive == null || isDevSdkAfter(minExclusive)) && - (maxInclusive == null || isDevSdkUpTo(maxInclusive)) -} - -private fun isDevSdkAfter(minExclusive: Int): Boolean { - // A development build for T typically has SDK_INT = 30 (R) or SDK_INT = 31 (S), so SDK_INT - // alone cannot be used to check the SDK version. - // For recent SDKs that still have development builds used for testing, use SdkLevel utilities - // instead of SDK_INT. - return when (minExclusive) { - // TODO: Use Build.VERSION_CODES.SC_V2 when it is available - SC_V2 -> SdkLevel.isAtLeastT() - // TODO: To use SdkLevel.isAtLeastSv2 when available - Build.VERSION_CODES.S -> fail("Do you expect to ignore the test until T? Use SC_V2 instead") - Build.VERSION_CODES.R -> SdkLevel.isAtLeastS() - // Development builds of SDK versions <= R are not used anymore - else -> Build.VERSION.SDK_INT > minExclusive - } -} - -private fun isDevSdkUpTo(maxInclusive: Int): Boolean { - return when (maxInclusive) { - // TODO: Use Build.VERSION_CODES.SC_V2 when it is available - SC_V2 -> !SdkLevel.isAtLeastT() - // TODO: To use SdkLevel.isAtLeastSv2 when available - Build.VERSION_CODES.S -> - fail("Do you expect to ignore the test before T? Use SC_V2 instead") - Build.VERSION_CODES.R -> !SdkLevel.isAtLeastS() - // Development builds of SDK versions <= R are not used anymore - else -> Build.VERSION.SDK_INT <= maxInclusive - } +fun isDevSdkInRange( + ignoreUpTo: DevSdkIgnoreRule.IgnoreUpTo?, + ignoreAfter: DevSdkIgnoreRule.IgnoreAfter? +): Boolean { + val minExclusive = + if (ignoreUpTo?.value == 0) ignoreUpTo.codename + else ignoreUpTo?.value?.toString() + val maxInclusive = + if (ignoreAfter?.value == 0) ignoreAfter.codename + else ignoreAfter?.value?.toString() + return isDevSdkInRange(minExclusive, maxInclusive) } private fun getMaxTargetSdk(description: Description): Int? { @@ -86,13 +69,23 @@ private fun getMaxTargetSdk(description: Description): Int? { * If the device is not using a release SDK, the development SDK is considered to be higher than * [Build.VERSION.SDK_INT]. * - * @param ignoreClassUpTo Skip all tests in the class if the device dev SDK is <= this value. - * @param ignoreClassAfter Skip all tests in the class if the device dev SDK is > this value. + * @param ignoreClassUpTo Skip all tests in the class if the device dev SDK is <= this codename or + * SDK level. + * @param ignoreClassAfter Skip all tests in the class if the device dev SDK is > this codename or + * SDK level. */ class DevSdkIgnoreRule @JvmOverloads constructor( - private val ignoreClassUpTo: Int? = null, - private val ignoreClassAfter: Int? = null + private val ignoreClassUpTo: String? = null, + private val ignoreClassAfter: String? = null ) : TestRule { + /** + * @param ignoreClassUpTo Skip all tests in the class if the device dev SDK is <= this value. + * @param ignoreClassAfter Skip all tests in the class if the device dev SDK is > this value. + */ + @JvmOverloads + constructor(ignoreClassUpTo: Int?, ignoreClassAfter: Int? = null) : this( + ignoreClassUpTo?.toString(), ignoreClassAfter?.toString()) + override fun apply(base: Statement, description: Description): Statement { return IgnoreBySdkStatement(base, description) } @@ -103,7 +96,7 @@ class DevSdkIgnoreRule @JvmOverloads constructor( * If the device is not using a release SDK, the development SDK is considered to be higher * than [Build.VERSION.SDK_INT]. */ - annotation class IgnoreAfter(val value: Int) + annotation class IgnoreAfter(val value: Int = 0, val codename: String = "") /** * Ignore the test for any development SDK that lower than or equal to [value]. @@ -111,7 +104,7 @@ class DevSdkIgnoreRule @JvmOverloads constructor( * If the device is not using a release SDK, the development SDK is considered to be higher * than [Build.VERSION.SDK_INT]. */ - annotation class IgnoreUpTo(val value: Int) + annotation class IgnoreUpTo(val value: Int = 0, val codename: String = "") private inner class IgnoreBySdkStatement( private val base: Statement, @@ -124,7 +117,7 @@ class DevSdkIgnoreRule @JvmOverloads constructor( val devSdkMessage = "Skipping test for build ${Build.VERSION.CODENAME} " + "with SDK ${Build.VERSION.SDK_INT}" assumeTrue(devSdkMessage, isDevSdkInRange(ignoreClassUpTo, ignoreClassAfter)) - assumeTrue(devSdkMessage, isDevSdkInRange(ignoreUpTo?.value, ignoreAfter?.value)) + assumeTrue(devSdkMessage, isDevSdkInRange(ignoreUpTo, ignoreAfter)) val maxTargetSdk = getMaxTargetSdk(description) if (maxTargetSdk != null) { diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt index da7bf97b95..2e73666bf4 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt @@ -52,7 +52,7 @@ class DevSdkIgnoreRunner(private val klass: Class<*>) : Runner(), Filterable, So val ignoreAfter = it.getAnnotation(IgnoreAfter::class.java) val ignoreUpTo = it.getAnnotation(IgnoreUpTo::class.java) - if (isDevSdkInRange(ignoreUpTo?.value, ignoreAfter?.value)) AndroidJUnit4(klass) else null + if (isDevSdkInRange(ignoreUpTo, ignoreAfter)) AndroidJUnit4(klass) else null } override fun run(notifier: RunNotifier) { From 39c7bd75713089df0d8a6253e1d94ffeefc98d96 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 22 Jun 2022 19:04:54 +0900 Subject: [PATCH 509/777] DeviceInfoUtils: add isKernelVersionAtLeast method. Add a method to check if the current kernel version is at least from a given version. Bug: 236783925 Test: atest com.android.testutils.DeviceInfoUtilsTest --iterations Change-Id: If0509b8ccad895c31d9447fee06789540002f666 --- .../android/testutils/DeviceInfoUtilsTest.java | 14 ++++++++++++++ .../com/android/testutils/DeviceInfoUtils.java | 15 +++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java b/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java index 6f603d50da..e46dd5997c 100644 --- a/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/testutils/DeviceInfoUtilsTest.java @@ -106,4 +106,18 @@ public final class DeviceInfoUtilsTest { assertFalse(v1.isAtLeast(v4)); assertFalse(v1.isAtLeast(v5)); } + + @Test + public void testKernelVersionIsAtLeast() { + // Pick a lower kernel version 4.0 which was released at April 2015, the kernel + // version running on all test devices nowadays should be higher than it. + assertTrue(DeviceInfoUtils.isKernelVersionAtLeast("4.0")); + + // Invalid kernel version. + assertTrue(DeviceInfoUtils.isKernelVersionAtLeast("0.0.0")); + + // Pick a higher kernel version which isn't released yet, comparison should return false. + // Need to update the target version in the future to make sure the test still passes. + assertFalse(DeviceInfoUtils.isKernelVersionAtLeast("20.0.0")); + } } diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java b/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java index 1925b55945..ea89edaa34 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java @@ -16,6 +16,7 @@ package com.android.testutils; +import android.os.VintfRuntimeInfo; import android.text.TextUtils; import android.util.Pair; @@ -157,4 +158,18 @@ public class DeviceInfoUtils { return new KVersion(0, 0, 0); } } + + /** + * Check if the current kernel version is at least satisfied with the given version. + * + * @param version the start version to compare + * @return return true if the current version is at least satisfied with the given version. + * otherwise, return false. + */ + public static boolean isKernelVersionAtLeast(final String version) { + final String kernelVersion = VintfRuntimeInfo.getKernelVersion(); + final KVersion current = DeviceInfoUtils.getMajorMinorSubminorVersion(kernelVersion); + final KVersion from = DeviceInfoUtils.getMajorMinorSubminorVersion(version); + return current.isAtLeast(from); + } } From 2ca2fc6d32b804ed932ed0c7459b680724a8a627 Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Wed, 22 Jun 2022 09:57:43 +0000 Subject: [PATCH 510/777] Add NetNativeTestBase Add a helper class NetNativeTestBase to log the life cycle of each test. Bug: 223731710 Test: m Change-Id: I2c3b561c5ecf33b6eb3b4512b2a8c2638f3db609 --- .../include/netdutils/NetNativeTestBase.h | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 staticlibs/netd/libnetdutils/include/netdutils/NetNativeTestBase.h diff --git a/staticlibs/netd/libnetdutils/include/netdutils/NetNativeTestBase.h b/staticlibs/netd/libnetdutils/include/netdutils/NetNativeTestBase.h new file mode 100644 index 0000000000..c8b30c6266 --- /dev/null +++ b/staticlibs/netd/libnetdutils/include/netdutils/NetNativeTestBase.h @@ -0,0 +1,46 @@ +/* + * 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. + * + */ +#pragma once + +#include +#include +#include "gtest/gtest.h" + +using ::testing::TestInfo; +using ::testing::UnitTest; + +#define DBG 1 + +/* + * Test base class for net native tests to support common usage. + */ +class NetNativeTestBase : public ::testing::Test { + public: + // TODO: update the logging when gtest supports logging the life cycle on each test. + NetNativeTestBase() { + if (DBG) LOG(INFO) << getTestCaseLog(true); + } + ~NetNativeTestBase() { + if (DBG) LOG(INFO) << getTestCaseLog(false); + } + + std::string getTestCaseLog(bool running) { + const TestInfo* const test_info = UnitTest::GetInstance()->current_test_info(); + return fmt::format("{}: {}#{}", (running ? "started" : "finished"), + test_info->test_suite_name(), test_info->name()); + } +}; From f11273951cca258f9cc309b631de0026939926bf Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 17 Jun 2022 15:47:17 +0900 Subject: [PATCH 511/777] Make IpNeighborMonitor#NeighborEvent member as public immutable. The members of NeighborEvent used to be package private, that allows NetworkStack module can access members directly due to they are in the same package. After de-duplicate the IpNeighborMonitor from NetworkStack module and rely on the 'net-utils-device-common-ip' lib, package private members are not accessible any more, change them to public immutable. Bug: 235901424 Test: m Change-Id: I49f863055242de4f4f815ea01fe2a695b8359751 --- .../net/module/util/ip/IpNeighborMonitor.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/ip/IpNeighborMonitor.java b/staticlibs/device/com/android/net/module/util/ip/IpNeighborMonitor.java index 88f8c9d37d..4a61794188 100644 --- a/staticlibs/device/com/android/net/module/util/ip/IpNeighborMonitor.java +++ b/staticlibs/device/com/android/net/module/util/ip/IpNeighborMonitor.java @@ -22,6 +22,7 @@ import static com.android.net.module.util.netlink.NetlinkConstants.RTM_DELNEIGH; import static com.android.net.module.util.netlink.NetlinkConstants.hexify; import static com.android.net.module.util.netlink.NetlinkConstants.stringForNlMsgType; +import android.annotation.NonNull; import android.net.MacAddress; import android.os.Handler; import android.system.ErrnoException; @@ -80,15 +81,17 @@ public class IpNeighborMonitor extends NetlinkMonitor { * An event about a neighbor. */ public static class NeighborEvent { - final long elapsedMs; - final short msgType; - final int ifindex; - final InetAddress ip; - final short nudState; - final MacAddress macAddr; + public final long elapsedMs; + public final short msgType; + public final int ifindex; + @NonNull + public final InetAddress ip; + public final short nudState; + @NonNull + public final MacAddress macAddr; - public NeighborEvent(long elapsedMs, short msgType, int ifindex, InetAddress ip, - short nudState, MacAddress macAddr) { + public NeighborEvent(long elapsedMs, short msgType, int ifindex, @NonNull InetAddress ip, + short nudState, @NonNull MacAddress macAddr) { this.elapsedMs = elapsedMs; this.msgType = msgType; this.ifindex = ifindex; @@ -101,7 +104,7 @@ public class IpNeighborMonitor extends NetlinkMonitor { return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateConnected(nudState); } - boolean isValid() { + public boolean isValid() { return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateValid(nudState); } From 1a542aa48d5f82e966edee000a392f987f3b3152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 22 Jun 2022 19:07:15 -0700 Subject: [PATCH 512/777] bpf_helpers - BPFLOADER_T_VERSION is v0.19 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: N/A Signed-off-by: Maciej Żenczykowski Change-Id: I1298757926acfe299d4646e4e3f1ead3a0dfa806 --- staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index ae3ad2c91b..8bc8eb17e4 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -30,6 +30,13 @@ // Android T / 13 Beta 3 (api level 33) - added support for 'netd_shared' #define BPFLOADER_T_BETA3_VERSION 13u +// v0.18 added support for shared and pindir, but still ignores selinux_content +// v0.19 added support for selinux_content along with the required selinux changes +// and should be available starting with Android T Beta 4 +// +// Android T / 13 (api level 33) - support for shared/selinux_context/pindir +#define BPFLOADER_T_VERSION 19u + /* For mainline module use, you can #define BPFLOADER_{MIN/MAX}_VER * before #include "bpf_helpers.h" to change which bpfloaders will * process the resulting .o file. From 96ffe3733c9077cbbd5c889a3085fe569ac6c6dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Mon, 20 Jun 2022 13:50:48 -0700 Subject: [PATCH 513/777] refactor common logic into abortOnKeyOrValueSizeMismatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per request on: https://googleplex-android-review.googlesource.com/c/platform/frameworks/libs/net/+/18992756 While we're at it let's temporarily remove the check in .reset(fd) if (bpfGetFdMapFlags(mMapFd) != 0) abort(); // TODO: fix for BpfMapRO We'll add it back when the code is in better shape, and read-only vs read-write state of the map is something we actually *know*. Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Id8d65bdc529872685b42656e638f22048fafb7f6 --- .../native/bpf_headers/include/bpf/BpfMap.h | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h index 297b20017b..47256fa098 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h @@ -50,10 +50,8 @@ class BpfMap { // (later on, for testing, we still make available a copy assignment operator) BpfMap(const BpfMap&) = delete; - protected: - // flag must be within BPF_OBJ_FLAG_MASK, ie. 0, BPF_F_RDONLY, BPF_F_WRONLY - BpfMap(const char* pathname, uint32_t flags) { - mMapFd.reset(mapRetrieve(pathname, flags)); + private: + void abortOnKeyOrValueSizeMismatch() { if (!mMapFd.ok()) abort(); if (isAtLeastKernelVersion(4, 14, 0)) { if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); @@ -61,6 +59,13 @@ class BpfMap { } } + protected: + // flag must be within BPF_OBJ_FLAG_MASK, ie. 0, BPF_F_RDONLY, BPF_F_WRONLY + BpfMap(const char* pathname, uint32_t flags) { + mMapFd.reset(mapRetrieve(pathname, flags)); + abortOnKeyOrValueSizeMismatch(); + } + public: explicit BpfMap(const char* pathname) : BpfMap(pathname, 0) {} @@ -117,14 +122,11 @@ class BpfMap { if (!mMapFd.ok()) { return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path); } - if (isAtLeastKernelVersion(4, 14, 0)) { - // Normally we should return an error here instead of calling abort, - // but this cannot happen at runtime without a massive code bug (K/V type mismatch) - // and as such it's better to just blow the system up and let the developer fix it. - // Crashes are much more likely to be noticed than logs and missing functionality. - if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); - if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort(); - } + // Normally we should return an error here instead of calling abort, + // but this cannot happen at runtime without a massive code bug (K/V type mismatch) + // and as such it's better to just blow the system up and let the developer fix it. + // Crashes are much more likely to be noticed than logs and missing functionality. + abortOnKeyOrValueSizeMismatch(); return {}; } @@ -202,11 +204,7 @@ class BpfMap { // check BpfMap.isValid() and look at errno and see why systemcall() failed. [[clang::reinitializes]] void reset(int fd) { mMapFd.reset(fd); - if ((fd >= 0) && isAtLeastKernelVersion(4, 14, 0)) { - if (bpfGetFdKeySize(mMapFd) != sizeof(Key)) abort(); - if (bpfGetFdValueSize(mMapFd) != sizeof(Value)) abort(); - if (bpfGetFdMapFlags(mMapFd) != 0) abort(); // TODO: fix for BpfMapRO - } + if (mMapFd.ok()) abortOnKeyOrValueSizeMismatch(); } #endif From 0ce7758487675d19a2acb9d7efe684f049375d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Mon, 20 Jun 2022 18:11:03 -0700 Subject: [PATCH 514/777] add more comments about bpfGetFd... and kernel version compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per request on: https://googleplex-android-review.googlesource.com/c/platform/frameworks/libs/net/+/18992756 Test: N/A Signed-off-by: Maciej Żenczykowski Change-Id: I853d177623dc64fdac70ddefde3e0cc65d6b2c9a --- .../bpf_syscall_wrappers/include/BpfSyscallWrappers.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h index 4b29c4487a..d5b7670158 100644 --- a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h +++ b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h @@ -150,8 +150,12 @@ inline int detachSingleProgram(bpf_attach_type type, const BPF_FD_TYPE prog_fd, }); } -// requires 4.14+ kernel - +// BPF_OBJ_GET_INFO_BY_FD requires 4.14+ kernel +// +// Note: some fields are only defined in newer kernels (ie. the map_info struct grows +// over time), so we need to check that the field we're interested in is actually +// supported/returned by the running kernel. We do this by checking it is fully +// within the bounds of the struct size as reported by the kernel. #define DEFINE_BPF_GET_FD_INFO(NAME, FIELD) \ inline int bpfGetFd ## NAME(const BPF_FD_TYPE map_fd) { \ struct bpf_map_info map_info = {}; \ From 686b32c66f4c25db9a6d511ec67cfb3d6c25ce47 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Fri, 24 Jun 2022 14:56:24 +0900 Subject: [PATCH 515/777] Set min_sdk_version This was done via the hard-coded list in build/soong. Ignore-AOSP-First: merge conflict resolutions Bug: 158059172 Test: m Merged-In: Icae85d5f4564ee3f04bacb0d3dad7a80d70ee443 Change-Id: Icae85d5f4564ee3f04bacb0d3dad7a80d70ee443 --- staticlibs/Android.bp | 2 ++ .../com/android/net/module/util/LocationPermissionChecker.java | 3 +++ 2 files changed, 5 insertions(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 31a726255b..66c9eaf6b9 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -232,7 +232,9 @@ java_library { ":net-utils-framework-common-srcs", ], sdk_version: "module_current", + min_sdk_version: "29", libs: [ + "androidx.annotation_annotation", "framework-annotations-lib", "framework-connectivity.stubs.module_lib", "framework-connectivity-t.stubs.module_lib", diff --git a/staticlibs/framework/com/android/net/module/util/LocationPermissionChecker.java b/staticlibs/framework/com/android/net/module/util/LocationPermissionChecker.java index e4ce9e8004..cd1f31cbc5 100644 --- a/staticlibs/framework/com/android/net/module/util/LocationPermissionChecker.java +++ b/staticlibs/framework/com/android/net/module/util/LocationPermissionChecker.java @@ -30,6 +30,8 @@ import android.os.Build; import android.os.UserHandle; import android.util.Log; +import androidx.annotation.RequiresApi; + import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; @@ -41,6 +43,7 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ +@RequiresApi(Build.VERSION_CODES.R) public class LocationPermissionChecker { private static final String TAG = "LocationPermissionChecker"; From f20af33290e155563fa27af938a665237da70062 Mon Sep 17 00:00:00 2001 From: Hassan Ali Date: Tue, 21 Jun 2022 16:14:01 +0000 Subject: [PATCH 516/777] Use IsAtLeastS SdkLevel utility implementation Bug: 175670047 Test: m Change-Id: Ibbc11e0f1d103016883f67e2720777b43c08d282 --- staticlibs/native/netjniutils/Android.bp | 3 +++ staticlibs/native/netjniutils/netjniutils.cpp | 25 +++---------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/staticlibs/native/netjniutils/Android.bp b/staticlibs/native/netjniutils/Android.bp index d8e6a04c26..22fd1fa400 100644 --- a/staticlibs/native/netjniutils/Android.bp +++ b/staticlibs/native/netjniutils/Android.bp @@ -19,6 +19,9 @@ package { cc_library_static { name: "libnetjniutils", srcs: ["netjniutils.cpp"], + static_libs: [ + "libmodules-utils-build", + ], header_libs: ["jni_headers"], shared_libs: ["liblog"], export_header_lib_headers: ["jni_headers"], diff --git a/staticlibs/native/netjniutils/netjniutils.cpp b/staticlibs/native/netjniutils/netjniutils.cpp index 210c6c3a29..8b7f903f1a 100644 --- a/staticlibs/native/netjniutils/netjniutils.cpp +++ b/staticlibs/native/netjniutils/netjniutils.cpp @@ -15,6 +15,7 @@ #define LOG_TAG "netjniutils" #include "netjniutils/netjniutils.h" +#include #include #include @@ -29,27 +30,6 @@ namespace netjniutils { namespace { -bool IsAtLeastS() { - // TODO(b/158749603#comment19): move to android::modules::sdklevel::IsAtLeastS(). - int api_level = android_get_device_api_level(); - - // Guarded check for branches that do not have __ANDROID_API_S__. -#ifdef __ANDROID_API_S__ - if (api_level >= __ANDROID_API_S__) { - return true; - } -#endif - - if (api_level < __ANDROID_API_R__) { - return false; - } - - // Device looks like R or above, check codename as it could be (S or above). - static constexpr const char* kCodenameProperty = "ro.build.version.codename"; - char codename[PROP_VALUE_MAX] = { 0 }; - return (__system_property_get(kCodenameProperty, codename) > 0 && - codename[0] >= 'S' && codename[1] == '\0'); -} int GetNativeFileDescriptorWithoutNdk(JNIEnv* env, jobject javaFd) { // Prior to Android S, we need to find the descriptor field in the FileDescriptor class. The @@ -92,7 +72,8 @@ int GetNativeFileDescriptorWithNdk(JNIEnv* env, jobject javaFd) { } // namespace int GetNativeFileDescriptor(JNIEnv* env, jobject javaFd) { - static const bool preferNdkFileDescriptorApi = []() -> bool { return IsAtLeastS(); }(); + static const bool preferNdkFileDescriptorApi = []() -> bool + { return android::modules::sdklevel::IsAtLeastS(); }(); if (preferNdkFileDescriptorApi) { return GetNativeFileDescriptorWithNdk(env, javaFd); } else { From c89302f198020008eaadae1659984db4b49815cc Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Wed, 29 Jun 2022 17:24:45 +0800 Subject: [PATCH 517/777] Move struct {Clat*, Tether4*, TetherStats*} to connectivity module Needed because these struct classes should not be exposed. Only used for the connectivity module and its integration test. Bug: 234160319 Test: atest ConnectivityCoverageTests Change-Id: I7ad2a711807d2ee0bb95d9be1d038c6b07143052 --- staticlibs/Android.bp | 1 - .../net/module/util/bpf/ClatEgress4Key.java | 37 ------- .../net/module/util/bpf/ClatEgress4Value.java | 46 --------- .../net/module/util/bpf/ClatIngress6Key.java | 41 -------- .../module/util/bpf/ClatIngress6Value.java | 37 ------- .../net/module/util/bpf/Tether4Key.java | 81 ---------------- .../net/module/util/bpf/Tether4Value.java | 97 ------------------- .../net/module/util/bpf/TetherStatsKey.java | 53 ---------- .../net/module/util/bpf/TetherStatsValue.java | 80 --------------- 9 files changed, 473 deletions(-) delete mode 100644 staticlibs/device/com/android/net/module/util/bpf/ClatEgress4Key.java delete mode 100644 staticlibs/device/com/android/net/module/util/bpf/ClatEgress4Value.java delete mode 100644 staticlibs/device/com/android/net/module/util/bpf/ClatIngress6Key.java delete mode 100644 staticlibs/device/com/android/net/module/util/bpf/ClatIngress6Value.java delete mode 100644 staticlibs/device/com/android/net/module/util/bpf/Tether4Key.java delete mode 100644 staticlibs/device/com/android/net/module/util/bpf/Tether4Value.java delete mode 100644 staticlibs/device/com/android/net/module/util/bpf/TetherStatsKey.java delete mode 100644 staticlibs/device/com/android/net/module/util/bpf/TetherStatsValue.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 31a726255b..81e985c50b 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -118,7 +118,6 @@ java_library { "device/com/android/net/module/util/JniUtil.java", "device/com/android/net/module/util/Struct.java", "device/com/android/net/module/util/TcUtils.java", - "device/com/android/net/module/util/bpf/*.java", ], sdk_version: "module_current", min_sdk_version: "29", diff --git a/staticlibs/device/com/android/net/module/util/bpf/ClatEgress4Key.java b/staticlibs/device/com/android/net/module/util/bpf/ClatEgress4Key.java deleted file mode 100644 index 12200ec60f..0000000000 --- a/staticlibs/device/com/android/net/module/util/bpf/ClatEgress4Key.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 com.android.net.module.util.bpf; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.net.Inet4Address; - -/** Key type for clat egress IPv4 maps. */ -public class ClatEgress4Key extends Struct { - @Field(order = 0, type = Type.U32) - public final long iif; // The input interface index - - @Field(order = 1, type = Type.Ipv4Address) - public final Inet4Address local4; // The source IPv4 address - - public ClatEgress4Key(final long iif, final Inet4Address local4) { - this.iif = iif; - this.local4 = local4; - } -} diff --git a/staticlibs/device/com/android/net/module/util/bpf/ClatEgress4Value.java b/staticlibs/device/com/android/net/module/util/bpf/ClatEgress4Value.java deleted file mode 100644 index c10cb4da32..0000000000 --- a/staticlibs/device/com/android/net/module/util/bpf/ClatEgress4Value.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 com.android.net.module.util.bpf; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.net.Inet6Address; - -/** Value type for clat egress IPv4 maps. */ -public class ClatEgress4Value extends Struct { - @Field(order = 0, type = Type.U32) - public final long oif; // The output interface to redirect to - - @Field(order = 1, type = Type.Ipv6Address) - public final Inet6Address local6; // The full 128-bits of the source IPv6 address - - @Field(order = 2, type = Type.Ipv6Address) - public final Inet6Address pfx96; // The destination /96 nat64 prefix, bottom 32 bits must be 0 - - @Field(order = 3, type = Type.U8, padding = 3) - public final short oifIsEthernet; // Whether the output interface requires ethernet header - - public ClatEgress4Value(final long oif, final Inet6Address local6, final Inet6Address pfx96, - final short oifIsEthernet) { - this.oif = oif; - this.local6 = local6; - this.pfx96 = pfx96; - this.oifIsEthernet = oifIsEthernet; - } -} diff --git a/staticlibs/device/com/android/net/module/util/bpf/ClatIngress6Key.java b/staticlibs/device/com/android/net/module/util/bpf/ClatIngress6Key.java deleted file mode 100644 index 1e2f4e06d6..0000000000 --- a/staticlibs/device/com/android/net/module/util/bpf/ClatIngress6Key.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 com.android.net.module.util.bpf; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.net.Inet6Address; - -/** Key type for clat ingress IPv6 maps. */ -public class ClatIngress6Key extends Struct { - @Field(order = 0, type = Type.U32) - public final long iif; // The input interface index - - @Field(order = 1, type = Type.Ipv6Address) - public final Inet6Address pfx96; // The source /96 nat64 prefix, bottom 32 bits must be 0 - - @Field(order = 2, type = Type.Ipv6Address) - public final Inet6Address local6; // The full 128-bits of the destination IPv6 address - - public ClatIngress6Key(final long iif, final Inet6Address pfx96, final Inet6Address local6) { - this.iif = iif; - this.pfx96 = pfx96; - this.local6 = local6; - } -} diff --git a/staticlibs/device/com/android/net/module/util/bpf/ClatIngress6Value.java b/staticlibs/device/com/android/net/module/util/bpf/ClatIngress6Value.java deleted file mode 100644 index bfec44fac2..0000000000 --- a/staticlibs/device/com/android/net/module/util/bpf/ClatIngress6Value.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 com.android.net.module.util.bpf; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.net.Inet4Address; - -/** Value type for clat ingress IPv6 maps. */ -public class ClatIngress6Value extends Struct { - @Field(order = 0, type = Type.U32) - public final long oif; // The output interface to redirect to (0 means don't redirect) - - @Field(order = 1, type = Type.Ipv4Address) - public final Inet4Address local4; // The destination IPv4 address - - public ClatIngress6Value(final long oif, final Inet4Address local4) { - this.oif = oif; - this.local4 = local4; - } -} diff --git a/staticlibs/device/com/android/net/module/util/bpf/Tether4Key.java b/staticlibs/device/com/android/net/module/util/bpf/Tether4Key.java deleted file mode 100644 index 638576f026..0000000000 --- a/staticlibs/device/com/android/net/module/util/bpf/Tether4Key.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.net.module.util.bpf; - -import android.net.MacAddress; - -import androidx.annotation.NonNull; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.net.Inet4Address; -import java.net.UnknownHostException; -import java.util.Objects; - -/** Key type for downstream & upstream IPv4 forwarding maps. */ -public class Tether4Key extends Struct { - @Field(order = 0, type = Type.U32) - public final long iif; - - @Field(order = 1, type = Type.EUI48) - public final MacAddress dstMac; - - @Field(order = 2, type = Type.U8, padding = 1) - public final short l4proto; - - @Field(order = 3, type = Type.ByteArray, arraysize = 4) - public final byte[] src4; - - @Field(order = 4, type = Type.ByteArray, arraysize = 4) - public final byte[] dst4; - - @Field(order = 5, type = Type.UBE16) - public final int srcPort; - - @Field(order = 6, type = Type.UBE16) - public final int dstPort; - - public Tether4Key(final long iif, @NonNull final MacAddress dstMac, final short l4proto, - final byte[] src4, final byte[] dst4, final int srcPort, - final int dstPort) { - Objects.requireNonNull(dstMac); - - this.iif = iif; - this.dstMac = dstMac; - this.l4proto = l4proto; - this.src4 = src4; - this.dst4 = dst4; - this.srcPort = srcPort; - this.dstPort = dstPort; - } - - @Override - public String toString() { - try { - return String.format( - "iif: %d, dstMac: %s, l4proto: %d, src4: %s, dst4: %s, " - + "srcPort: %d, dstPort: %d", - iif, dstMac, l4proto, - Inet4Address.getByAddress(src4), Inet4Address.getByAddress(dst4), - Short.toUnsignedInt((short) srcPort), Short.toUnsignedInt((short) dstPort)); - } catch (UnknownHostException | IllegalArgumentException e) { - return String.format("Invalid IP address", e); - } - } -} diff --git a/staticlibs/device/com/android/net/module/util/bpf/Tether4Value.java b/staticlibs/device/com/android/net/module/util/bpf/Tether4Value.java deleted file mode 100644 index de98766ee3..0000000000 --- a/staticlibs/device/com/android/net/module/util/bpf/Tether4Value.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.net.module.util.bpf; - -import android.net.MacAddress; - -import androidx.annotation.NonNull; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Objects; - -/** Value type for downstream & upstream IPv4 forwarding maps. */ -public class Tether4Value extends Struct { - @Field(order = 0, type = Type.U32) - public final long oif; - - // The ethhdr struct which is defined in uapi/linux/if_ether.h - @Field(order = 1, type = Type.EUI48) - public final MacAddress ethDstMac; - @Field(order = 2, type = Type.EUI48) - public final MacAddress ethSrcMac; - @Field(order = 3, type = Type.UBE16) - public final int ethProto; // Packet type ID field. - - @Field(order = 4, type = Type.U16) - public final int pmtu; - - @Field(order = 5, type = Type.ByteArray, arraysize = 16) - public final byte[] src46; - - @Field(order = 6, type = Type.ByteArray, arraysize = 16) - public final byte[] dst46; - - @Field(order = 7, type = Type.UBE16) - public final int srcPort; - - @Field(order = 8, type = Type.UBE16) - public final int dstPort; - - // TODO: consider using U64. - @Field(order = 9, type = Type.U63) - public final long lastUsed; - - public Tether4Value(final long oif, @NonNull final MacAddress ethDstMac, - @NonNull final MacAddress ethSrcMac, final int ethProto, final int pmtu, - final byte[] src46, final byte[] dst46, final int srcPort, - final int dstPort, final long lastUsed) { - Objects.requireNonNull(ethDstMac); - Objects.requireNonNull(ethSrcMac); - - this.oif = oif; - this.ethDstMac = ethDstMac; - this.ethSrcMac = ethSrcMac; - this.ethProto = ethProto; - this.pmtu = pmtu; - this.src46 = src46; - this.dst46 = dst46; - this.srcPort = srcPort; - this.dstPort = dstPort; - this.lastUsed = lastUsed; - } - - @Override - public String toString() { - try { - return String.format( - "oif: %d, ethDstMac: %s, ethSrcMac: %s, ethProto: %d, pmtu: %d, " - + "src46: %s, dst46: %s, srcPort: %d, dstPort: %d, " - + "lastUsed: %d", - oif, ethDstMac, ethSrcMac, ethProto, pmtu, - InetAddress.getByAddress(src46), InetAddress.getByAddress(dst46), - Short.toUnsignedInt((short) srcPort), Short.toUnsignedInt((short) dstPort), - lastUsed); - } catch (UnknownHostException | IllegalArgumentException e) { - return String.format("Invalid IP address", e); - } - } -} diff --git a/staticlibs/device/com/android/net/module/util/bpf/TetherStatsKey.java b/staticlibs/device/com/android/net/module/util/bpf/TetherStatsKey.java deleted file mode 100644 index c6d595be64..0000000000 --- a/staticlibs/device/com/android/net/module/util/bpf/TetherStatsKey.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.net.module.util.bpf; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** The key of BpfMap which is used for tethering stats. */ -public class TetherStatsKey extends Struct { - @Field(order = 0, type = Type.U32) - public final long ifindex; // upstream interface index - - public TetherStatsKey(final long ifindex) { - this.ifindex = ifindex; - } - - // TODO: remove equals, hashCode and toString once aosp/1536721 is merged. - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - - if (!(obj instanceof TetherStatsKey)) return false; - - final TetherStatsKey that = (TetherStatsKey) obj; - - return ifindex == that.ifindex; - } - - @Override - public int hashCode() { - return Long.hashCode(ifindex); - } - - @Override - public String toString() { - return String.format("ifindex: %d", ifindex); - } -} diff --git a/staticlibs/device/com/android/net/module/util/bpf/TetherStatsValue.java b/staticlibs/device/com/android/net/module/util/bpf/TetherStatsValue.java deleted file mode 100644 index 028d217a93..0000000000 --- a/staticlibs/device/com/android/net/module/util/bpf/TetherStatsValue.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.net.module.util.bpf; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** The key of BpfMap which is used for tethering stats. */ -public class TetherStatsValue extends Struct { - // Use the signed long variable to store the uint64 stats from stats BPF map. - // U63 is enough for each data element even at 5Gbps for ~468 years. - // 2^63 / (5 * 1000 * 1000 * 1000) * 8 / 86400 / 365 = 468. - @Field(order = 0, type = Type.U63) - public final long rxPackets; - @Field(order = 1, type = Type.U63) - public final long rxBytes; - @Field(order = 2, type = Type.U63) - public final long rxErrors; - @Field(order = 3, type = Type.U63) - public final long txPackets; - @Field(order = 4, type = Type.U63) - public final long txBytes; - @Field(order = 5, type = Type.U63) - public final long txErrors; - - public TetherStatsValue(final long rxPackets, final long rxBytes, final long rxErrors, - final long txPackets, final long txBytes, final long txErrors) { - this.rxPackets = rxPackets; - this.rxBytes = rxBytes; - this.rxErrors = rxErrors; - this.txPackets = txPackets; - this.txBytes = txBytes; - this.txErrors = txErrors; - } - - // TODO: remove equals, hashCode and toString once aosp/1536721 is merged. - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - - if (!(obj instanceof TetherStatsValue)) return false; - - final TetherStatsValue that = (TetherStatsValue) obj; - - return rxPackets == that.rxPackets - && rxBytes == that.rxBytes - && rxErrors == that.rxErrors - && txPackets == that.txPackets - && txBytes == that.txBytes - && txErrors == that.txErrors; - } - - @Override - public int hashCode() { - return Long.hashCode(rxPackets) ^ Long.hashCode(rxBytes) ^ Long.hashCode(rxErrors) - ^ Long.hashCode(txPackets) ^ Long.hashCode(txBytes) ^ Long.hashCode(txErrors); - } - - @Override - public String toString() { - return String.format("rxPackets: %s, rxBytes: %s, rxErrors: %s, txPackets: %s, " - + "txBytes: %s, txErrors: %s", rxPackets, rxBytes, rxErrors, txPackets, - txBytes, txErrors); - } -} From b3b6798adc4c6bc45a680d825cba45525913992d Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Fri, 24 Jun 2022 14:56:24 +0900 Subject: [PATCH 518/777] Set min_sdk_version This was done via the hard-coded list in build/soong. Bug: 158059172 Test: m Merged-In: Icae85d5f4564ee3f04bacb0d3dad7a80d70ee443 Change-Id: Icae85d5f4564ee3f04bacb0d3dad7a80d70ee443 (cherry picked from commit 6e043e136d3390f44e84bb57e4a8eeb4ec25d838) --- staticlibs/Android.bp | 2 ++ .../com/android/net/module/util/LocationPermissionChecker.java | 3 +++ 2 files changed, 5 insertions(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 31a726255b..66c9eaf6b9 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -232,7 +232,9 @@ java_library { ":net-utils-framework-common-srcs", ], sdk_version: "module_current", + min_sdk_version: "29", libs: [ + "androidx.annotation_annotation", "framework-annotations-lib", "framework-connectivity.stubs.module_lib", "framework-connectivity-t.stubs.module_lib", diff --git a/staticlibs/framework/com/android/net/module/util/LocationPermissionChecker.java b/staticlibs/framework/com/android/net/module/util/LocationPermissionChecker.java index e4ce9e8004..cd1f31cbc5 100644 --- a/staticlibs/framework/com/android/net/module/util/LocationPermissionChecker.java +++ b/staticlibs/framework/com/android/net/module/util/LocationPermissionChecker.java @@ -30,6 +30,8 @@ import android.os.Build; import android.os.UserHandle; import android.util.Log; +import androidx.annotation.RequiresApi; + import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; @@ -41,6 +43,7 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ +@RequiresApi(Build.VERSION_CODES.R) public class LocationPermissionChecker { private static final String TAG = "LocationPermissionChecker"; From b3e71a2959bd178f90bf06e85e5cd6c974d94247 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Thu, 23 Jun 2022 21:34:54 +0800 Subject: [PATCH 519/777] Add BpfDump.toBase64EncodedString to dump raw map Move base64 related bpf map function and constant from BpfCoordinator. This is preparation for testing BPF map in ClatCoordinator. Test: atest NetworkStaticLibTests Change-Id: I3a23393abe5b108cdb8d621e99b74fd20847474e --- staticlibs/Android.bp | 1 + .../com/android/net/module/util/BpfDump.java | 49 +++++++++++++++++++ .../android/net/module/util/BpfDumpTest.java | 43 ++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/BpfDump.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 31a726255b..e5f8d58f85 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -111,6 +111,7 @@ java_library { name: "net-utils-device-common-bpf", srcs: [ "device/com/android/net/module/util/BpfBitmap.java", + "device/com/android/net/module/util/BpfDump.java", "device/com/android/net/module/util/BpfMap.java", "device/com/android/net/module/util/BpfUtils.java", "device/com/android/net/module/util/HexDump.java", diff --git a/staticlibs/device/com/android/net/module/util/BpfDump.java b/staticlibs/device/com/android/net/module/util/BpfDump.java new file mode 100644 index 0000000000..fec225c10a --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/BpfDump.java @@ -0,0 +1,49 @@ +/* + * 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 com.android.net.module.util; + +import android.util.Base64; + +import androidx.annotation.NonNull; + +/** + * The classes and the methods for BPF dump utilization. + */ +public class BpfDump { + // Using "," as a separator between base64 encoded key and value is safe because base64 + // characters are [0-9a-zA-Z/=+]. + public static final String BASE64_DELIMITER = ","; + + /** + * Encode BPF key and value into a base64 format string which uses the delimiter ',': + * , + */ + public static String toBase64EncodedString( + @NonNull final K key, @NonNull final V value) { + final byte[] keyBytes = key.writeToBytes(); + final String keyBase64Str = Base64.encodeToString(keyBytes, Base64.DEFAULT) + .replace("\n", ""); + final byte[] valueBytes = value.writeToBytes(); + final String valueBase64Str = Base64.encodeToString(valueBytes, Base64.DEFAULT) + .replace("\n", ""); + + return keyBase64Str + BASE64_DELIMITER + valueBase64Str; + } + + // TODO: add a helper to dump bpf map content with the map name, the header line + // (ex: "BPF ingress map: iif nat64Prefix v6Addr -> v4Addr oif"), a lambda that + // knows how to dump each line, and the PrintWriter. +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java new file mode 100644 index 0000000000..b166b4a4db --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java @@ -0,0 +1,43 @@ +/* + * 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 com.android.net.module.util; + +import static org.junit.Assert.assertEquals; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class BpfDumpTest { + @Test + public void testToBase64EncodedString() { + final Struct.U32 key = new Struct.U32(123); + final Struct.U32 value = new Struct.U32(456); + + // Verified in python: + // import base64 + // print(base64.b64encode(b'\x7b\x00\x00\x00')) # key: ewAAAA== + // print(base64.b64encode(b'\xc8\x01\x00\x00')) # value: yAEAAA== + assertEquals("7B000000", HexDump.toHexString(key.writeToBytes())); + assertEquals("C8010000", HexDump.toHexString(value.writeToBytes())); + assertEquals("ewAAAA==,yAEAAA==", BpfDump.toBase64EncodedString(key, value)); + } +} From 3b5af9962d5f59bbb2505d9c3d408fc3d3246e79 Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Wed, 22 Jun 2022 01:08:35 +0000 Subject: [PATCH 520/777] Add more tests to cover SharedLog methods Add tests for SharedLog methods that do not have test coverage. - SharedLog#reverseDump(java.io.PrintWriter) - SharedLog#e(java.lang.Exception) - SharedLog#getTag() - SharedLog#i(java.lang.String) - SharedLog#logf(java.lang.String, java.lang.Object[]) - SharedLog$LocalLog#reverseDump(java.io.PrintWriter) Bug: 236768003 Test: atest NetworkStaticLibTests Change-Id: I465b8e2d528fe70cddc49257d14fecad948fc50f --- .../net/module/util/SharedLogTest.java | 58 +++++++++++++++---- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/SharedLogTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/SharedLogTest.java index 446e8819fd..aa1bfee4dd 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/SharedLogTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/SharedLogTest.java @@ -17,6 +17,8 @@ package com.android.net.module.util; 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 androidx.test.filters.SmallTest; @@ -27,16 +29,24 @@ import org.junit.runner.RunWith; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; @RunWith(AndroidJUnit4.class) @SmallTest public class SharedLogTest { private static final String TIMESTAMP_PATTERN = "\\d{2}:\\d{2}:\\d{2}"; private static final String TIMESTAMP = "HH:MM:SS"; + private static final String TAG = "top"; @Test public void testBasicOperation() { - final SharedLog logTop = new SharedLog("top"); + final SharedLog logTop = new SharedLog(TAG); + assertTrue(TAG.equals(logTop.getTag())); + logTop.mark("first post!"); final SharedLog logLevel2a = logTop.forSubComponent("twoA"); @@ -48,8 +58,10 @@ public class SharedLogTest { final SharedLog logLevel3 = logLevel2a.forSubComponent("three"); logTop.log("still logging"); - logLevel3.log("3 >> 2"); + logLevel2b.e(new Exception("Got another exception")); + logLevel3.i("3 >> 2"); logLevel2a.mark("ok: last post"); + logTop.logf("finished!"); final String[] expected = { " - MARK first post!", @@ -59,29 +71,53 @@ public class SharedLogTest { " - [twoB] ERROR Wait, here's one: Test", " - [twoA] WARN second post?", " - still logging", + " - [twoB] ERROR java.lang.Exception: Got another exception", " - [twoA.three] 3 >> 2", " - [twoA] MARK ok: last post", + " - finished!", }; // Verify the logs are all there and in the correct order. - verifyLogLines(expected, logTop); + assertDumpLogs(expected, logTop); // In fact, because they all share the same underlying LocalLog, // every subcomponent SharedLog's dump() is identical. - verifyLogLines(expected, logLevel2a); - verifyLogLines(expected, logLevel2b); - verifyLogLines(expected, logLevel3); + assertDumpLogs(expected, logLevel2a); + assertDumpLogs(expected, logLevel2b); + assertDumpLogs(expected, logLevel3); } - private static void verifyLogLines(String[] expected, SharedLog log) { + private static void assertDumpLogs(String[] expected, SharedLog log) { + verifyLogLines(expected, dump(log)); + verifyLogLines(reverse(expected), reverseDump(log)); + } + + private static String dump(SharedLog log) { + return getSharedLogString(pw -> log.dump(null /* fd */, pw, null /* args */)); + } + + private static String reverseDump(SharedLog log) { + return getSharedLogString(pw -> log.reverseDump(pw)); + } + + private static String[] reverse(String[] ary) { + final List ls = new ArrayList<>(Arrays.asList(ary)); + Collections.reverse(ls); + return ls.toArray(new String[ary.length]); + } + + private static String getSharedLogString(Consumer functor) { final ByteArrayOutputStream ostream = new ByteArrayOutputStream(); final PrintWriter pw = new PrintWriter(ostream, true); - log.dump(null, pw, null); + functor.accept(pw); final String dumpOutput = ostream.toString(); - assertTrue(dumpOutput != null); - assertTrue(!"".equals(dumpOutput)); + assertNotNull(dumpOutput); + assertFalse("".equals(dumpOutput)); + return dumpOutput; + } - final String[] lines = dumpOutput.split("\n"); + private static void verifyLogLines(String[] expected, String gottenLogs) { + final String[] lines = gottenLogs.split("\n"); assertEquals(expected.length, lines.length); for (int i = 0; i < expected.length; i++) { From b6338cec030c3c1d53f130f9d20c08fe03109739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 15 Jul 2022 13:00:21 -0700 Subject: [PATCH 521/777] define BPFLOADER_OBJ_AT_VER_VERSION as 25 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BpfLoader v0.25+ support loading obj@ver.o files as if they were obj.o. This allows different versions of the .o per bpfloader version. This is useful because BTF enabled bpf.o files are incompatible with BpfLoader < 0.10. Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I2067b1c54c36842c0baa779f37a904b75b9dfb6d --- staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 8bc8eb17e4..b60ab4cf3b 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -37,6 +37,9 @@ // Android T / 13 (api level 33) - support for shared/selinux_context/pindir #define BPFLOADER_T_VERSION 19u +// BpfLoader v0.25+ support obj@ver.o files +#define BPFLOADER_OBJ_AT_VER_VERSION 25u + /* For mainline module use, you can #define BPFLOADER_{MIN/MAX}_VER * before #include "bpf_helpers.h" to change which bpfloaders will * process the resulting .o file. From 72e19c51fa8f5ed2e5b2605a2fc5d7db1f4979ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 8 Jul 2022 14:22:57 -0700 Subject: [PATCH 522/777] Bpf maps & programs: support DEFAULT_BPF_(MAP|PROG)_(UID|SELINUX_CONTEXT|PIN_SUBDIR) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sometimes you just want to change the setting for all maps and/or programs in a specific .c file... Bug: 190523685 Bug: 236925089 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I3ba6b3a8dadf18c1436b21feb1ee03db446e6aba --- .../bpf_headers/include/bpf/bpf_helpers.h | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index b60ab4cf3b..236318d699 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -182,20 +182,39 @@ static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, return bpf_map_delete_elem_unsafe(&the_map, k); \ }; +#ifndef DEFAULT_BPF_MAP_SELINUX_CONTEXT +#define DEFAULT_BPF_MAP_SELINUX_CONTEXT "" +#endif + +#ifndef DEFAULT_BPF_MAP_PIN_SUBDIR +#define DEFAULT_BPF_MAP_PIN_SUBDIR "" +#endif + +#ifndef DEFAULT_BPF_MAP_UID +#define DEFAULT_BPF_MAP_UID AID_ROOT +#elif BPFLOADER_MIN_VER < 21u +#error "Bpf Map UID must be left at default of AID_ROOT for BpfLoader prior to v0.21" +#endif + #define DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md) \ - DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, "", "", false) + DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, \ + DEFAULT_BPF_MAP_SELINUX_CONTEXT, DEFAULT_BPF_MAP_PIN_SUBDIR, false) #define DEFINE_BPF_MAP(the_map, TYPE, KeyType, ValueType, num_entries) \ - DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, AID_ROOT, 0600) + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \ + DEFAULT_BPF_MAP_UID, AID_ROOT, 0600) #define DEFINE_BPF_MAP_GWO(the_map, TYPE, KeyType, ValueType, num_entries, gid) \ - DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, gid, 0620) + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \ + DEFAULT_BPF_MAP_UID, gid, 0620) #define DEFINE_BPF_MAP_GRO(the_map, TYPE, KeyType, ValueType, num_entries, gid) \ - DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, gid, 0640) + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \ + DEFAULT_BPF_MAP_UID, gid, 0640) #define DEFINE_BPF_MAP_GRW(the_map, TYPE, KeyType, ValueType, num_entries, gid) \ - DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, AID_ROOT, gid, 0660) + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \ + DEFAULT_BPF_MAP_UID, gid, 0660) static int (*bpf_probe_read)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read; static int (*bpf_probe_read_str)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read_str; @@ -224,9 +243,18 @@ static long (*bpf_get_current_comm)(void* buf, uint32_t buf_size) = (void*) BPF_ SECTION(SECTION_NAME) \ int the_prog +#ifndef DEFAULT_BPF_PROG_SELINUX_CONTEXT +#define DEFAULT_BPF_PROG_SELINUX_CONTEXT "" +#endif + +#ifndef DEFAULT_BPF_PROG_PIN_SUBDIR +#define DEFAULT_BPF_PROG_PIN_SUBDIR "" +#endif + #define DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \ opt) \ - DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, opt, "", "") + DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, opt, \ + DEFAULT_BPF_PROG_SELINUX_CONTEXT, DEFAULT_BPF_PROG_PIN_SUBDIR) // Programs (here used in the sense of functions/sections) marked optional are allowed to fail // to load (for example due to missing kernel patches). From 12ac792079d4c9a3fbc2132ef9cdb59a9e67732a Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 20 Jul 2022 15:02:00 +0900 Subject: [PATCH 523/777] Add CtsNetTestCasesMaxTargetSdk30 The annotation is used to verify behavior for apps with max target SDK 30. Bug: 235355681 Test: atest CtsNetTestCasesMaxTargetSdk30 Change-Id: Idb358ee1179bc3b6ef9ddbe7b567532822bdc64e --- .../filters/CtsNetTestCasesMaxTargetSdk30.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/filters/CtsNetTestCasesMaxTargetSdk30.kt diff --git a/staticlibs/testutils/devicetests/com/android/testutils/filters/CtsNetTestCasesMaxTargetSdk30.kt b/staticlibs/testutils/devicetests/com/android/testutils/filters/CtsNetTestCasesMaxTargetSdk30.kt new file mode 100644 index 0000000000..843c41e6fa --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/filters/CtsNetTestCasesMaxTargetSdk30.kt @@ -0,0 +1,22 @@ +/* + * 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 com.android.testutils.filters + +/** + * Only run this test in the CtsNetTestCasesMaxTargetSdk30 suite. + */ +annotation class CtsNetTestCasesMaxTargetSdk30(val reason: String) From a2469f36fc4ff605ba2e686540c1d6d08016e734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 21 Jul 2022 08:56:03 +0000 Subject: [PATCH 524/777] bpf_map_def: rename uid to 'zero', add new uid field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 239807354 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I13dce79dc11956c1903645a442bd00bd6d499a32 --- staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h index 14a0295922..2d47426f39 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h @@ -143,7 +143,7 @@ struct bpf_map_def { // unsigned int inner_map_idx; // unsigned int numa_node; - unsigned int uid; // uid_t + unsigned int zero; // uid_t, for compat with old (buggy) bpfloader must be AID_ROOT == 0 unsigned int gid; // gid_t unsigned int mode; // mode_t @@ -171,13 +171,15 @@ struct bpf_map_def { bool shared; // use empty string as 'file' component of pin path - allows cross .o map sharing char pad0[3]; // manually pad up to 4 byte alignment, may be used for extensions in the future + + unsigned int uid; // uid_t }; _Static_assert(sizeof(((struct bpf_map_def *)0)->selinux_context) == 32, "must be 32 bytes"); _Static_assert(sizeof(((struct bpf_map_def *)0)->pin_subdir) == 32, "must be 32 bytes"); // This needs to be updated whenever the above structure definition is expanded. -_Static_assert(sizeof(struct bpf_map_def) == 116, "sizeof struct bpf_map_def != 116"); +_Static_assert(sizeof(struct bpf_map_def) == 120, "sizeof struct bpf_map_def != 120"); _Static_assert(__alignof__(struct bpf_map_def) == 4, "__alignof__ struct bpf_map_def != 4"); _Static_assert(_Alignof(struct bpf_map_def) == 4, "_Alignof struct bpf_map_def != 4"); From eb4194e8523c4596c588b970d9b5c8276f889f17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 21 Jul 2022 13:33:16 +0000 Subject: [PATCH 525/777] BpfLoader v0.21-v0.27 don't support map uid at the new location MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 239807354 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: If55ab36c1434e28d293135a97b87351de9f39686 --- staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 236318d699..a21e6855df 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -192,8 +192,8 @@ static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, #ifndef DEFAULT_BPF_MAP_UID #define DEFAULT_BPF_MAP_UID AID_ROOT -#elif BPFLOADER_MIN_VER < 21u -#error "Bpf Map UID must be left at default of AID_ROOT for BpfLoader prior to v0.21" +#elif BPFLOADER_MIN_VER < 28u +#error "Bpf Map UID must be left at default of AID_ROOT for BpfLoader prior to v0.28" #endif #define DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md) \ From 406063f0e2753138dd2b91b4237817b8e0dc9ce1 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Thu, 7 Jul 2022 16:22:27 -0700 Subject: [PATCH 526/777] RaResponder: add support for NS/NA for tests Add support to respond to neighbor solicitations in addition to router solicitations. This is useful for tests that need to send IPv6 traffic through a tap interface. I have previously experimented with the target link-layer address option in the RA, but it did not seem to prevent a subsequent NS. As a TODO, this class should be renamed to NdResponder (and possibly rewritten in Kotlin). Test: test only change Bug: 235559605 Change-Id: I33bac507082fa89d1a5ae02cbe671ce7f5f09b07 --- .../RouterAdvertisementResponder.java | 103 ++++++++++++++---- 1 file changed, 79 insertions(+), 24 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java b/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java index 4ad93d85ce..91c3f766d4 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java @@ -18,12 +18,14 @@ package com.android.testutils; import static android.system.OsConstants.IPPROTO_ICMPV6; -import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN; -import static com.android.net.module.util.NetworkStackConstants.ETHER_SRC_ADDR_OFFSET; import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION; import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_NODES_MULTICAST; -import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST; +import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE; +import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER; +import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED; import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_AUTONOMOUS; import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_ON_LINK; @@ -31,6 +33,7 @@ import android.net.InetAddresses; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.MacAddress; +import android.util.ArrayMap; import android.util.Pair; import com.android.net.module.util.Ipv6Utils; @@ -38,18 +41,19 @@ import com.android.net.module.util.Struct; import com.android.net.module.util.structs.EthernetHeader; import com.android.net.module.util.structs.Icmpv6Header; import com.android.net.module.util.structs.Ipv6Header; +import com.android.net.module.util.structs.LlaOption; +import com.android.net.module.util.structs.NsHeader; import com.android.net.module.util.structs.PrefixInformationOption; import com.android.net.module.util.structs.RdnssOption; import java.io.IOException; import java.net.Inet6Address; import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.Map; /** - * RA responder class useful for tests that require a provisioned interface. + * ND (RA & NA) responder class useful for tests that require a provisioned IPv6 interface. + * TODO: rename to NdResponder */ public class RouterAdvertisementResponder extends PacketResponder { private static final String TAG = "RouterAdvertisementResponder"; @@ -57,26 +61,28 @@ public class RouterAdvertisementResponder extends PacketResponder { private static final Inet6Address DNS_SERVER = (Inet6Address) InetAddresses.parseNumericAddress("2001:4860:4860::64"); private final TapPacketReader mPacketReader; - private final List> mRouterList = new ArrayList<>(); + // Maps IPv6 address to MacAddress and isRouter boolean. + private final Map> mNeighborMap = new ArrayMap<>(); public RouterAdvertisementResponder(TapPacketReader packetReader) { - super(packetReader, RouterAdvertisementResponder::isRouterSolicitation, TAG); + super(packetReader, RouterAdvertisementResponder::isRsOrNs, TAG); mPacketReader = packetReader; } - private static boolean isRouterSolicitation(byte[] packet) { + /** Returns true if the packet is a router solicitation or neighbor solicitation message. */ + private static boolean isRsOrNs(byte[] packet) { final ByteBuffer buffer = ByteBuffer.wrap(packet); final EthernetHeader ethHeader = Struct.parse(EthernetHeader.class, buffer); if (ethHeader.etherType != ETHER_TYPE_IPV6) { return false; } final Ipv6Header ipv6Header = Struct.parse(Ipv6Header.class, buffer); - if (ipv6Header.nextHeader != IPPROTO_ICMPV6 - || !ipv6Header.dstIp.equals(IPV6_ADDR_ALL_ROUTERS_MULTICAST)) { + if (ipv6Header.nextHeader != IPPROTO_ICMPV6) { return false; } final Icmpv6Header icmpv6Header = Struct.parse(Icmpv6Header.class, buffer); - return icmpv6Header.type == ICMPV6_ROUTER_SOLICITATION; + return icmpv6Header.type == ICMPV6_ROUTER_SOLICITATION + || icmpv6Header.type == ICMPV6_NEIGHBOR_SOLICITATION; } /** @@ -85,7 +91,16 @@ public class RouterAdvertisementResponder extends PacketResponder { * @param ip the link-local address of the router. */ public void addRouterEntry(MacAddress mac, Inet6Address ip) { - mRouterList.add(new Pair<>(mac, ip)); + mNeighborMap.put(ip, new Pair<>(mac, true)); + } + + /** + * Adds a new neighbor to be advertised. + * @param mac the mac address of the neighbor. + * @param ip the link-local address of the neighbor. + */ + public void addNeighborEntry(MacAddress mac, Inet6Address ip) { + mNeighborMap.put(ip, new Pair<>(mac, false)); } private ByteBuffer buildPrefixOption() { @@ -105,19 +120,59 @@ public class RouterAdvertisementResponder extends PacketResponder { 0/*retransTimer, unspecified*/, buildPrefixOption(), buildRdnssOption()); } + private static void sendResponse(TapPacketReader reader, ByteBuffer buffer) { + try { + reader.sendResponse(buffer); + } catch (IOException e) { + throw new RuntimeException("Failed to send buffer."); + } + } + + private void replyToRouterSolicitation(TapPacketReader reader, MacAddress dstMac) { + for (Map.Entry> it : mNeighborMap.entrySet()) { + final boolean isRouter = it.getValue().second; + if (!isRouter) { + continue; + } + final ByteBuffer raResponse = buildRaPacket(it.getValue().first, dstMac, it.getKey()); + sendResponse(reader, raResponse); + } + } + + private void replyToNeighborSolicitation(TapPacketReader reader, MacAddress dstMac, + Inet6Address dstIp, Inet6Address targetIp) { + final Pair neighbor = mNeighborMap.get(targetIp); + if (neighbor == null) { + return; + } + + final MacAddress srcMac = neighbor.first; + final boolean isRouter = neighbor.second; + int flags = NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED | NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE; + if (isRouter) { + flags |= NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER; + } + + final ByteBuffer tlla = LlaOption.build((byte) ICMPV6_ND_OPTION_TLLA, srcMac); + final ByteBuffer naResponse = Ipv6Utils.buildNaPacket(srcMac, dstMac, targetIp, dstIp, + flags, targetIp, tlla); + sendResponse(reader, naResponse); + } + @Override protected void replyToPacket(byte[] packet, TapPacketReader reader) { - final MacAddress srcMac = MacAddress.fromBytes( - Arrays.copyOfRange(packet, ETHER_SRC_ADDR_OFFSET, - ETHER_SRC_ADDR_OFFSET + ETHER_ADDR_LEN)); + final ByteBuffer buf = ByteBuffer.wrap(packet); + // Messages are filtered by parent class, so it is safe to assume that packet is either an + // RS or NS. + final EthernetHeader ethHdr = Struct.parse(EthernetHeader.class, buf); + final Ipv6Header ipv6Hdr = Struct.parse(Ipv6Header.class, buf); + final Icmpv6Header icmpv6Header = Struct.parse(Icmpv6Header.class, buf); - for (Pair it : mRouterList) { - final ByteBuffer raResponse = buildRaPacket(it.first, srcMac, it.second); - try { - reader.sendResponse(raResponse); - } catch (IOException e) { - throw new RuntimeException("Failed to send RA"); - } + if (icmpv6Header.type == ICMPV6_ROUTER_SOLICITATION) { + replyToRouterSolicitation(reader, ethHdr.srcMac); + } else if (icmpv6Header.type == ICMPV6_NEIGHBOR_SOLICITATION) { + final NsHeader nsHeader = Struct.parse(NsHeader.class, buf); + replyToNeighborSolicitation(reader, ethHdr.srcMac, ipv6Hdr.srcIp, nsHeader.target); } } } From 53165692caa29ee7c37b098cc2df26d8aa0298bb Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Tue, 19 Jul 2022 19:30:50 -0700 Subject: [PATCH 527/777] RaResponder: add slla option to RA Test: test only change Change-Id: I75beb79cd95489c8a93bd930eb54fc0cb8168cdf --- .../android/testutils/RouterAdvertisementResponder.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java b/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java index 91c3f766d4..21cb1496e4 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java @@ -19,6 +19,7 @@ package com.android.testutils; import static android.system.OsConstants.IPPROTO_ICMPV6; import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION; @@ -114,10 +115,15 @@ public class RouterAdvertisementResponder extends PacketResponder { return RdnssOption.build(3600/*lifetime, must be at least 120*/, DNS_SERVER); } + private ByteBuffer buildSllaOption(MacAddress srcMac) { + return LlaOption.build((byte) ICMPV6_ND_OPTION_SLLA, srcMac); + } + private ByteBuffer buildRaPacket(MacAddress srcMac, MacAddress dstMac, Inet6Address srcIp) { return Ipv6Utils.buildRaPacket(srcMac, dstMac, srcIp, IPV6_ADDR_ALL_NODES_MULTICAST, (byte) 0 /*M=0, O=0*/, 3600 /*lifetime*/, 0 /*reachableTime, unspecified*/, - 0/*retransTimer, unspecified*/, buildPrefixOption(), buildRdnssOption()); + 0/*retransTimer, unspecified*/, buildPrefixOption(), buildRdnssOption(), + buildSllaOption(srcMac)); } private static void sendResponse(TapPacketReader reader, ByteBuffer buffer) { From e68c6eea82dd76b57c1714d11049a41e7d66a21e Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Mon, 25 Jul 2022 17:10:17 +0800 Subject: [PATCH 528/777] Add struct Icmpv4Header class to parse icmpv4 header from a packet Bug: 237369591 Test: atest EthernetTetheringTest Change-Id: I1023fe3bf1cb5504f8e547cfca233dbb8dfaf3c1 --- .../net/module/util/structs/Icmpv4Header.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/structs/Icmpv4Header.java diff --git a/staticlibs/device/com/android/net/module/util/structs/Icmpv4Header.java b/staticlibs/device/com/android/net/module/util/structs/Icmpv4Header.java new file mode 100644 index 0000000000..454bb0747a --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/Icmpv4Header.java @@ -0,0 +1,43 @@ +/* + * 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 com.android.net.module.util.structs; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * ICMPv4 header as per https://tools.ietf.org/html/rfc792. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class Icmpv4Header extends Struct { + @Field(order = 0, type = Type.U8) + public short type; + @Field(order = 1, type = Type.U8) + public short code; + @Field(order = 2, type = Type.S16) + public short checksum; + public Icmpv4Header(final short type, final short code, final short checksum) { + this.type = type; + this.code = code; + this.checksum = checksum; + } +} From 30a1808c1bf0f5be9ad92090b3d8ef23540db906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sun, 24 Jul 2022 22:45:35 +0000 Subject: [PATCH 529/777] Bump up BPFLOADER_MIN_VER for platform bpf.o's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Non platform ones (ie. shipped via mainline) already have the value manually specified. The goal here is to be able to do some bpf.o validity checking in the bpfloader based on the bpfloader_min_ver. Such validity checking really only makes sense for mainline shipped bpf.o's which might need to load on older bpfloaders. Hence we no longer want platform bpf.o's to have minver == 0. Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I9e2f670c48e30818689a42bc515eb49e86f3cbea --- staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h | 3 ++- staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index a21e6855df..35d9f31d1e 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -46,9 +46,10 @@ * * While this will work outside of mainline too, there just is no point to * using it when the .o and the bpfloader ship in sync with each other. + * In which case it's just best to use the default. */ #ifndef BPFLOADER_MIN_VER -#define BPFLOADER_MIN_VER DEFAULT_BPFLOADER_MIN_VER +#define BPFLOADER_MIN_VER COMPILE_FOR_BPFLOADER_VERSION #endif #ifndef BPFLOADER_MAX_VER diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h index 2d47426f39..02caf07e93 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h @@ -48,6 +48,10 @@ #define DEFAULT_SIZEOF_BPF_MAP_DEF 32 // v0.0 struct: enum (uint sized) + 7 uint #define DEFAULT_SIZEOF_BPF_PROG_DEF 20 // v0.0 struct: 4 uint + bool + 3 byte alignment pad +// By default, unless otherwise specified, allow the use of features only supported by v0.28, +// which first added working support for map uid != root +#define COMPILE_FOR_BPFLOADER_VERSION 28u + /* * The bpf_{map,prog}_def structures are compiled for different architectures. * Once by the BPF compiler for the BPF architecture, and once by a C++ From a5500c6d058c9233621acba0969fbe258c127280 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Thu, 28 Jul 2022 15:43:21 -0700 Subject: [PATCH 530/777] PacketResponder: stop should wait for thread to join stop() calls interrupt which does not terminate the thread instantly. Therefore, it should wait for the thread to join, as otherwise the caller has no way of knowing when it is safe to close the underlying fd. This led to frequent test process crashes during EthernetManagerTest runs. Test: atest EthernetManagerTest Change-Id: I28f0d46c4f0295acffa5ec9f04964cd73d3de928 --- .../devicetests/com/android/testutils/PacketResponder.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/PacketResponder.kt b/staticlibs/testutils/devicetests/com/android/testutils/PacketResponder.kt index daf29e4363..964c6c60d0 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/PacketResponder.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/PacketResponder.kt @@ -54,6 +54,7 @@ abstract class PacketResponder( */ fun stop() { replyThread.interrupt() + replyThread.join() } private inner class ReplyThread(name: String) : Thread(name) { From 4a76563701385b4fbd70e54e83c528e60cfd1cb1 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Thu, 28 Jul 2022 15:47:17 -0700 Subject: [PATCH 531/777] RaResponder: log instead of throw exception Throwing an exception in RaResponder crashes the test process (as it runs in a secondary thread). This is not very useful as that will fail the execution of all the other tests. Adding a log statement instead of throwing an exception makes more sense as the tests will most likely fail anyways. Test: atest EthernetManagerTest Change-Id: I9c5f5dc417dad7df1c7f729caa4e0259ed71591f --- .../com/android/testutils/RouterAdvertisementResponder.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java b/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java index 21cb1496e4..478161da70 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java @@ -35,6 +35,7 @@ import android.net.IpPrefix; import android.net.LinkAddress; import android.net.MacAddress; import android.util.ArrayMap; +import android.util.Log; import android.util.Pair; import com.android.net.module.util.Ipv6Utils; @@ -130,7 +131,9 @@ public class RouterAdvertisementResponder extends PacketResponder { try { reader.sendResponse(buffer); } catch (IOException e) { - throw new RuntimeException("Failed to send buffer."); + // Throwing an exception here will crash the test process. Let's stick to logging, as + // the test will fail either way. + Log.e(TAG, "Failed to send buffer", e); } } From 0b3378b7d4dfdd46692bee750f0eaa0dafafad68 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 3 Aug 2022 15:54:23 +0900 Subject: [PATCH 532/777] Randomize the prefix used by RouterAdvertisementResponder. Currently RouterAdvertisementResponder always uses a prefix of 2001:db8::/64, even if there are multiple instances on different interfaces. Randomize the prefix instead. Test: TH Bug: 240323229 Change-Id: I585ca804845f4278187602a6c9816470dcea04f8 --- .../RouterAdvertisementResponder.java | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java b/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java index 478161da70..51d57bc1f0 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java @@ -32,7 +32,6 @@ import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_ON_LINK import android.net.InetAddresses; import android.net.IpPrefix; -import android.net.LinkAddress; import android.net.MacAddress; import android.util.ArrayMap; import android.util.Log; @@ -52,6 +51,8 @@ import java.io.IOException; import java.net.Inet6Address; import java.nio.ByteBuffer; import java.util.Map; +import java.util.Objects; +import java.util.Random; /** * ND (RA & NA) responder class useful for tests that require a provisioned IPv6 interface. @@ -59,16 +60,30 @@ import java.util.Map; */ public class RouterAdvertisementResponder extends PacketResponder { private static final String TAG = "RouterAdvertisementResponder"; - private static final LinkAddress SLAAC_PREFIX = new LinkAddress("2001:db8::/64"); private static final Inet6Address DNS_SERVER = (Inet6Address) InetAddresses.parseNumericAddress("2001:4860:4860::64"); private final TapPacketReader mPacketReader; // Maps IPv6 address to MacAddress and isRouter boolean. private final Map> mNeighborMap = new ArrayMap<>(); + private final IpPrefix mPrefix; - public RouterAdvertisementResponder(TapPacketReader packetReader) { + public RouterAdvertisementResponder(TapPacketReader packetReader, IpPrefix prefix) { super(packetReader, RouterAdvertisementResponder::isRsOrNs, TAG); mPacketReader = packetReader; + mPrefix = Objects.requireNonNull(prefix); + } + + public RouterAdvertisementResponder(TapPacketReader packetReader) { + this(packetReader, makeRandomPrefix()); + } + + private static IpPrefix makeRandomPrefix() { + final byte[] prefixBytes = new IpPrefix("2001:db8::/64").getAddress().getAddress(); + final Random r = new Random(); + for (int i = 4; i < 8; i++) { + prefixBytes[i] = (byte) r.nextInt(); + } + return new IpPrefix(prefixBytes, 64); } /** Returns true if the packet is a router solicitation or neighbor solicitation message. */ @@ -105,11 +120,17 @@ public class RouterAdvertisementResponder extends PacketResponder { mNeighborMap.put(ip, new Pair<>(mac, false)); } + /** + * @return the prefix that is announced in the Router Advertisements sent by this object. + */ + public IpPrefix getPrefix() { + return mPrefix; + } + private ByteBuffer buildPrefixOption() { return PrefixInformationOption.build( - new IpPrefix(SLAAC_PREFIX.getAddress(), SLAAC_PREFIX.getPrefixLength()), - (byte) (PIO_FLAG_ON_LINK | PIO_FLAG_AUTONOMOUS), 3600/*valid lifetime*/, - 3600/*preferred lifetime*/); + mPrefix, (byte) (PIO_FLAG_ON_LINK | PIO_FLAG_AUTONOMOUS), + 3600 /* valid lifetime */, 3600 /* preferred lifetime */); } private ByteBuffer buildRdnssOption() { From 1453c7c74a48b6b0cf30f65ff12ccc6b9faa7508 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 15 Jul 2022 12:08:48 +0900 Subject: [PATCH 533/777] Move NetworkMonitorUtils to net-utils-device-common lib. Move the NetworkMonitorUtils class from NetworkStack module to frameworks/libs/net, then we can remove the filegroups defined in NetworkStack module which are shared with Connectivity module. Import the net-utils-device-common lib instead. Update the NetworkMonitorUtils#isValidationRequired() first param type to make the migration easier, change the NetworkAgentConfigShim type param to boolean, which can be passed by the caller directly such as in ConnectivityServiceTest or NetworkMonitor, then we don't need to add static lib to support NetworkAgentConfigShim, not easy to support. Bug: 238960524 Test: m Change-Id: I72dfb5902dea0e7ddb2c33a08f874fe36adcbeec --- staticlibs/Android.bp | 2 + .../net/module/util/NetworkMonitorUtils.java | 113 ++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/NetworkMonitorUtils.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index d13f9387f8..c04d1d464b 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -37,6 +37,7 @@ java_library { "device/com/android/net/module/util/DeviceConfigUtils.java", "device/com/android/net/module/util/FdEventsReader.java", "device/com/android/net/module/util/HexDump.java", + "device/com/android/net/module/util/NetworkMonitorUtils.java", "device/com/android/net/module/util/PacketReader.java", "device/com/android/net/module/util/SharedLog.java", // This library is used by system modules, for which the system health impact of Kotlin @@ -69,6 +70,7 @@ java_library { libs: [ "androidx.annotation_annotation", "framework-annotations-lib", + "framework-connectivity.stubs.module_lib", ], lint: { strict_updatability_linting: true }, } diff --git a/staticlibs/device/com/android/net/module/util/NetworkMonitorUtils.java b/staticlibs/device/com/android/net/module/util/NetworkMonitorUtils.java new file mode 100644 index 0000000000..f6cd044e4e --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/NetworkMonitorUtils.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util; + +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; +import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + +import android.annotation.NonNull; +import android.net.NetworkCapabilities; +import android.os.Build; + +/** @hide */ +public class NetworkMonitorUtils { + // This class is used by both NetworkMonitor and ConnectivityService, so it cannot use + // NetworkStack shims, but at the same time cannot use non-system APIs. + // TRANSPORT_TEST is test API as of R (so it is enforced to always be 7 and can't be changed), + // and it is being added as a system API in S. + // TODO: use NetworkCapabilities.TRANSPORT_TEST once NetworkStack builds against API 31. + private static final int TRANSPORT_TEST = 7; + + // This class is used by both NetworkMonitor and ConnectivityService, so it cannot use + // NetworkStack shims, but at the same time cannot use non-system APIs. + // NET_CAPABILITY_NOT_VCN_MANAGED is system API as of S (so it is enforced to always be 28 and + // can't be changed). + // TODO: use NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED once NetworkStack builds against + // API 31. + public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; + + // Network conditions broadcast constants + public static final String ACTION_NETWORK_CONDITIONS_MEASURED = + "android.net.conn.NETWORK_CONDITIONS_MEASURED"; + public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type"; + public static final String EXTRA_NETWORK_TYPE = "extra_network_type"; + public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received"; + public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal"; + public static final String EXTRA_CELL_ID = "extra_cellid"; + public static final String EXTRA_SSID = "extra_ssid"; + public static final String EXTRA_BSSID = "extra_bssid"; + /** real time since boot */ + public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms"; + public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms"; + public static final String PERMISSION_ACCESS_NETWORK_CONDITIONS = + "android.permission.ACCESS_NETWORK_CONDITIONS"; + + /** + * Return whether validation is required for private DNS in strict mode. + * @param nc Network capabilities of the network to test. + */ + public static boolean isPrivateDnsValidationRequired(@NonNull final NetworkCapabilities nc) { + final boolean isVcnManaged = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) + && !nc.hasCapability(NET_CAPABILITY_NOT_VCN_MANAGED); + final boolean isOemPaid = nc.hasCapability(NET_CAPABILITY_OEM_PAID) + && nc.hasCapability(NET_CAPABILITY_TRUSTED); + final boolean isDefaultCapable = nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) + && nc.hasCapability(NET_CAPABILITY_TRUSTED); + + // TODO: Consider requiring validation for DUN networks. + if (nc.hasCapability(NET_CAPABILITY_INTERNET) + && (isVcnManaged || isOemPaid || isDefaultCapable)) { + return true; + } + + // Test networks that also have one of the major transport types are attempting to replicate + // that transport on a test interface (for example, test ethernet networks with + // EthernetManager#setIncludeTestInterfaces). Run validation on them for realistic tests. + // See also comments on EthernetManager#setIncludeTestInterfaces and on TestNetworkManager. + if (nc.hasTransport(TRANSPORT_TEST) && nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) && ( + nc.hasTransport(TRANSPORT_WIFI) + || nc.hasTransport(TRANSPORT_CELLULAR) + || nc.hasTransport(TRANSPORT_BLUETOOTH) + || nc.hasTransport(TRANSPORT_ETHERNET))) { + return true; + } + + return false; + } + + /** + * Return whether validation is required for a network. + * @param isVpnValidationRequired Whether network validation should be performed for VPN + * networks. + * @param nc Network capabilities of the network to test. + */ + public static boolean isValidationRequired(boolean isVpnValidationRequired, + @NonNull final NetworkCapabilities nc) { + // TODO: Consider requiring validation for DUN networks. + if (!nc.hasCapability(NET_CAPABILITY_NOT_VPN)) { + return isVpnValidationRequired; + } + return isPrivateDnsValidationRequired(nc); + } +} From af0ae6785f1318c319f2ee1e590d5c77fea2fa89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 10 Aug 2022 12:25:56 +0000 Subject: [PATCH 534/777] fix wrong bpf path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (also note the program in p/m/C netd.C is not optional or kernel version dependent) Bug: 237030932 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ia984f6a1ce0ab14a204fe47ec295db1363879b7b --- staticlibs/native/tcutils/tests/tcutils_test.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/staticlibs/native/tcutils/tests/tcutils_test.cpp b/staticlibs/native/tcutils/tests/tcutils_test.cpp index 32736d6b9d..8129286f0a 100644 --- a/staticlibs/native/tcutils/tests/tcutils_test.cpp +++ b/staticlibs/native/tcutils/tests/tcutils_test.cpp @@ -113,12 +113,9 @@ TEST(LibTcUtilsTest, AddAndDeleteBpfFilter) { TEST(LibTcUtilsTest, AddAndDeleteIngressPoliceFilter) { // TODO: this should use bpf_shared.h rather than hardcoding the path static constexpr char bpfProgPath[] = - "/sys/fs/bpf/prog_netd_schedact_ingress_account"; + "/sys/fs/bpf/netd_shared/prog_netd_schedact_ingress_account"; int fd = bpf::retrieveProgram(bpfProgPath); - if (fd == -1) { - // ingress policing is not supported. - return; - } + ASSERT_LE(3, fd); close(fd); const int errNOENT = isAtLeastKernelVersion(4, 19, 0) ? ENOENT : EINVAL; From 0e5b5d856b3137b0dca7995e526fd119f06a5e4a Mon Sep 17 00:00:00 2001 From: Cole Faust Date: Mon, 15 Aug 2022 15:03:05 -0700 Subject: [PATCH 535/777] Fix array-related errorprone warnings The ArrayEquals, ArrayHashCode, ArrayToString, and ArraysAsListPrimitiveArray errorprone findings were demoted from errors to warnings. Fix existing occurrences of them so they can be made errors again. Bug: 242630963 Test: RUN_ERROR_PRONE=true m javac-check Change-Id: I6132205b0e86e3ec73c78d54ce2a8c334b81c5ed --- staticlibs/framework/com/android/net/module/util/IpRange.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/framework/com/android/net/module/util/IpRange.java b/staticlibs/framework/com/android/net/module/util/IpRange.java index 40b57b10f0..0a3f95bee5 100644 --- a/staticlibs/framework/com/android/net/module/util/IpRange.java +++ b/staticlibs/framework/com/android/net/module/util/IpRange.java @@ -200,7 +200,7 @@ public final class IpRange { @Override public int hashCode() { - return Objects.hash(mStartAddr, mEndAddr); + return Objects.hash(Arrays.hashCode(mStartAddr), Arrays.hashCode(mEndAddr)); } @Override From a19f85124e4deff0432565183a53efef81b2ca9c Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 4 Aug 2021 21:56:45 +0900 Subject: [PATCH 536/777] Add Function3 ...and rename ExceptionUtils to FunctionalUtils as the old name would no longer be appropriate. Test: FrameworksNetTests Change-Id: I2affd69fb84d7f250b4a45497eec6c052bf6ec50 --- .../android/testutils/TestPermissionUtil.kt | 4 ++-- .../com/android/testutils/Cleanup.kt | 4 ++-- ...ceptionUtils.java => FunctionalUtils.java} | 19 ++++++++++++++++++- .../com/android/testutils/MiscAsserts.kt | 2 +- 4 files changed, 23 insertions(+), 6 deletions(-) rename staticlibs/testutils/hostdevice/com/android/testutils/{ExceptionUtils.java => FunctionalUtils.java} (74%) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestPermissionUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestPermissionUtil.kt index a4dbd9ada9..f571f64fe7 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestPermissionUtil.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestPermissionUtil.kt @@ -20,8 +20,8 @@ package com.android.testutils import androidx.test.platform.app.InstrumentationRegistry import com.android.modules.utils.build.SdkLevel -import com.android.testutils.ExceptionUtils.ThrowingRunnable -import com.android.testutils.ExceptionUtils.ThrowingSupplier +import com.android.testutils.FunctionalUtils.ThrowingRunnable +import com.android.testutils.FunctionalUtils.ThrowingSupplier /** * Run the specified [task] with the specified [permissions] obtained through shell diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt index 3db357b565..9f282347f5 100644 --- a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt +++ b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt @@ -18,8 +18,8 @@ package com.android.testutils -import com.android.testutils.ExceptionUtils.ThrowingRunnable -import com.android.testutils.ExceptionUtils.ThrowingSupplier +import com.android.testutils.FunctionalUtils.ThrowingRunnable +import com.android.testutils.FunctionalUtils.ThrowingSupplier import javax.annotation.CheckReturnValue /** diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/ExceptionUtils.java b/staticlibs/testutils/hostdevice/com/android/testutils/FunctionalUtils.java similarity index 74% rename from staticlibs/testutils/hostdevice/com/android/testutils/ExceptionUtils.java rename to staticlibs/testutils/hostdevice/com/android/testutils/FunctionalUtils.java index d3bda98cb0..da36e4de2b 100644 --- a/staticlibs/testutils/hostdevice/com/android/testutils/ExceptionUtils.java +++ b/staticlibs/testutils/hostdevice/com/android/testutils/FunctionalUtils.java @@ -21,7 +21,7 @@ import java.util.function.Supplier; /** * A class grouping some utilities to deal with exceptions. */ -public class ExceptionUtils { +public class FunctionalUtils { /** * Like a Consumer, but declared to throw an exception. * @param @@ -79,4 +79,21 @@ public class ExceptionUtils { } }; } + + // Java has Function and BiFunction but nothing for higher-arity functions. + // Function3 is what Kotlin and Scala use (they also have higher-arity variants, with + // FunctionN taking N arguments, as the JVM does not have variadic formal parameters) + /** + * A function with three arguments. + * @param Type of the first argument + * @param Type of the second argument + * @param Type of the third argument + * @param Type of the return value + */ + public interface Function3 { + /** + * Apply the function to the arguments + */ + TResult apply(TArg1 a1, TArg2 a2, TArg3 a3); + } } diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt b/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt index efd9402d8f..1883387c62 100644 --- a/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt +++ b/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt @@ -18,7 +18,7 @@ package com.android.testutils -import com.android.testutils.ExceptionUtils.ThrowingRunnable +import com.android.testutils.FunctionalUtils.ThrowingRunnable import java.lang.reflect.Modifier import kotlin.system.measureTimeMillis import kotlin.test.assertEquals From cc5f01c610d5476f48ea600408f6c9809343c5bd Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 16 Aug 2022 17:31:18 +0900 Subject: [PATCH 537/777] Add findFirst and findLast to CollectionsUtils Test: new tests in this patch Change-Id: Ie13ee7f50832ffec1febe4f4596d0b26e4c4a2f6 --- .../net/module/util/CollectionUtils.java | 35 +++++++++++++++++++ .../net/module/util/CollectionUtilsTest.kt | 25 +++++++++++++ 2 files changed, 60 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index a16ef337cd..73f6cd8d79 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -22,6 +22,7 @@ import android.util.SparseArray; import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.Objects; import java.util.function.Predicate; @@ -219,4 +220,38 @@ public final class CollectionUtils { return haystack.containsAll(needles); } + /** + * Returns the first item of a collection that matches the predicate. + * @param haystack The collection to search. + * @param condition The predicate to match. + * @param The type of element in the collection. + * @return The first element matching the predicate, or null if none. + */ + @Nullable + public static T findFirst(Collection haystack, Predicate condition) { + for (T needle : haystack) { + if (condition.test(needle)) return needle; + } + return null; + } + + /** + * Returns the last item of a List that matches the predicate. + * @param haystack The List to search. + * @param condition The predicate to match. + * @param The type of element in the list. + * @return The last element matching the predicate, or null if none. + */ + // There is no way to reverse iterate a Collection in Java (e.g. the collection may + // be a single-linked list), so implementing this on Collection is necessarily very + // wasteful (store and reverse a copy, test all elements, or recurse to the end of the + // list to test on the up path and possibly blow the call stack) + @Nullable + public static T findLast(List haystack, Predicate condition) { + for (int i = haystack.size() - 1; i >= 0; --i) { + final T needle = haystack.get(i); + if (condition.test(needle)) return needle; + } + return null; + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt index 911483a821..2de92f4d06 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt @@ -22,6 +22,8 @@ import org.junit.Test import org.junit.runner.RunWith import kotlin.test.assertEquals import kotlin.test.assertFalse +import kotlin.test.assertNull +import kotlin.test.assertSame import kotlin.test.assertTrue @RunWith(AndroidJUnit4::class) @@ -86,4 +88,27 @@ class CollectionUtilsTest { assertEquals(3, CollectionUtils.total(longArrayOf(1, 1, 1))) assertEquals(0, CollectionUtils.total(null)) } + + @Test + fun testFindFirstFindLast() { + val listAE = listOf("A", "B", "C", "D", "E") + assertSame(CollectionUtils.findFirst(listAE) { it == "A" }, listAE[0]) + assertSame(CollectionUtils.findFirst(listAE) { it == "B" }, listAE[1]) + assertSame(CollectionUtils.findFirst(listAE) { it == "E" }, listAE[4]) + assertNull(CollectionUtils.findFirst(listAE) { it == "F" }) + assertSame(CollectionUtils.findLast(listAE) { it == "A" }, listAE[0]) + assertSame(CollectionUtils.findLast(listAE) { it == "B" }, listAE[1]) + assertSame(CollectionUtils.findLast(listAE) { it == "E" }, listAE[4]) + assertNull(CollectionUtils.findLast(listAE) { it == "F" }) + + val listMulti = listOf("A", "B", "A", "C", "D", "E", "A", "E") + assertSame(CollectionUtils.findFirst(listMulti) { it == "A" }, listMulti[0]) + assertSame(CollectionUtils.findFirst(listMulti) { it == "B" }, listMulti[1]) + assertSame(CollectionUtils.findFirst(listMulti) { it == "E" }, listMulti[5]) + assertNull(CollectionUtils.findFirst(listMulti) { it == "F" }) + assertSame(CollectionUtils.findLast(listMulti) { it == "A" }, listMulti[6]) + assertSame(CollectionUtils.findLast(listMulti) { it == "B" }, listMulti[1]) + assertSame(CollectionUtils.findLast(listMulti) { it == "E" }, listMulti[7]) + assertNull(CollectionUtils.findLast(listMulti) { it == "F" }) + } } From c0a6d524eb0fc63a110b054f744048f7b526513e Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 5 Jul 2022 11:09:10 +0800 Subject: [PATCH 538/777] Add getter to PerUidCounter This is needed by ConnectivityServiceTest, refer to the counter part CL in the module git. This CL also fix guarded by annotation and remove the increment/decrement method with count methods, which is not very useful. Test: TH Bug: 235771502 Change-Id: Iaab681bf456e14afb4c6ddf700eb3308abead35f --- .../net/module/util/PerUidCounter.java | 29 +++---- .../net/module/util/PerUidCounterTest.kt | 77 +++++++++++++------ 2 files changed, 65 insertions(+), 41 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/PerUidCounter.java b/staticlibs/framework/com/android/net/module/util/PerUidCounter.java index 0b2de7a2a1..463b0c4203 100644 --- a/staticlibs/framework/com/android/net/module/util/PerUidCounter.java +++ b/staticlibs/framework/com/android/net/module/util/PerUidCounter.java @@ -32,7 +32,7 @@ public class PerUidCounter { // Map from UID to count that UID has filed. @VisibleForTesting - @GuardedBy("mUidToCount") + @GuardedBy("this") final SparseIntArray mUidToCount = new SparseIntArray(); /** @@ -57,15 +57,8 @@ public class PerUidCounter { * * @param uid the uid that the counter was made under */ - public void incrementCountOrThrow(final int uid) { - incrementCountOrThrow(uid, 1 /* numToIncrement */); - } - - public synchronized void incrementCountOrThrow(final int uid, final int numToIncrement) { - if (numToIncrement <= 0) { - throw new IllegalArgumentException("Increment count must be positive"); - } - final long newCount = ((long) mUidToCount.get(uid, 0)) + numToIncrement; + public synchronized void incrementCountOrThrow(final int uid) { + final long newCount = ((long) mUidToCount.get(uid, 0)) + 1; if (newCount > mMaxCountPerUid) { throw new IllegalStateException("Uid " + uid + " exceeded its allowed limit"); } @@ -83,15 +76,8 @@ public class PerUidCounter { * * @param uid the uid that the count was made under */ - public void decrementCountOrThrow(final int uid) { - decrementCountOrThrow(uid, 1 /* numToDecrement */); - } - - public synchronized void decrementCountOrThrow(final int uid, final int numToDecrement) { - if (numToDecrement <= 0) { - throw new IllegalArgumentException("Decrement count must be positive"); - } - final int newCount = mUidToCount.get(uid, 0) - numToDecrement; + public synchronized void decrementCountOrThrow(final int uid) { + final int newCount = mUidToCount.get(uid, 0) - 1; if (newCount < 0) { throw new IllegalStateException("BUG: too small count " + newCount + " for UID " + uid); } else if (newCount == 0) { @@ -100,4 +86,9 @@ public class PerUidCounter { mUidToCount.put(uid, newCount); } } + + @VisibleForTesting + public synchronized int get(int uid) { + return mUidToCount.get(uid, 0); + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt index 0f2d52acac..321fe59486 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PerUidCounterTest.kt @@ -20,6 +20,7 @@ import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import org.junit.Test import org.junit.runner.RunWith +import kotlin.test.assertEquals import kotlin.test.assertFailsWith @RunWith(AndroidJUnit4::class) @@ -27,6 +28,7 @@ import kotlin.test.assertFailsWith class PerUidCounterTest { private val UID_A = 1000 private val UID_B = 1001 + private val UID_C = 1002 @Test fun testCounterMaximum() { @@ -37,31 +39,35 @@ class PerUidCounterTest { PerUidCounter(0) } - val largeMaxCounter = PerUidCounter(Integer.MAX_VALUE) - largeMaxCounter.incrementCountOrThrow(UID_A, Integer.MAX_VALUE) - assertFailsWith { - largeMaxCounter.incrementCountOrThrow(UID_A) + val testLimit = 1000 + val testCounter = PerUidCounter(testLimit) + assertEquals(0, testCounter[UID_A]) + repeat(testLimit) { + testCounter.incrementCountOrThrow(UID_A) } + assertEquals(testLimit, testCounter[UID_A]) + assertFailsWith { + testCounter.incrementCountOrThrow(UID_A) + } + assertEquals(testLimit, testCounter[UID_A]) } @Test fun testIncrementCountOrThrow() { val counter = PerUidCounter(3) - // Verify the increment count cannot be zero. - assertFailsWith { - counter.incrementCountOrThrow(UID_A, 0) - } - // Verify the counters work independently. counter.incrementCountOrThrow(UID_A) - counter.incrementCountOrThrow(UID_B, 2) + counter.incrementCountOrThrow(UID_B) counter.incrementCountOrThrow(UID_B) counter.incrementCountOrThrow(UID_A) counter.incrementCountOrThrow(UID_A) + assertEquals(3, counter[UID_A]) + assertEquals(2, counter[UID_B]) assertFailsWith { counter.incrementCountOrThrow(UID_A) } + counter.incrementCountOrThrow(UID_B) assertFailsWith { counter.incrementCountOrThrow(UID_B) } @@ -71,39 +77,66 @@ class PerUidCounterTest { counter.incrementCountOrThrow(UID_A) } assertFailsWith { - counter.incrementCountOrThrow(UID_A, 3) + repeat(3) { + counter.incrementCountOrThrow(UID_A) + } } + assertEquals(3, counter[UID_A]) + assertEquals(3, counter[UID_B]) + assertEquals(0, counter[UID_C]) } @Test fun testDecrementCountOrThrow() { val counter = PerUidCounter(3) - // Verify the decrement count cannot be zero. - assertFailsWith { - counter.decrementCountOrThrow(UID_A, 0) - } - // Verify the count cannot go below zero. assertFailsWith { counter.decrementCountOrThrow(UID_A) } assertFailsWith { - counter.decrementCountOrThrow(UID_A, 5) - } - assertFailsWith { - counter.decrementCountOrThrow(UID_A, Integer.MAX_VALUE) + repeat(5) { + counter.decrementCountOrThrow(UID_A) + } } // Verify the counters work independently. counter.incrementCountOrThrow(UID_A) counter.incrementCountOrThrow(UID_B) + assertEquals(1, counter[UID_A]) + assertEquals(1, counter[UID_B]) assertFailsWith { - counter.decrementCountOrThrow(UID_A, 3) + repeat(3) { + counter.decrementCountOrThrow(UID_A) + } } - counter.decrementCountOrThrow(UID_A) assertFailsWith { counter.decrementCountOrThrow(UID_A) } + assertEquals(0, counter[UID_A]) + assertEquals(1, counter[UID_B]) + + // Verify mixing increment and decrement. + val largeCounter = PerUidCounter(100) + repeat(90) { + largeCounter.incrementCountOrThrow(UID_A) + } + repeat(70) { + largeCounter.decrementCountOrThrow(UID_A) + } + repeat(80) { + largeCounter.incrementCountOrThrow(UID_A) + } + assertFailsWith { + largeCounter.incrementCountOrThrow(UID_A) + } + assertEquals(100, largeCounter[UID_A]) + repeat(100) { + largeCounter.decrementCountOrThrow(UID_A) + } + assertFailsWith { + largeCounter.decrementCountOrThrow(UID_A) + } + assertEquals(0, largeCounter[UID_A]) } } \ No newline at end of file From 8a8bd3734f313df2a5c955bb2fd7a2014c397930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 17 Aug 2022 15:20:38 +0000 Subject: [PATCH 539/777] create Struct.S32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I7bddfec540ba0f7c9b842d4c5ec0c9402eedc72a --- .../device/com/android/net/module/util/Struct.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/Struct.java b/staticlibs/device/com/android/net/module/util/Struct.java index d717bc708a..b638a4615d 100644 --- a/staticlibs/device/com/android/net/module/util/Struct.java +++ b/staticlibs/device/com/android/net/module/util/Struct.java @@ -742,6 +742,17 @@ public class Struct { } } + /** A simple Struct which only contains an s32 field. */ + public static class S32 extends Struct { + @Struct.Field(order = 0, type = Struct.Type.S32) + public final int val; + + public S32(final int val) { + this.val = val; + } + } + + /** A simple Struct which only contains a u32 field. */ public static class U32 extends Struct { @Struct.Field(order = 0, type = Struct.Type.U32) public final long val; @@ -751,6 +762,7 @@ public class Struct { } } + /** A simple Struct which only contains an s64 field. */ public static class S64 extends Struct { @Struct.Field(order = 0, type = Struct.Type.S64) public final long val; From 4dcf00e78cf3a43cdf3d0e2557a958b0f262bded Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Tue, 9 Aug 2022 08:43:47 +0000 Subject: [PATCH 540/777] Add fromBase64EncodedString to BpfDump EthernetTetheringTest has parseMapKeyValue that decodes the string encoded by BpfDump#toBase64EncodedString Upcoming CL also wants to decode the encoded string. So this CL renames parseMapKeyValue to fromBase64EncodedString and moves to BpfDump with refactoring Bug: 217624062 Test: atest NetworkStaticLibTests Change-Id: I6ec302aaaa3e8779119cf153567cb032828f5daf --- .../com/android/net/module/util/BpfDump.java | 33 ++++++++++++- .../android/net/module/util/BpfDumpTest.java | 49 +++++++++++++++++-- 2 files changed, 76 insertions(+), 6 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/BpfDump.java b/staticlibs/device/com/android/net/module/util/BpfDump.java index fec225c10a..67e9c936ec 100644 --- a/staticlibs/device/com/android/net/module/util/BpfDump.java +++ b/staticlibs/device/com/android/net/module/util/BpfDump.java @@ -16,16 +16,20 @@ package com.android.net.module.util; import android.util.Base64; +import android.util.Pair; import androidx.annotation.NonNull; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + /** * The classes and the methods for BPF dump utilization. */ public class BpfDump { // Using "," as a separator between base64 encoded key and value is safe because base64 // characters are [0-9a-zA-Z/=+]. - public static final String BASE64_DELIMITER = ","; + private static final String BASE64_DELIMITER = ","; /** * Encode BPF key and value into a base64 format string which uses the delimiter ',': @@ -43,6 +47,33 @@ public class BpfDump { return keyBase64Str + BASE64_DELIMITER + valueBase64Str; } + /** + * Decode Struct from a base64 format string + */ + private static T parseStruct( + Class structClass, @NonNull String base64Str) { + final byte[] bytes = Base64.decode(base64Str, Base64.DEFAULT); + final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); + byteBuffer.order(ByteOrder.nativeOrder()); + return Struct.parse(structClass, byteBuffer); + } + + /** + * Decode BPF key and value from a base64 format string which uses the delimiter ',': + * , + */ + public static Pair fromBase64EncodedString( + Class keyClass, Class valueClass, @NonNull String base64Str) { + String[] keyValueStrs = base64Str.split(BASE64_DELIMITER); + if (keyValueStrs.length != 2 /* key + value */) { + throw new IllegalArgumentException("Invalid base64Str (" + base64Str + "), base64Str" + + " must contain exactly one delimiter '" + BASE64_DELIMITER + "'"); + } + final K k = parseStruct(keyClass, keyValueStrs[0]); + final V v = parseStruct(valueClass, keyValueStrs[1]); + return new Pair<>(k, v); + } + // TODO: add a helper to dump bpf map content with the map name, the header line // (ex: "BPF ingress map: iif nat64Prefix v6Addr -> v4Addr oif"), a lambda that // knows how to dump each line, and the PrintWriter. diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java index b166b4a4db..395011cf50 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java @@ -17,6 +17,9 @@ package com.android.net.module.util; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import android.util.Pair; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -27,17 +30,53 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @SmallTest public class BpfDumpTest { + private static final int TEST_KEY = 123; + private static final String TEST_KEY_BASE64 = "ewAAAA=="; + private static final int TEST_VAL = 456; + private static final String TEST_VAL_BASE64 = "yAEAAA=="; + private static final String BASE64_DELIMITER = ","; + private static final String TEST_KEY_VAL_BASE64 = + TEST_KEY_BASE64 + BASE64_DELIMITER + TEST_VAL_BASE64; + private static final String INVALID_BASE64_STRING = "Map is null"; + @Test public void testToBase64EncodedString() { - final Struct.U32 key = new Struct.U32(123); - final Struct.U32 value = new Struct.U32(456); + final Struct.U32 key = new Struct.U32(TEST_KEY); + final Struct.U32 value = new Struct.U32(TEST_VAL); // Verified in python: // import base64 - // print(base64.b64encode(b'\x7b\x00\x00\x00')) # key: ewAAAA== - // print(base64.b64encode(b'\xc8\x01\x00\x00')) # value: yAEAAA== + // print(base64.b64encode(b'\x7b\x00\x00\x00')) # key: ewAAAA== (TEST_KEY_BASE64) + // print(base64.b64encode(b'\xc8\x01\x00\x00')) # value: yAEAAA== (TEST_VAL_BASE64) assertEquals("7B000000", HexDump.toHexString(key.writeToBytes())); assertEquals("C8010000", HexDump.toHexString(value.writeToBytes())); - assertEquals("ewAAAA==,yAEAAA==", BpfDump.toBase64EncodedString(key, value)); + assertEquals(TEST_KEY_VAL_BASE64, BpfDump.toBase64EncodedString(key, value)); + } + + @Test + public void testFromBase64EncodedString() { + Pair decodedKeyValue = BpfDump.fromBase64EncodedString( + Struct.U32.class, Struct.U32.class, TEST_KEY_VAL_BASE64); + assertEquals(TEST_KEY, decodedKeyValue.first.val); + assertEquals(TEST_VAL, decodedKeyValue.second.val); + } + + private void assertThrowsIllegalArgumentException(final String testStr) { + assertThrows(IllegalArgumentException.class, + () -> BpfDump.fromBase64EncodedString(Struct.U32.class, Struct.U32.class, testStr)); + } + + @Test + public void testFromBase64EncodedStringInvalidString() { + assertThrowsIllegalArgumentException(INVALID_BASE64_STRING); + assertThrowsIllegalArgumentException(TEST_KEY_BASE64); + assertThrowsIllegalArgumentException( + TEST_KEY_BASE64 + BASE64_DELIMITER + INVALID_BASE64_STRING); + assertThrowsIllegalArgumentException( + INVALID_BASE64_STRING + BASE64_DELIMITER + TEST_VAL_BASE64); + assertThrowsIllegalArgumentException( + INVALID_BASE64_STRING + BASE64_DELIMITER + INVALID_BASE64_STRING); + assertThrowsIllegalArgumentException( + TEST_KEY_VAL_BASE64 + BASE64_DELIMITER + TEST_KEY_BASE64); } } From 0d8bd9005ddbec351ef5a4bd79fe8cf6fba3b0de Mon Sep 17 00:00:00 2001 From: Cole Faust Date: Mon, 22 Aug 2022 09:17:29 +0900 Subject: [PATCH 541/777] Add CollectionUtils.indexOfSubArray() This is useful as an array version of Collections.indexOfSubList(). Bug: 242630963 Test: atest NetworkStaticLibTests Change-Id: I36724791ceece1348826a51cb2a975e169dfecc6 --- .../net/module/util/CollectionUtils.java | 20 +++++++++++++++++++ .../net/module/util/CollectionUtilsTest.kt | 16 +++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index a16ef337cd..58689fb521 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -164,6 +164,26 @@ public final class CollectionUtils { return -1; } + /** + * Returns the index of the needle array in the haystack array, or -1 if it can't be found. + * This is a byte array equivalent of Collections.indexOfSubList(). + */ + public static int indexOfSubArray(@NonNull byte[] haystack, @NonNull byte[] needle) { + for (int i = 0; i < haystack.length - needle.length + 1; i++) { + boolean found = true; + for (int j = 0; j < needle.length; j++) { + if (haystack[i + j] != needle[j]) { + found = false; + break; + } + } + if (found) { + return i; + } + } + return -1; + } + /** * Returns a new collection of elements that match the passed predicate. * @param source the elements to filter. diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt index 911483a821..c925a0c1af 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt @@ -18,6 +18,7 @@ package com.android.net.module.util import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 +import com.android.testutils.assertThrows import org.junit.Test import org.junit.runner.RunWith import kotlin.test.assertEquals @@ -49,6 +50,21 @@ class CollectionUtilsTest { assertEquals(1, CollectionUtils.indexOf(listOf(null, "CCCC")) { it != null }) } + @Test + fun testIndexOfSubArray() { + val haystack = byteArrayOf(1, 2, 3, 4, 5) + assertEquals(2, CollectionUtils.indexOfSubArray(haystack, byteArrayOf(3, 4))) + assertEquals(3, CollectionUtils.indexOfSubArray(haystack, byteArrayOf(4, 5))) + assertEquals(4, CollectionUtils.indexOfSubArray(haystack, byteArrayOf(5))) + assertEquals(-1, CollectionUtils.indexOfSubArray(haystack, byteArrayOf(3, 2))) + assertEquals(0, CollectionUtils.indexOfSubArray(haystack, byteArrayOf())) + assertEquals(-1, CollectionUtils.indexOfSubArray(byteArrayOf(), byteArrayOf(3, 2))) + assertEquals(0, CollectionUtils.indexOfSubArray(byteArrayOf(), byteArrayOf())) + assertThrows(NullPointerException::class.java) { + CollectionUtils.indexOfSubArray(haystack, null) + } + } + @Test fun testAll() { assertFalse(CollectionUtils.all(listOf("A", "B", "C", "D", "E")) { it != "E" }) From da0e17255164a82c21551d9e807d3e4ea74cdab2 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 16 Aug 2022 13:32:27 +0900 Subject: [PATCH 542/777] Check that cell network is available before tests Instead of only checking that a sim card that supports data connectivity is inserted, also check that there is an available cellular network. This helps ensure that the device is setup with a working data plan and APN configuration. Bug: 242628522 Test: atest CtsNetTestCases Change-Id: Id47d49de77da5d9f7a87ff34b954c61662965c9e --- .../ConnectivityCheckTest.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitychecker/ConnectivityCheckTest.kt b/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitychecker/ConnectivityCheckTest.kt index 43b130b27b..f34ca22f62 100644 --- a/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitychecker/ConnectivityCheckTest.kt +++ b/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitychecker/ConnectivityCheckTest.kt @@ -18,10 +18,17 @@ package com.android.testutils.connectivitychecker import android.content.pm.PackageManager.FEATURE_TELEPHONY import android.content.pm.PackageManager.FEATURE_WIFI +import android.net.ConnectivityManager +import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET +import android.net.NetworkCapabilities.TRANSPORT_CELLULAR +import android.net.NetworkRequest import android.telephony.TelephonyManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import com.android.testutils.ConnectUtil +import com.android.testutils.RecorderCallback +import com.android.testutils.TestableNetworkCallback +import com.android.testutils.tryTest import org.junit.Test import org.junit.runner.RunWith import kotlin.test.assertTrue @@ -61,5 +68,20 @@ class ConnectivityCheckTest { assertTrue(tm.isDataConnectivityPossible, "The device is not setup with a SIM card that supports data connectivity. " + commonError) + val cb = TestableNetworkCallback() + val cm = context.getSystemService(ConnectivityManager::class.java) + ?: fail("Could not get ConnectivityManager") + cm.registerNetworkCallback( + NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET).build(), cb) + tryTest { + cb.eventuallyExpectOrNull() + ?: fail("The device does not have mobile data available. Check that it is " + + "setup with a SIM card that has a working data plan, and that the " + + "APN configuration is valid.") + } cleanup { + cm.unregisterNetworkCallback(cb) + } } } \ No newline at end of file From fbc3280c7974fee9b2b6f63f57d084a27d784ff6 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Fri, 8 Jul 2022 07:55:40 +0000 Subject: [PATCH 543/777] Add test for StructInetDiagSockId Upcoming CL will modify StructInetDiagSockId. So, as a preparation, this CL adds test for existing behavior of StructInetDiagSockId. Bug: 217624062 Test: atest NetworkStaticLibTests Change-Id: I6ef475bec050ba2689a8df6182be36a6fccd9bfb --- .../netlink/StructInetDiagSockIdTest.java | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructInetDiagSockIdTest.java diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructInetDiagSockIdTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructInetDiagSockIdTest.java new file mode 100644 index 0000000000..fb929fc860 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructInetDiagSockIdTest.java @@ -0,0 +1,130 @@ +/* + * 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 com.android.net.module.util.netlink; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import android.net.InetAddresses; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class StructInetDiagSockIdTest { + private static final Inet4Address IPV4_SRC_ADDR = + (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.1"); + private static final Inet4Address IPV4_DST_ADDR = + (Inet4Address) InetAddresses.parseNumericAddress("198.51.100.1"); + private static final Inet6Address IPV6_SRC_ADDR = + (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::1"); + private static final Inet6Address IPV6_DST_ADDR = + (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::2"); + private static final int SRC_PORT = 65297; + private static final int DST_PORT = 443; + + private static final byte[] INET_DIAG_SOCKET_ID_IPV4 = + new byte[] { + // src port, dst port + (byte) 0xff, (byte) 0x11, (byte) 0x01, (byte) 0xbb, + // src address + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + // dst address + (byte) 0xc6, (byte) 0x33, (byte) 0x64, (byte) 0x01, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + // if index + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + // cookie + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff + }; + + private static final byte[] INET_DIAG_SOCKET_ID_IPV6 = + new byte[] { + // src port, dst port + (byte) 0xff, (byte) 0x11, (byte) 0x01, (byte) 0xbb, + // src address + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, + // dst address + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, + // if index + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + // cookie + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff + }; + + @Test + public void testPackStructInetDiagSockIdWithIpv4() { + final InetSocketAddress srcAddr = new InetSocketAddress(IPV4_SRC_ADDR, SRC_PORT); + final InetSocketAddress dstAddr = new InetSocketAddress(IPV4_DST_ADDR, DST_PORT); + final StructInetDiagSockId sockId = new StructInetDiagSockId(srcAddr, dstAddr); + final ByteBuffer buffer = ByteBuffer.allocate(StructInetDiagSockId.STRUCT_SIZE); + sockId.pack(buffer); + assertArrayEquals(INET_DIAG_SOCKET_ID_IPV4, buffer.array()); + } + + @Test + public void testPackStructInetDiagSockIdWithIpv6() { + final InetSocketAddress srcAddr = new InetSocketAddress(IPV6_SRC_ADDR, SRC_PORT); + final InetSocketAddress dstAddr = new InetSocketAddress(IPV6_DST_ADDR, DST_PORT); + final StructInetDiagSockId sockId = new StructInetDiagSockId(srcAddr, dstAddr); + final ByteBuffer buffer = ByteBuffer.allocate(StructInetDiagSockId.STRUCT_SIZE); + sockId.pack(buffer); + assertArrayEquals(INET_DIAG_SOCKET_ID_IPV6, buffer.array()); + } + + @Test + public void testToStringStructInetDiagSockIdWithIpv4() { + final InetSocketAddress srcAddr = new InetSocketAddress(IPV4_SRC_ADDR, SRC_PORT); + final InetSocketAddress dstAddr = new InetSocketAddress(IPV4_DST_ADDR, DST_PORT); + final StructInetDiagSockId sockId = new StructInetDiagSockId(srcAddr, dstAddr); + assertEquals("StructInetDiagSockId{ idiag_sport{65297}, idiag_dport{443}," + + " idiag_src{192.0.2.1}, idiag_dst{198.51.100.1}, idiag_if{0}" + + " idiag_cookie{INET_DIAG_NOCOOKIE}}", sockId.toString()); + } + + @Test + public void testToStringStructInetDiagSockIdWithIpv6() { + final InetSocketAddress srcAddr = new InetSocketAddress(IPV6_SRC_ADDR, SRC_PORT); + final InetSocketAddress dstAddr = new InetSocketAddress(IPV6_DST_ADDR, DST_PORT); + final StructInetDiagSockId sockId = new StructInetDiagSockId(srcAddr, dstAddr); + assertEquals("StructInetDiagSockId{ idiag_sport{65297}, idiag_dport{443}," + + " idiag_src{2001:db8::1}, idiag_dst{2001:db8::2}, idiag_if{0}" + + " idiag_cookie{INET_DIAG_NOCOOKIE}}", sockId.toString()); + } +} From 556667ef02453a83df6f6bd7d9df8e7b19a22303 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Tue, 16 Aug 2022 03:45:17 +0000 Subject: [PATCH 544/777] Support StructInetDiagSockId parse Bug: 217624062 Test: atest NetworkStaticLibTests Change-Id: If42436459874d4c61037a98db18c43b40eb81066 --- .../util/netlink/StructInetDiagSockId.java | 115 ++++++++++++++---- .../netlink/StructInetDiagSockIdTest.java | 99 ++++++++++++++- 2 files changed, 191 insertions(+), 23 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java index 95d60e5319..95723cbffd 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java @@ -16,10 +16,22 @@ package com.android.net.module.util.netlink; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + +import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_LEN; +import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN; + import static java.nio.ByteOrder.BIG_ENDIAN; +import android.util.Log; + +import androidx.annotation.Nullable; + import java.net.Inet4Address; +import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -41,19 +53,79 @@ import java.nio.ByteOrder; * @hide */ public class StructInetDiagSockId { + private static final String TAG = StructInetDiagSockId.class.getSimpleName(); public static final int STRUCT_SIZE = 48; - private static final byte[] INET_DIAG_NOCOOKIE = new byte[]{ - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}; + private static final long INET_DIAG_NOCOOKIE = ~0L; private static final byte[] IPV4_PADDING = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - private final InetSocketAddress mLocSocketAddress; - private final InetSocketAddress mRemSocketAddress; + public final InetSocketAddress locSocketAddress; + public final InetSocketAddress remSocketAddress; + public final int ifIndex; + public final long cookie; public StructInetDiagSockId(InetSocketAddress loc, InetSocketAddress rem) { - mLocSocketAddress = loc; - mRemSocketAddress = rem; + this(loc, rem, 0 /* ifIndex */, INET_DIAG_NOCOOKIE); + } + + public StructInetDiagSockId(InetSocketAddress loc, InetSocketAddress rem, + int ifIndex, long cookie) { + this.locSocketAddress = loc; + this.remSocketAddress = rem; + this.ifIndex = ifIndex; + this.cookie = cookie; + } + + /** + * Parse inet diag socket id from buffer. + */ + @Nullable + public static StructInetDiagSockId parse(final ByteBuffer byteBuffer, final byte family) { + if (byteBuffer.remaining() < STRUCT_SIZE) { + return null; + } + + byteBuffer.order(BIG_ENDIAN); + final int srcPort = Short.toUnsignedInt(byteBuffer.getShort()); + final int dstPort = Short.toUnsignedInt(byteBuffer.getShort()); + + final byte[] srcAddrByte; + final byte[] dstAddrByte; + if (family == AF_INET) { + srcAddrByte = new byte[IPV4_ADDR_LEN]; + dstAddrByte = new byte[IPV4_ADDR_LEN]; + byteBuffer.get(srcAddrByte); + // Address always uses IPV6_ADDR_LEN in the buffer. So if the address is IPv4, position + // needs to be advanced to the next field. + byteBuffer.position(byteBuffer.position() + (IPV6_ADDR_LEN - IPV4_ADDR_LEN)); + byteBuffer.get(dstAddrByte); + byteBuffer.position(byteBuffer.position() + (IPV6_ADDR_LEN - IPV4_ADDR_LEN)); + } else if (family == AF_INET6) { + srcAddrByte = new byte[IPV6_ADDR_LEN]; + dstAddrByte = new byte[IPV6_ADDR_LEN]; + byteBuffer.get(srcAddrByte); + byteBuffer.get(dstAddrByte); + } else { + Log.e(TAG, "Invalid address family: " + family); + return null; + } + + final InetSocketAddress srcAddr; + final InetSocketAddress dstAddr; + try { + srcAddr = new InetSocketAddress(InetAddress.getByAddress(srcAddrByte), srcPort); + dstAddr = new InetSocketAddress(InetAddress.getByAddress(dstAddrByte), dstPort); + } catch (UnknownHostException e) { + // Should not happen. UnknownHostException is thrown only if addr byte array is of + // illegal length. + Log.e(TAG, "Failed to parse address: " + e); + return null; + } + + byteBuffer.order(ByteOrder.nativeOrder()); + final int ifIndex = byteBuffer.getInt(); + final long cookie = byteBuffer.getLong(); + return new StructInetDiagSockId(srcAddr, dstAddr, ifIndex, cookie); } /** @@ -61,30 +133,31 @@ public class StructInetDiagSockId { */ public void pack(ByteBuffer byteBuffer) { byteBuffer.order(BIG_ENDIAN); - byteBuffer.putShort((short) mLocSocketAddress.getPort()); - byteBuffer.putShort((short) mRemSocketAddress.getPort()); - byteBuffer.put(mLocSocketAddress.getAddress().getAddress()); - if (mLocSocketAddress.getAddress() instanceof Inet4Address) { + byteBuffer.putShort((short) locSocketAddress.getPort()); + byteBuffer.putShort((short) remSocketAddress.getPort()); + byteBuffer.put(locSocketAddress.getAddress().getAddress()); + if (locSocketAddress.getAddress() instanceof Inet4Address) { byteBuffer.put(IPV4_PADDING); } - byteBuffer.put(mRemSocketAddress.getAddress().getAddress()); - if (mRemSocketAddress.getAddress() instanceof Inet4Address) { + byteBuffer.put(remSocketAddress.getAddress().getAddress()); + if (remSocketAddress.getAddress() instanceof Inet4Address) { byteBuffer.put(IPV4_PADDING); } byteBuffer.order(ByteOrder.nativeOrder()); - byteBuffer.putInt(0); - byteBuffer.put(INET_DIAG_NOCOOKIE); + byteBuffer.putInt(ifIndex); + byteBuffer.putLong(cookie); } @Override public String toString() { return "StructInetDiagSockId{ " - + "idiag_sport{" + mLocSocketAddress.getPort() + "}, " - + "idiag_dport{" + mRemSocketAddress.getPort() + "}, " - + "idiag_src{" + mLocSocketAddress.getAddress().getHostAddress() + "}, " - + "idiag_dst{" + mRemSocketAddress.getAddress().getHostAddress() + "}, " - + "idiag_if{" + 0 + "} " - + "idiag_cookie{INET_DIAG_NOCOOKIE}" + + "idiag_sport{" + locSocketAddress.getPort() + "}, " + + "idiag_dport{" + remSocketAddress.getPort() + "}, " + + "idiag_src{" + locSocketAddress.getAddress().getHostAddress() + "}, " + + "idiag_dst{" + remSocketAddress.getAddress().getHostAddress() + "}, " + + "idiag_if{" + ifIndex + "}, " + + "idiag_cookie{" + + (cookie == INET_DIAG_NOCOOKIE ? "INET_DIAG_NOCOOKIE" : cookie) + "}" + "}"; } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructInetDiagSockIdTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructInetDiagSockIdTest.java index fb929fc860..ce190f2c97 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructInetDiagSockIdTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructInetDiagSockIdTest.java @@ -16,6 +16,9 @@ package com.android.net.module.util.netlink; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -45,6 +48,8 @@ public class StructInetDiagSockIdTest { (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::2"); private static final int SRC_PORT = 65297; private static final int DST_PORT = 443; + private static final int IF_INDEX = 7; + private static final long COOKIE = 561; private static final byte[] INET_DIAG_SOCKET_ID_IPV4 = new byte[] { @@ -67,6 +72,27 @@ public class StructInetDiagSockIdTest { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; + private static final byte[] INET_DIAG_SOCKET_ID_IPV4_IF_COOKIE = + new byte[] { + // src port, dst port + (byte) 0xff, (byte) 0x11, (byte) 0x01, (byte) 0xbb, + // src address + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + // dst address + (byte) 0xc6, (byte) 0x33, (byte) 0x64, (byte) 0x01, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + // if index + (byte) 0x07, (byte) 0x00, (byte) 0x00, (byte) 0x00, + // cookie + (byte) 0x31, (byte) 0x02, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + }; + private static final byte[] INET_DIAG_SOCKET_ID_IPV6 = new byte[] { // src port, dst port @@ -88,6 +114,27 @@ public class StructInetDiagSockIdTest { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; + private static final byte[] INET_DIAG_SOCKET_ID_IPV6_IF_COOKIE = + new byte[] { + // src port, dst port + (byte) 0xff, (byte) 0x11, (byte) 0x01, (byte) 0xbb, + // src address + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, + // dst address + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, + // if index + (byte) 0x07, (byte) 0x00, (byte) 0x00, (byte) 0x00, + // cookie + (byte) 0x31, (byte) 0x02, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + }; + @Test public void testPackStructInetDiagSockIdWithIpv4() { final InetSocketAddress srcAddr = new InetSocketAddress(IPV4_SRC_ADDR, SRC_PORT); @@ -108,13 +155,61 @@ public class StructInetDiagSockIdTest { assertArrayEquals(INET_DIAG_SOCKET_ID_IPV6, buffer.array()); } + @Test + public void testPackStructInetDiagSockIdWithIpv4IfIndexCookie() { + final InetSocketAddress srcAddr = new InetSocketAddress(IPV4_SRC_ADDR, SRC_PORT); + final InetSocketAddress dstAddr = new InetSocketAddress(IPV4_DST_ADDR, DST_PORT); + final StructInetDiagSockId sockId = + new StructInetDiagSockId(srcAddr, dstAddr, IF_INDEX, COOKIE); + final ByteBuffer buffer = ByteBuffer.allocate(StructInetDiagSockId.STRUCT_SIZE); + sockId.pack(buffer); + assertArrayEquals(INET_DIAG_SOCKET_ID_IPV4_IF_COOKIE, buffer.array()); + } + + @Test + public void testPackStructInetDiagSockIdWithIpv6IfIndexCookie() { + final InetSocketAddress srcAddr = new InetSocketAddress(IPV6_SRC_ADDR, SRC_PORT); + final InetSocketAddress dstAddr = new InetSocketAddress(IPV6_DST_ADDR, DST_PORT); + final StructInetDiagSockId sockId = + new StructInetDiagSockId(srcAddr, dstAddr, IF_INDEX, COOKIE); + final ByteBuffer buffer = ByteBuffer.allocate(StructInetDiagSockId.STRUCT_SIZE); + sockId.pack(buffer); + assertArrayEquals(INET_DIAG_SOCKET_ID_IPV6_IF_COOKIE, buffer.array()); + } + + @Test + public void testParseStructInetDiagSockIdWithIpv4() { + final ByteBuffer buffer = ByteBuffer.wrap(INET_DIAG_SOCKET_ID_IPV4_IF_COOKIE); + final StructInetDiagSockId sockId = StructInetDiagSockId.parse(buffer, (byte) AF_INET); + + assertEquals(SRC_PORT, sockId.locSocketAddress.getPort()); + assertEquals(IPV4_SRC_ADDR, sockId.locSocketAddress.getAddress()); + assertEquals(DST_PORT, sockId.remSocketAddress.getPort()); + assertEquals(IPV4_DST_ADDR, sockId.remSocketAddress.getAddress()); + assertEquals(IF_INDEX, sockId.ifIndex); + assertEquals(COOKIE, sockId.cookie); + } + + @Test + public void testParseStructInetDiagSockIdWithIpv6() { + final ByteBuffer buffer = ByteBuffer.wrap(INET_DIAG_SOCKET_ID_IPV6_IF_COOKIE); + final StructInetDiagSockId sockId = StructInetDiagSockId.parse(buffer, (byte) AF_INET6); + + assertEquals(SRC_PORT, sockId.locSocketAddress.getPort()); + assertEquals(IPV6_SRC_ADDR, sockId.locSocketAddress.getAddress()); + assertEquals(DST_PORT, sockId.remSocketAddress.getPort()); + assertEquals(IPV6_DST_ADDR, sockId.remSocketAddress.getAddress()); + assertEquals(IF_INDEX, sockId.ifIndex); + assertEquals(COOKIE, sockId.cookie); + } + @Test public void testToStringStructInetDiagSockIdWithIpv4() { final InetSocketAddress srcAddr = new InetSocketAddress(IPV4_SRC_ADDR, SRC_PORT); final InetSocketAddress dstAddr = new InetSocketAddress(IPV4_DST_ADDR, DST_PORT); final StructInetDiagSockId sockId = new StructInetDiagSockId(srcAddr, dstAddr); assertEquals("StructInetDiagSockId{ idiag_sport{65297}, idiag_dport{443}," - + " idiag_src{192.0.2.1}, idiag_dst{198.51.100.1}, idiag_if{0}" + + " idiag_src{192.0.2.1}, idiag_dst{198.51.100.1}, idiag_if{0}," + " idiag_cookie{INET_DIAG_NOCOOKIE}}", sockId.toString()); } @@ -124,7 +219,7 @@ public class StructInetDiagSockIdTest { final InetSocketAddress dstAddr = new InetSocketAddress(IPV6_DST_ADDR, DST_PORT); final StructInetDiagSockId sockId = new StructInetDiagSockId(srcAddr, dstAddr); assertEquals("StructInetDiagSockId{ idiag_sport{65297}, idiag_dport{443}," - + " idiag_src{2001:db8::1}, idiag_dst{2001:db8::2}, idiag_if{0}" + + " idiag_src{2001:db8::1}, idiag_dst{2001:db8::2}, idiag_if{0}," + " idiag_cookie{INET_DIAG_NOCOOKIE}}", sockId.toString()); } } From fbe576b383c9ae09fcbc3ef9294a6315045cf3e4 Mon Sep 17 00:00:00 2001 From: William Escande Date: Mon, 22 Aug 2022 11:28:00 -0700 Subject: [PATCH 545/777] RESTRICT AUTOMERGE - [Bluetooth apex] Use new apex name The Bluetooth apex name is now called com.android.btservices Bug: 243054261 Test: Build Change-Id: I38caf03e134d9623ee73fa5b7f742d5ebbafeaa1 --- staticlibs/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index c04d1d464b..4dfc752bb5 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -284,7 +284,7 @@ java_library { // TODO: remove "apex_available:platform". apex_available: [ "//apex_available:platform", - "com.android.bluetooth", + "com.android.btservices", "com.android.tethering", "com.android.wifi", ], From 3d835e9a8e85b98a4958282ee36efefaf9364a02 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Wed, 24 Aug 2022 12:38:02 +0900 Subject: [PATCH 546/777] TestBpfMap implements IBpfMap instead of extends BpfMap Bug: 217624062 Test: m, atest BpfCoordinatorTest BpfNetMapsTest Change-Id: I41153a569d79031f0841432c6e83bef2170a33e4 --- .../com/android/net/module/util/BpfMap.java | 19 ------------------- .../com/android/net/module/util/IBpfMap.java | 5 +++++ .../com/android/testutils/TestBpfMap.java | 19 +++++++++++-------- 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java index f7019a503b..2267f318df 100644 --- a/staticlibs/device/com/android/net/module/util/BpfMap.java +++ b/staticlibs/device/com/android/net/module/util/BpfMap.java @@ -24,9 +24,6 @@ import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import com.android.net.module.util.Struct; import java.io.IOException; import java.nio.ByteBuffer; @@ -104,22 +101,6 @@ public class BpfMap implements IBpfMap mValueSize = Struct.getSize(value); } - /** - * Constructor for testing only. - * The derived class implements an internal mocked map. It need to implement all functions - * which are related with the native BPF map because the BPF map handler is not initialized. - * See BpfCoordinatorTest#TestBpfMap. - * TODO: remove once TestBpfMap derive from IBpfMap. - */ - @VisibleForTesting - protected BpfMap(final Class key, final Class value) { - mMapFd = null; // unused - mKeyClass = key; - mValueClass = value; - mKeySize = Struct.getSize(key); - mValueSize = Struct.getSize(value); - } - /** * Update an existing or create a new key -> value entry in an eBbpf map. * (use insertOrReplaceEntry() if you need to know whether insert or replace happened) diff --git a/staticlibs/device/com/android/net/module/util/IBpfMap.java b/staticlibs/device/com/android/net/module/util/IBpfMap.java index dce369a25c..83ff875c60 100644 --- a/staticlibs/device/com/android/net/module/util/IBpfMap.java +++ b/staticlibs/device/com/android/net/module/util/IBpfMap.java @@ -19,6 +19,7 @@ import android.system.ErrnoException; import androidx.annotation.NonNull; +import java.io.IOException; import java.util.NoSuchElementException; /** @@ -74,4 +75,8 @@ public interface IBpfMap extends AutoCloseab /** Clears the map. */ void clear() throws ErrnoException; + + /** Close for AutoCloseable. */ + @Override + void close() throws IOException; } diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java b/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java index 3883511388..733bd9807b 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestBpfMap.java @@ -20,10 +20,10 @@ import android.system.ErrnoException; import androidx.annotation.NonNull; -import com.android.net.module.util.BpfMap; -import com.android.net.module.util.IBpfMap.ThrowingBiConsumer; +import com.android.net.module.util.IBpfMap; import com.android.net.module.util.Struct; +import java.io.IOException; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; @@ -32,20 +32,19 @@ import java.util.concurrent.ConcurrentHashMap; /** * - * Fake BPF map class for tests that have no no privilege to access real BPF maps. All member - * functions which eventually call JNI to access the real native BPF map are overridden. + * Fake BPF map class for tests that have no privilege to access real BPF maps. TestBpfMap does not + * load JNI and all member functions do not access real BPF maps. * - * Inherits from BpfMap instead of implementing IBpfMap so that any class using a BpfMap can use - * this class in its tests. + * Implements IBpfMap so that any class using IBpfMap can use this class in its tests. * * @param the key type * @param the value type */ -public class TestBpfMap extends BpfMap { +public class TestBpfMap implements IBpfMap { private final ConcurrentHashMap mMap = new ConcurrentHashMap<>(); + // TODO: Remove this constructor public TestBpfMap(final Class key, final Class value) { - super(key, value); } @Override @@ -133,4 +132,8 @@ public class TestBpfMap extends BpfMap // TODO: consider using mocked #getFirstKey and #deleteEntry to implement. mMap.clear(); } + + @Override + public void close() throws IOException { + } } From 3becbd22dcefb8f88f4c38a9919848dfb375e26d Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Wed, 24 Aug 2022 12:38:29 +0900 Subject: [PATCH 547/777] Add BpfDump#dumpMap Bug: 217624062 Test: atest NetworkStaticLibTests Change-Id: I7b0a949e667da4120cc20d8587019bfb0f922584 --- .../com/android/net/module/util/BpfDump.java | 36 +++++++++++++++++ .../android/net/module/util/BpfDumpTest.java | 39 +++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/BpfDump.java b/staticlibs/device/com/android/net/module/util/BpfDump.java index 67e9c936ec..2534d61612 100644 --- a/staticlibs/device/com/android/net/module/util/BpfDump.java +++ b/staticlibs/device/com/android/net/module/util/BpfDump.java @@ -15,13 +15,17 @@ */ package com.android.net.module.util; +import android.system.ErrnoException; +import android.system.Os; import android.util.Base64; import android.util.Pair; import androidx.annotation.NonNull; +import java.io.PrintWriter; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.function.BiFunction; /** * The classes and the methods for BPF dump utilization. @@ -74,6 +78,38 @@ public class BpfDump { return new Pair<>(k, v); } + /** + * Dump the BpfMap name and entries + */ + public static void dumpMap(IBpfMap map, + PrintWriter pw, String mapName, BiFunction entryToString) { + dumpMap(map, pw, mapName, "" /* header */, entryToString); + } + + /** + * Dump the BpfMap name, header, and entries + */ + public static void dumpMap(IBpfMap map, + PrintWriter pw, String mapName, String header, BiFunction entryToString) { + pw.println(mapName + ":"); + if (!header.isEmpty()) { + pw.println(" " + header); + } + try { + map.forEach((key, value) -> { + // Value could be null if there is a concurrent entry deletion. + // http://b/220084230. + if (value != null) { + pw.println(" " + entryToString.apply(key, value)); + } else { + pw.println("Entry is deleted while dumping, iterating from first entry"); + } + }); + } catch (ErrnoException e) { + pw.println("Map dump end with error: " + Os.strerror(e.errno)); + } + } + // TODO: add a helper to dump bpf map content with the map name, the header line // (ex: "BPF ingress map: iif nat64Prefix v6Addr -> v4Addr oif"), a lambda that // knows how to dump each line, and the PrintWriter. diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java index 395011cf50..3932925874 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java @@ -18,15 +18,21 @@ package com.android.net.module.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import android.util.Pair; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.testutils.TestBpfMap; + import org.junit.Test; import org.junit.runner.RunWith; +import java.io.PrintWriter; +import java.io.StringWriter; + @RunWith(AndroidJUnit4.class) @SmallTest public class BpfDumpTest { @@ -79,4 +85,37 @@ public class BpfDumpTest { assertThrowsIllegalArgumentException( TEST_KEY_VAL_BASE64 + BASE64_DELIMITER + TEST_KEY_BASE64); } + + private String getDumpMap(final IBpfMap map) { + final StringWriter sw = new StringWriter(); + BpfDump.dumpMap(map, new PrintWriter(sw), "mapName", "header", + (key, val) -> "key=" + key.val + ", val=" + val.val); + return sw.toString(); + } + + @Test + public void testDumpMap() throws Exception { + final IBpfMap map = + new TestBpfMap<>(Struct.U32.class, Struct.U32.class); + map.updateEntry(new Struct.U32(123), new Struct.U32(456)); + + final String dump = getDumpMap(map); + assertEquals(dump, "mapName:\n" + + " header\n" + + " key=123, val=456\n"); + } + + @Test + public void testDumpMapMultipleEntries() throws Exception { + final IBpfMap map = + new TestBpfMap<>(Struct.U32.class, Struct.U32.class); + map.updateEntry(new Struct.U32(123), new Struct.U32(456)); + map.updateEntry(new Struct.U32(789), new Struct.U32(123)); + + final String dump = getDumpMap(map); + assertTrue(dump.contains("mapName:")); + assertTrue(dump.contains("header")); + assertTrue(dump.contains("key=123, val=456")); + assertTrue(dump.contains("key=789, val=123")); + } } From 8cbe32c50196e52b8b4178e7868542dcdcd6f4cc Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Fri, 26 Aug 2022 20:31:55 -0700 Subject: [PATCH 548/777] Switch from std::result_of to std::invoke_result std::result_of is deprecated in C++17 and removed in C++20. std::invoke_result is added in C++17. Upstream libc++ has started removing the declaration of std::result_of when a new-enough C++ dialect is selected, so switch to the supported type. Bug: http://b/175635923 Test: treehugger Change-Id: Ie2db3e092b4300e20858097ac4e88ebaedc7ae07 --- staticlibs/netd/libnetdutils/Syscalls.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/netd/libnetdutils/Syscalls.cpp b/staticlibs/netd/libnetdutils/Syscalls.cpp index 9f653f70c7..7e1a242635 100644 --- a/staticlibs/netd/libnetdutils/Syscalls.cpp +++ b/staticlibs/netd/libnetdutils/Syscalls.cpp @@ -26,7 +26,7 @@ namespace { // Retry syscall fn as long as it returns -1 with errno == EINTR template -typename std::result_of::type syscallRetry(FnT fn, Params&&... params) { +typename std::invoke_result::type syscallRetry(FnT fn, Params&&... params) { auto rv = fn(std::forward(params)...); while ((rv == -1) && (errno == EINTR)) { rv = fn(std::forward(params)...); From 6f469c8e9d33c0c3461ae52e42c44be986cde6e2 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 18 Aug 2022 19:25:42 +0900 Subject: [PATCH 549/777] Fix a flake due to uncertainties in time measurement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The concurrent interpreter supports a `time` directive that lets testers ensure some instruction has taken at least some amount of time. This is useful when testing that some callback didn't arrive before it was sent, for example. Unfortunately, there is some unavoidable uncertainty in how time is measured. Because the thread that measures time needs a very small amount of time before it starts measuring the time taken by its instruction, it is possible that the time that is intended to be measured actually took X, but because the measuring thread took Ɛ before it started measuring time, the measured time is X - Ɛ, which may fail the test because it didn't take enough time. Because there is no way at all to know how much time passed between the measuring thread being woken up and it measuring start time, it's not possible to fix this as long as the measure for the minimum time is taken after the wait. So instead, take the measure before the wait. It's always technically possible that there is a bug where the code doesn't take enough time, but the test doesn't catch it because the device happened to run slowly as it ran the test (e.g. other stuff running at the same time), and this patch makes it a little worse – there will be more true negatives, but this is the only way to ensure no false positives and it should still catch the "too fast" cases most of the time. Now, each thread has its own "blocked" time. It would be possible to store that time in a local and pass it down to all instructions, but that would require all instructions to take the blocked time as an argument, while only the `time` instruction can have any meaningful use of it. Therefore, store it in a thread local instead of adding an argument to all instructions for all interpreters. Test: atest --iterations 100 'TestableNetworkCallbackTest#testPollForNextCallback' ...although I can't get it to fail locally, so the proof will be in a dying out of the flakes. Also checked that increasing the minimum time on an existing test does fail as expected Bug: 185735163 Change-Id: I0afb651337a8b10a864cc5bc793d65d2ce56ab20 --- .../testutils/ConcurrentInterpreter.kt | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt b/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt index 98464eb002..40575d3f97 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt @@ -2,7 +2,6 @@ package com.android.testutils import android.os.SystemClock import java.util.concurrent.CyclicBarrier -import kotlin.system.measureTimeMillis import kotlin.test.assertEquals import kotlin.test.assertFails import kotlin.test.assertNull @@ -48,6 +47,9 @@ open class ConcurrentInterpreter( ) { private val interpretTable: List> = localInterpretTable + getDefaultInstructions() + // The last time the thread became blocked, with base System.currentTimeMillis(). This should + // be set immediately before any time the thread gets blocked. + internal val lastBlockedTime = ThreadLocal() // Split the line into multiple statements separated by ";" and execute them. Return whatever // the last statement returned. @@ -87,6 +89,7 @@ open class ConcurrentInterpreter( threadInstructions.mapIndexed { threadIndex, instructions -> Thread { val threadLocal = threadTransform(initial) + lastBlockedTime.set(System.currentTimeMillis()) barrier.await() var lineNum = 0 instructions.forEach { @@ -104,6 +107,7 @@ open class ConcurrentInterpreter( callSite.lineNumber + lineNum + lineShift, callSite.className, callSite.methodName, callSite.fileName, e) } + lastBlockedTime.set(System.currentTimeMillis()) barrier.await() } }.also { it.start() } @@ -145,8 +149,25 @@ private fun getDefaultInstructions() = listOf>( Regex("(.*)//.*") to { i, t, r -> i.interpret(r.strArg(1), t) }, // Interpret "XXX time x..y" : run XXX and check it took at least x and not more than y Regex("""(.*)\s*time\s*(\d+)\.\.(\d+)""") to { i, t, r -> - val time = measureTimeMillis { i.interpret(r.strArg(1), t) } - assertTrue(time in r.timeArg(2)..r.timeArg(3), "$time not in ${r.timeArg(2)..r.timeArg(3)}") + val lateStart = System.currentTimeMillis() + i.interpret(r.strArg(1), t) + val end = System.currentTimeMillis() + // There is uncertainty in measuring time. + // It takes some (small) time for the thread to even measure the time at which it + // starts interpreting the instruction. It is therefore possible that thread A sleeps for + // n milliseconds, and B expects to have waited for at least n milliseconds, but because + // B started measuring after 1ms or so, B thinks it didn't wait long enough. + // To avoid this, when the `time` instruction tests the instruction took at least X and + // at most Y, it tests X against a time measured since *before* the thread blocked but + // Y against a time measured as late as possible. This ensures that the timer is + // sufficiently lenient in both directions that there are no flaky measures. + val minTime = end - lateStart + val maxTime = end - i.lastBlockedTime.get()!! + + assertTrue(maxTime >= r.timeArg(2), + "Should have taken at least ${r.timeArg(2)} but took less than $maxTime") + assertTrue(minTime <= r.timeArg(3), + "Should have taken at most ${r.timeArg(3)} but took more than $minTime") }, // Interpret "XXX = YYY" : run XXX and assert its return value is equal to YYY. "null" supported Regex("""(.*)\s*=\s*(null|\d+)""") to { i, t, r -> From 9df957f80320849dd888aa78adf73aab7ac348f5 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 23 Aug 2022 16:56:39 +0900 Subject: [PATCH 550/777] Improve documentation for the concurrent interpreter Test: comment-only change Change-Id: I506872f7ff83b8c99527ff593eecc8fdc6760b53 --- .../testutils/ConcurrentInterpreter.kt | 76 ++++++++++++++----- 1 file changed, 55 insertions(+), 21 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt b/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt index 40575d3f97..cbdc01730f 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt @@ -16,14 +16,18 @@ typealias InterpretMatcher = Pair, T, MatchR val INTERPRET_TIME_UNIT = 40L // ms /** - * A small interpreter for testing parallel code. The interpreter will read a list of lines - * consisting of "|"-separated statements. Each column runs in a different concurrent thread - * and all threads wait for each other in between lines. Each statement is split on ";" then - * matched with regular expressions in the instructionTable constant, which contains the - * code associated with each statement. The interpreter supports an object being passed to - * the interpretTestSpec() method to be passed in each lambda (think about the object under - * test), and an optional transform function to be executed on the object at the start of - * every thread. + * A small interpreter for testing parallel code. + * + * The interpreter will read a list of lines consisting of "|"-separated statements, e.g. : + * sleep 2 ; unblock thread2 | wait thread2 time 2..5 + * sendMessage "x" | obtainMessage = "x" time 0..1 + * + * Each column runs in a different concurrent thread and all threads wait for each other in + * between lines. Each statement is split on ";" then matched with regular expressions in the + * instructionTable constant, which contains the code associated with each statement. The + * interpreter supports an object being passed to the interpretTestSpec() method to be passed + * in each lambda (think about the object under test), and an optional transform function to be + * executed on the object at the start of every thread. * * The time unit is defined in milliseconds by the interpretTimeUnit member, which has a default * value but can be passed to the constructor. Whitespace is ignored. @@ -33,13 +37,8 @@ val INTERPRET_TIME_UNIT = 40L // ms * the regexp match, and the object. See the individual tests for the DSL of that test. * Implementors for new interpreting languages are encouraged to look at the defaultInterpretTable * constant below for an example of how to write an interpreting table. - * Some expressions already exist by default and can be used by all interpreters. They include : - * sleep(x) : sleeps for x time units and returns Unit ; sleep alone means sleep(1) - * EXPR = VALUE : asserts that EXPR equals VALUE. EXPR is interpreted. VALUE can either be the - * string "null" or an int. Returns Unit. - * EXPR time x..y : measures the time taken by EXPR and asserts it took at least x and at most - * y time units. - * EXPR // any text : comments are ignored. + * Some expressions already exist by default and can be used by all interpreters. Refer to + * getDefaultInstructions() below for a list and documentation. */ open class ConcurrentInterpreter( localInterpretTable: List>, @@ -65,11 +64,28 @@ open class ConcurrentInterpreter( return code(this, r, match) } - // Spins as many threads as needed by the test spec and interpret each program concurrently, - // having all threads waiting on a CyclicBarrier after each line. - // |lineShift| says how many lines after the call the spec starts. This is used for error - // reporting. Unfortunately AFAICT there is no way to get the line of an argument rather - // than the line at which the expression starts. + /** + * Spins as many threads as needed by the test spec and interpret each program concurrently. + * + * All threads wait on a CyclicBarrier after each line. + * |lineShift| says how many lines after the call the spec starts. This is used for error + * reporting. Unfortunately AFAICT there is no way to get the line of an argument rather + * than the line at which the expression starts. + * + * This method is mostly meant for implementations that extend the ConcurrentInterpreter + * class to add their own directives and instructions. These may need to operate on some + * data, which can be passed in |initial|. For example, an interpreter specialized in callbacks + * may want to pass the callback there. In some cases, it's necessary that each thread + * performs a transformation *after* it starts on that value before starting ; in this case, + * the transformation can be passed to |threadTransform|. The default is to return |initial| as + * is. Look at some existing child classes of this interpreter for some examples of how this + * can be used. + * + * @param spec The test spec, as a string of lines separated by pipes. + * @param initial An initial value passed to all threads. + * @param lineShift How many lines after the call the spec starts, for error reporting. + * @param threadTransform an optional transformation that each thread will apply to |initial| + */ fun interpretTestSpec( spec: String, initial: T, @@ -79,11 +95,19 @@ open class ConcurrentInterpreter( // For nice stack traces val callSite = getCallingMethod() val lines = spec.trim().trim('\n').split("\n").map { it.split("|") } - // |threads| contains arrays of strings that make up the statements of a thread : in other + // |lines| contains arrays of strings that make up the statements of a thread : in other // words, it's an array that contains a list of statements for each column in the spec. + // E.g. if the string is """ + // a | b | c + // d | e | f + // """, then lines is [ [ "a", "b", "c" ], [ "d", "e", "f" ] ]. val threadCount = lines[0].size assertTrue(lines.all { it.size == threadCount }) val threadInstructions = (0 until threadCount).map { i -> lines.map { it[i].trim() } } + // |threadInstructions| is a list where each element is the list of instructions for the + // thread at the index. In other words, it's just |lines| transposed. In the example + // above, it would be [ [ "a", "d" ], [ "b", "e" ], [ "c", "f" ] ] + // mapIndexed below will pass in |instructions| the list of instructions for this thread. val barrier = CyclicBarrier(threadCount) var crash: InterpretException? = null threadInstructions.mapIndexed { threadIndex, instructions -> @@ -142,6 +166,16 @@ open class ConcurrentInterpreter( } } +/** + * Default instructions available to all interpreters. + * sleep(x) : sleeps for x time units and returns Unit ; sleep alone means sleep(1) + * EXPR = VALUE : asserts that EXPR equals VALUE. EXPR is interpreted. VALUE can either be the + * string "null" or an int. Returns Unit. + * EXPR time x..y : measures the time taken by EXPR and asserts it took at least x and at most + * y time units. + * EXPR // any text : comments are ignored. + * EXPR fails : checks that EXPR throws some exception. + */ private fun getDefaultInstructions() = listOf>( // Interpret an empty line as doing nothing. Regex("") to { _, _, _ -> null }, From debdc78518b32ac1480791288686f711d3530776 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 31 Aug 2022 13:24:16 +0900 Subject: [PATCH 551/777] Add CollectionUtils.contains with predicate Test: included in this patch Change-Id: Id10c8878a8e7fe59fa2d7858212e4c01d4de1ca4 --- .../net/module/util/CollectionUtils.java | 27 +++++++++++++++---- .../net/module/util/CollectionUtilsTest.kt | 6 +++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index d1728c21d6..7cac90d598 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -99,7 +99,8 @@ public final class CollectionUtils { * @return The index of the first element that matches the predicate, or -1 if none. */ @Nullable - public static int indexOf(@NonNull Collection elem, @NonNull Predicate predicate) { + public static int indexOf(@NonNull final Collection elem, + @NonNull final Predicate predicate) { int idx = 0; for (final T e : elem) { if (predicate.test(e)) return idx; @@ -222,7 +223,8 @@ public final class CollectionUtils { * @param type of elements * @return true if |haystack| contains any of the |needles|, false otherwise */ - public static boolean containsAny(Collection haystack, Collection needles) { + public static boolean containsAny(@NonNull final Collection haystack, + @NonNull final Collection needles) { for (T needle : needles) { if (haystack.contains(needle)) return true; } @@ -236,7 +238,8 @@ public final class CollectionUtils { * @param type of elements * @return true if |haystack| contains all of the |needles|, false otherwise */ - public static boolean containsAll(Collection haystack, Collection needles) { + public static boolean containsAll(@NonNull final Collection haystack, + @NonNull final Collection needles) { return haystack.containsAll(needles); } @@ -248,7 +251,8 @@ public final class CollectionUtils { * @return The first element matching the predicate, or null if none. */ @Nullable - public static T findFirst(Collection haystack, Predicate condition) { + public static T findFirst(@NonNull final Collection haystack, + @NonNull final Predicate condition) { for (T needle : haystack) { if (condition.test(needle)) return needle; } @@ -267,11 +271,24 @@ public final class CollectionUtils { // wasteful (store and reverse a copy, test all elements, or recurse to the end of the // list to test on the up path and possibly blow the call stack) @Nullable - public static T findLast(List haystack, Predicate condition) { + public static T findLast(@NonNull final List haystack, + @NonNull final Predicate condition) { for (int i = haystack.size() - 1; i >= 0; --i) { final T needle = haystack.get(i); if (condition.test(needle)) return needle; } return null; } + + /** + * Returns whether a collection contains an element matching a condition + * @param haystack The collection to search. + * @param condition The predicate to match. + * @param The type of element in the collection. + * @return Whether the collection contains any element matching the condition. + */ + public static boolean contains(@NonNull final Collection haystack, + @NonNull final Predicate condition) { + return -1 != indexOf(haystack, condition); + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt index 09913526ec..0f00d0b57b 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt @@ -94,6 +94,12 @@ class CollectionUtilsTest { assertTrue(CollectionUtils.contains(arrayOf("A", "B", "C"), "C")) assertFalse(CollectionUtils.contains(arrayOf("A", "B", "C"), "D")) assertFalse(CollectionUtils.contains(null, "A")) + + val list = listOf("A", "B", "Ab", "C", "D", "E", "A", "E") + assertTrue(CollectionUtils.contains(list) { it.length == 2 }) + assertFalse(CollectionUtils.contains(list) { it.length < 1 }) + assertTrue(CollectionUtils.contains(list) { it > "A" }) + assertFalse(CollectionUtils.contains(list) { it > "F" }) } @Test From 96c4750d59884a78b0b45cdc1e0d3cd154c95705 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 4 Aug 2020 22:00:16 +0800 Subject: [PATCH 552/777] [ST02] Add methods for synthesizing DNS packets Bug: 139774492 Test: atest NetworkStaticLibTests:com.android.net.moduletests.util.DnsPacketUtilsTest Change-Id: I0c1547cbc1e7295e9a3dcb0f553065356b05bd7c --- staticlibs/Android.bp | 5 +- .../android/net/module/util/DnsPacket.java | 407 +++++++++++++++++- .../net/module/util/DnsPacketUtils.java | 59 ++- .../net/module/util/DnsPacketTest.java | 273 +++++++++++- .../net/module/util/DnsPacketUtilsTest.java | 37 ++ 5 files changed, 755 insertions(+), 26 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 4dfc752bb5..f4997a1691 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -96,7 +96,10 @@ java_library { visibility: [ "//packages/services/Iwlan:__subpackages__", ], - libs: ["framework-annotations-lib"], + libs: [ + "framework-annotations-lib", + "framework-connectivity.stubs.module_lib", + ], } filegroup { diff --git a/staticlibs/framework/com/android/net/module/util/DnsPacket.java b/staticlibs/framework/com/android/net/module/util/DnsPacket.java index 080781c1ff..13a83ad7de 100644 --- a/staticlibs/framework/com/android/net/module/util/DnsPacket.java +++ b/staticlibs/framework/com/android/net/module/util/DnsPacket.java @@ -16,15 +16,35 @@ package com.android.net.module.util; +import static android.net.DnsResolver.TYPE_A; +import static android.net.DnsResolver.TYPE_AAAA; +import static android.net.DnsResolver.TYPE_CNAME; + +import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; +import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; +import static com.android.net.module.util.DnsPacketUtils.DnsRecordParser.domainNameToLabels; + +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.text.TextUtils; +import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.DnsPacketUtils.DnsRecordParser; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.net.InetAddress; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Objects; /** * Defines basic data for DNS protocol based on RFC 1035. @@ -50,13 +70,29 @@ public abstract class DnsPacket { } /** - * DNS header for DNS protocol based on RFC 1035. + * DNS header for DNS protocol based on RFC 1035 section 4.1.1. + * + * 1 1 1 1 1 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | ID | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * |QR| Opcode |AA|TC|RD|RA| Z | RCODE | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | QDCOUNT | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | ANCOUNT | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | NSCOUNT | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | ARCOUNT | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ */ - public class DnsHeader { + public static class DnsHeader { private static final String TAG = "DnsHeader"; - public final int id; - public final int flags; - public final int rcode; + private static final int SIZE_IN_BYTES = 12; + private final int mId; + private final int mFlags; private final int[] mRecordCount; /* If this bit in the 'flags' field is set to 0, the DNS message corresponding to this @@ -73,10 +109,11 @@ public abstract class DnsPacket { * advanced to the end of the DNS header record. * This is meant to chain with other methods reading a DNS response in sequence. */ - DnsHeader(@NonNull ByteBuffer buf) throws BufferUnderflowException { - id = Short.toUnsignedInt(buf.getShort()); - flags = Short.toUnsignedInt(buf.getShort()); - rcode = flags & 0xF; + @VisibleForTesting + public DnsHeader(@NonNull ByteBuffer buf) throws BufferUnderflowException { + Objects.requireNonNull(buf); + mId = Short.toUnsignedInt(buf.getShort()); + mFlags = Short.toUnsignedInt(buf.getShort()); mRecordCount = new int[NUM_SECTIONS]; for (int i = 0; i < NUM_SECTIONS; ++i) { mRecordCount[i] = Short.toUnsignedInt(buf.getShort()); @@ -88,7 +125,23 @@ public abstract class DnsPacket { * RFC 1035 Section 4.1.1. */ public boolean isResponse() { - return (flags & (1 << FLAGS_SECTION_QR_BIT)) != 0; + return (mFlags & (1 << FLAGS_SECTION_QR_BIT)) != 0; + } + + /** + * Create a new DnsHeader from specified parameters. + * + * This constructor only builds the question and answer sections. Authority + * and additional sections are not supported. Useful when synthesizing dns + * responses from query or reply packets. + */ + @VisibleForTesting + public DnsHeader(int id, int flags, int qdcount, int ancount) { + this.mId = id; + this.mFlags = flags; + mRecordCount = new int[NUM_SECTIONS]; + mRecordCount[QDSECTION] = qdcount; + mRecordCount[ANSECTION] = ancount; } /** @@ -97,15 +150,103 @@ public abstract class DnsPacket { public int getRecordCount(int type) { return mRecordCount[type]; } + + /** + * Get flags of this instance. + */ + public int getFlags() { + return mFlags; + } + + /** + * Get id of this instance. + */ + public int getId() { + return mId; + } + + @Override + public String toString() { + return "DnsHeader{" + "id=" + mId + ", flags=" + mFlags + + ", recordCounts=" + Arrays.toString(mRecordCount) + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o.getClass() != getClass()) return false; + final DnsHeader other = (DnsHeader) o; + return mId == other.mId + && mFlags == other.mFlags + && Arrays.equals(mRecordCount, other.mRecordCount); + } + + @Override + public int hashCode() { + return 31 * mId + 37 * mFlags + Arrays.hashCode(mRecordCount); + } + + /** + * Get DnsHeader as byte array. + */ + @NonNull + public byte[] getBytes() { + // TODO: if this is called often, optimize the ByteBuffer out and write to the + // array directly. + final ByteBuffer buf = ByteBuffer.allocate(SIZE_IN_BYTES); + buf.putShort((short) mId); + buf.putShort((short) mFlags); + for (int i = 0; i < NUM_SECTIONS; ++i) { + buf.putShort((short) mRecordCount[i]); + } + return buf.array(); + } } /** * Superclass for DNS questions and DNS resource records. * - * DNS questions (No TTL/RDATA) - * DNS resource records (With TTL/RDATA) + * DNS questions (No TTL/RDLENGTH/RDATA) based on RFC 1035 section 4.1.2. + * 1 1 1 1 1 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | | + * / QNAME / + * / / + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | QTYPE | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | QCLASS | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * + * DNS resource records (With TTL/RDLENGTH/RDATA) based on RFC 1035 section 4.1.3. + * 1 1 1 1 1 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | | + * / / + * / NAME / + * | | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | TYPE | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | CLASS | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | TTL | + * | | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | RDLENGTH | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + * / RDATA / + * / / + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ */ - public class DnsRecord { + // TODO: Make DnsResourceRecord and DnsQuestion subclasses of DnsRecord, and construct + // corresponding object from factory methods. + public static class DnsRecord { + // Refer to RFC 1035 section 2.3.4 for MAXNAMESIZE. + // NAME_NORMAL and NAME_COMPRESSION are used for checking name compression, + // refer to rfc 1035 section 4.1.4. private static final int MAXNAMESIZE = 255; public static final int NAME_NORMAL = 0; public static final int NAME_COMPRESSION = 0xC0; @@ -117,22 +258,31 @@ public abstract class DnsPacket { public final int nsClass; public final long ttl; private final byte[] mRdata; + /** + * Type of this DNS record. + */ + @RecordType + public final int rType; /** * Create a new DnsRecord from a positioned ByteBuffer. * * Reads the passed ByteBuffer from its current position and decodes a DNS record. * When this constructor returns, the reading position of the ByteBuffer has been - * advanced to the end of the DNS header record. + * advanced to the end of the DNS resource record. * This is meant to chain with other methods reading a DNS response in sequence. * + * @param rType Type of the record. * @param buf ByteBuffer input of record, must be in network byte order * (which is the default). */ - DnsRecord(int recordType, @NonNull ByteBuffer buf) + @VisibleForTesting(visibility = PACKAGE) + public DnsRecord(@RecordType int rType, @NonNull ByteBuffer buf) throws BufferUnderflowException, ParseException { + Objects.requireNonNull(buf); + this.rType = rType; dName = DnsRecordParser.parseName(buf, 0 /* Parse depth */, - /* isNameCompressionSupported= */ true); + true /* isNameCompressionSupported */); if (dName.length() > MAXNAMESIZE) { throw new ParseException( "Parse name fail, name size is too long: " + dName.length()); @@ -140,7 +290,7 @@ public abstract class DnsPacket { nsType = Short.toUnsignedInt(buf.getShort()); nsClass = Short.toUnsignedInt(buf.getShort()); - if (recordType != QDSECTION) { + if (rType != QDSECTION) { ttl = Integer.toUnsignedLong(buf.getInt()); final int length = Short.toUnsignedInt(buf.getShort()); mRdata = new byte[length]; @@ -151,6 +301,95 @@ public abstract class DnsPacket { } } + /** + * Make an A or AAAA record based on the specified parameters. + * + * @param rType Type of the record, can be {@link #ANSECTION}, {@link #ARSECTION} + * or {@link #NSSECTION}. + * @param dName Domain name of the record. + * @param nsClass Class of the record. See RFC 1035 section 3.2.4. + * @param ttl time interval (in seconds) that the resource record may be + * cached before it should be discarded. Zero values are + * interpreted to mean that the RR can only be used for the + * transaction in progress, and should not be cached. + * @param address Instance of {@link InetAddress} + * @return A record if the {@code address} is an IPv4 address, or AAAA record if the + * {@code address} is an IPv6 address. + */ + public static DnsRecord makeAOrAAAARecord(int rType, @NonNull String dName, + int nsClass, long ttl, @NonNull InetAddress address) throws IOException { + final int nsType = (address.getAddress().length == 4) ? TYPE_A : TYPE_AAAA; + return new DnsRecord(rType, dName, nsType, nsClass, ttl, address, null /* rDataStr */); + } + + /** + * Make an CNAME record based on the specified parameters. + * + * @param rType Type of the record, can be {@link #ANSECTION}, {@link #ARSECTION} + * or {@link #NSSECTION}. + * @param dName Domain name of the record. + * @param nsClass Class of the record. See RFC 1035 section 3.2.4. + * @param ttl time interval (in seconds) that the resource record may be + * cached before it should be discarded. Zero values are + * interpreted to mean that the RR can only be used for the + * transaction in progress, and should not be cached. + * @param domainName Canonical name of the {@code dName}. + * @return A record if the {@code address} is an IPv4 address, or AAAA record if the + * {@code address} is an IPv6 address. + */ + public static DnsRecord makeCNameRecord(int rType, @NonNull String dName, int nsClass, + long ttl, @NonNull String domainName) throws IOException { + return new DnsRecord(rType, dName, TYPE_CNAME, nsClass, ttl, null /* address */, + domainName); + } + + /** + * Make a DNS question based on the specified parameters. + */ + public static DnsRecord makeQuestion(@NonNull String dName, int nsType, int nsClass) { + return new DnsRecord(dName, nsType, nsClass); + } + + private static String requireHostName(@NonNull String name) { + if (!DnsRecordParser.isHostName(name)) { + throw new IllegalArgumentException("Expected domain name but got " + name); + } + return name; + } + + /** + * Create a new query DnsRecord from specified parameters, useful when synthesizing + * dns response. + */ + private DnsRecord(@NonNull String dName, int nsType, int nsClass) { + this.rType = QDSECTION; + this.dName = requireHostName(dName); + this.nsType = nsType; + this.nsClass = nsClass; + mRdata = null; + this.ttl = 0; + } + + /** + * Create a new CNAME/A/AAAA DnsRecord from specified parameters. + * + * @param address The address only used when synthesizing A or AAAA record. + * @param rDataStr The alias of the domain, only used when synthesizing CNAME record. + */ + private DnsRecord(@RecordType int rType, @NonNull String dName, int nsType, int nsClass, + long ttl, @Nullable InetAddress address, @Nullable String rDataStr) + throws IOException { + this.rType = rType; + this.dName = requireHostName(dName); + this.nsType = nsType; + this.nsClass = nsClass; + if (rType < 0 || rType >= NUM_SECTIONS || rType == QDSECTION) { + throw new IllegalArgumentException("Unexpected record type: " + rType); + } + mRdata = nsType == TYPE_CNAME ? domainNameToLabels(rDataStr) : address.getAddress(); + this.ttl = ttl; + } + /** * Get a copy of rdata. */ @@ -159,13 +398,84 @@ public abstract class DnsPacket { return (mRdata == null) ? null : mRdata.clone(); } + /** + * Get DnsRecord as byte array. + */ + @NonNull + public byte[] getBytes() throws IOException { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final DataOutputStream dos = new DataOutputStream(baos); + dos.write(domainNameToLabels(dName)); + dos.writeShort(nsType); + dos.writeShort(nsClass); + if (rType != QDSECTION) { + dos.writeInt((int) ttl); + if (mRdata == null) { + dos.writeShort(0); + } else { + dos.writeShort(mRdata.length); + dos.write(mRdata); + } + } + return baos.toByteArray(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o.getClass() != getClass()) return false; + final DnsRecord other = (DnsRecord) o; + return rType == other.rType + && nsType == other.nsType + && nsClass == other.nsClass + && ttl == other.ttl + && TextUtils.equals(dName, other.dName) + && Arrays.equals(mRdata, other.mRdata); + } + + @Override + public int hashCode() { + return 31 * Objects.hash(dName) + + 37 * ((int) (ttl & 0xFFFFFFFF)) + + 41 * ((int) (ttl >> 32)) + + 43 * nsType + + 47 * nsClass + + 53 * rType + + Arrays.hashCode(mRdata); + } + + @Override + public String toString() { + return "DnsRecord{" + + "rType=" + rType + + ", dName='" + dName + '\'' + + ", nsType=" + nsType + + ", nsClass=" + nsClass + + ", ttl=" + ttl + + ", mRdata=" + Arrays.toString(mRdata) + + '}'; + } } + /** + * Header section types, refer to RFC 1035 section 4.1.1. + */ public static final int QDSECTION = 0; public static final int ANSECTION = 1; public static final int NSSECTION = 2; public static final int ARSECTION = 3; - private static final int NUM_SECTIONS = ARSECTION + 1; + @VisibleForTesting(visibility = PRIVATE) + static final int NUM_SECTIONS = ARSECTION + 1; + + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + QDSECTION, + ANSECTION, + NSSECTION, + ARSECTION, + }) + public @interface RecordType {} + private static final String TAG = DnsPacket.class.getSimpleName(); @@ -189,9 +499,7 @@ public abstract class DnsPacket { for (int i = 0; i < NUM_SECTIONS; ++i) { final int count = mHeader.getRecordCount(i); - if (count > 0) { - mRecords[i] = new ArrayList(count); - } + mRecords[i] = new ArrayList(count); for (int j = 0; j < count; ++j) { try { mRecords[i].add(new DnsRecord(i, buffer)); @@ -201,4 +509,61 @@ public abstract class DnsPacket { } } } + + /** + * Create a new {@link #DnsPacket} from specified parameters. + * + * Note that authority records section and additional records section is not supported. + */ + protected DnsPacket(@NonNull DnsHeader header, @NonNull List qd, + @NonNull List an) { + mHeader = Objects.requireNonNull(header); + mRecords = new List[NUM_SECTIONS]; + mRecords[QDSECTION] = Collections.unmodifiableList(new ArrayList<>(qd)); + mRecords[ANSECTION] = Collections.unmodifiableList(new ArrayList<>(an)); + mRecords[NSSECTION] = new ArrayList<>(); + mRecords[ARSECTION] = new ArrayList<>(); + for (int i = 0; i < NUM_SECTIONS; i++) { + if (mHeader.mRecordCount[i] != mRecords[i].size()) { + throw new IllegalArgumentException("Record count mismatch: expected " + + mHeader.mRecordCount[i] + " but was " + mRecords[i]); + } + } + } + + /** + * Get DnsPacket as byte array. + */ + public @NonNull byte[] getBytes() throws IOException { + final ByteArrayOutputStream buf = new ByteArrayOutputStream(); + buf.write(mHeader.getBytes()); + + for (int i = 0; i < NUM_SECTIONS; ++i) { + for (final DnsRecord record : mRecords[i]) { + buf.write(record.getBytes()); + } + } + return buf.toByteArray(); + } + + @Override + public String toString() { + return "DnsPacket{" + "header=" + mHeader + ", records='" + Arrays.toString(mRecords) + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o.getClass() != getClass()) return false; + final DnsPacket other = (DnsPacket) o; + return Objects.equals(mHeader, other.mHeader) + && Arrays.deepEquals(mRecords, other.mRecords); + } + + @Override + public int hashCode() { + int result = Objects.hash(mHeader); + result = 31 * result + Arrays.hashCode(mRecords); + return result; + } } diff --git a/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java b/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java index 3448cadf6f..c47bfa0746 100644 --- a/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java +++ b/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java @@ -20,10 +20,19 @@ import static com.android.net.module.util.DnsPacket.DnsRecord.NAME_COMPRESSION; import static com.android.net.module.util.DnsPacket.DnsRecord.NAME_NORMAL; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.InetAddresses; +import android.net.ParseException; import android.text.TextUtils; +import android.util.Patterns; +import com.android.internal.annotations.VisibleForTesting; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.text.DecimalFormat; import java.text.FieldPosition; @@ -38,6 +47,7 @@ public final class DnsPacketUtils { */ public static class DnsRecordParser { private static final int MAXLABELSIZE = 63; + private static final int MAXNAMESIZE = 255; private static final int MAXLABELCOUNT = 128; private static final DecimalFormat sByteFormat = new DecimalFormat(); @@ -48,7 +58,8 @@ public final class DnsPacketUtils { * *

Follows the same conversion rules of the native code (ns_name.c in libc). */ - private static String labelToString(@NonNull byte[] label) { + @VisibleForTesting + static String labelToString(@NonNull byte[] label) { final StringBuffer sb = new StringBuffer(); for (int i = 0; i < label.length; ++i) { @@ -71,6 +82,52 @@ public final class DnsPacketUtils { return sb.toString(); } + /** + * Converts domain name to labels according to RFC 1035. + * + * @param name Domain name as String that needs to be converted to labels. + * @return An encoded byte array that is constructed out of labels, + * and ends with zero-length label. + * @throws ParseException if failed to parse the given domain name or + * IOException if failed to output labels. + */ + public static @NonNull byte[] domainNameToLabels(@NonNull String name) throws + IOException, ParseException { + if (name.length() > MAXNAMESIZE) { + throw new ParseException("Domain name exceeds max length: " + name.length()); + } + if (!isHostName(name)) { + throw new ParseException("Failed to parse domain name: " + name); + } + final ByteArrayOutputStream buf = new ByteArrayOutputStream(); + final String[] labels = name.split("\\."); + for (final String label : labels) { + if (label.length() > MAXLABELSIZE) { + throw new ParseException("label is too long: " + label); + } + buf.write(label.length()); + // Encode as UTF-8 as suggested in RFC 6055 section 3. + buf.write(label.getBytes(StandardCharsets.UTF_8)); + } + buf.write(0x00); // end with zero-length label + return buf.toByteArray(); + } + + /** + * Check whether the input is a valid hostname based on rfc 1035 section 3.3. + * + * @param hostName the target host name. + * @return true if the input is a valid hostname. + */ + public static boolean isHostName(@Nullable String hostName) { + // TODO: Use {@code Patterns.HOST_NAME} if available. + // Patterns.DOMAIN_NAME accepts host names or IP addresses, so reject + // IP addresses. + return hostName != null + && Patterns.DOMAIN_NAME.matcher(hostName).matches() + && !InetAddresses.isNumericAddress(hostName); + } + /** * Parses the domain / target name of a DNS record. * diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java index 1bbba08804..409c1ebb77 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java @@ -16,26 +16,45 @@ package com.android.net.module.util; +import static android.net.DnsResolver.CLASS_IN; +import static android.net.DnsResolver.TYPE_A; +import static android.net.DnsResolver.TYPE_AAAA; + import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.annotation.NonNull; +import android.annotation.Nullable; + import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import libcore.net.InetAddressUtils; + import org.junit.Test; import org.junit.runner.RunWith; +import java.io.IOException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @RunWith(AndroidJUnit4.class) @SmallTest public class DnsPacketTest { + private static final int TEST_DNS_PACKET_ID = 0x7722; + private static final int TEST_DNS_PACKET_FLAGS = 0x8180; + private void assertHeaderParses(DnsPacket.DnsHeader header, int id, int flag, int qCount, int aCount, int nsCount, int arCount) { - assertEquals(header.id, id); - assertEquals(header.flags, flag); + assertEquals(header.getId(), id); + assertEquals(header.getFlags(), flag); assertEquals(header.getRecordCount(DnsPacket.QDSECTION), qCount); assertEquals(header.getRecordCount(DnsPacket.ANSECTION), aCount); assertEquals(header.getRecordCount(DnsPacket.NSSECTION), nsCount); @@ -51,11 +70,16 @@ public class DnsPacketTest { assertTrue(Arrays.equals(record.getRR(), rr)); } - class TestDnsPacket extends DnsPacket { + static class TestDnsPacket extends DnsPacket { TestDnsPacket(byte[] data) throws DnsPacket.ParseException { super(data); } + TestDnsPacket(@NonNull DnsHeader header, @Nullable ArrayList qd, + @Nullable ArrayList an) { + super(header, qd, an); + } + public DnsHeader getHeader() { return mHeader; } @@ -156,4 +180,247 @@ public class DnsPacketTest { new byte[]{ 0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 }); } + + /** Verifies that the synthesized {@link DnsPacket.DnsHeader} can be parsed correctly. */ + @Test + public void testDnsHeaderSynthesize() { + final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(TEST_DNS_PACKET_ID, + TEST_DNS_PACKET_FLAGS, 3 /* qcount */, 5 /* ancount */); + final DnsPacket.DnsHeader actualHeader = new DnsPacket.DnsHeader( + ByteBuffer.wrap(testHeader.getBytes())); + assertEquals(testHeader, actualHeader); + } + + /** Verifies that the synthesized {@link DnsPacket.DnsRecord} can be parsed correctly. */ + @Test + public void testDnsRecordSynthesize() throws IOException { + assertDnsRecordRoundTrip( + DnsPacket.DnsRecord.makeAOrAAAARecord(DnsPacket.ANSECTION, + "test.com", CLASS_IN, 5 /* ttl */, + InetAddressUtils.parseNumericAddress("abcd::fedc"))); + assertDnsRecordRoundTrip(DnsPacket.DnsRecord.makeQuestion("test.com", TYPE_AAAA, CLASS_IN)); + assertDnsRecordRoundTrip(DnsPacket.DnsRecord.makeCNameRecord(DnsPacket.ANSECTION, + "test.com", CLASS_IN, 0 /* ttl */, "example.com")); + } + + /** + * Verifies ttl/rData error handling when parsing + * {@link DnsPacket.DnsRecord} from bytes. + */ + @Test + public void testDnsRecordTTLRDataErrorHandling() throws IOException { + // Verify the constructor ignore ttl/rData of questions even if they are supplied. + final byte[] qdWithTTLRData = new byte[]{ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x00, /* Type */ + 0x00, 0x01, /* Class */ + 0x00, 0x00, 0x01, 0x2b, /* TTL */ + 0x00, 0x04, /* Data length */ + (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 /* Address */}; + final DnsPacket.DnsRecord questionsFromBytes = + new DnsPacket.DnsRecord(DnsPacket.QDSECTION, ByteBuffer.wrap(qdWithTTLRData)); + assertEquals(0, questionsFromBytes.ttl); + assertNull(questionsFromBytes.getRR()); + + // Verify ANSECTION must have rData when constructing. + final byte[] anWithoutTTLRData = new byte[]{ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */}; + assertThrows(BufferUnderflowException.class, () -> + new DnsPacket.DnsRecord(DnsPacket.ANSECTION, ByteBuffer.wrap(anWithoutTTLRData))); + } + + private void assertDnsRecordRoundTrip(DnsPacket.DnsRecord before) + throws IOException { + final DnsPacket.DnsRecord after = new DnsPacket.DnsRecord(before.rType, + ByteBuffer.wrap(before.getBytes())); + assertEquals(after, before); + } + + /** Verifies that the synthesized {@link DnsPacket} can be parsed correctly. */ + @Test + public void testDnsPacketSynthesize() throws IOException { + // Ipv4 dns response packet generated by scapy: + // dns_r = scapy.DNS( + // id=0xbeef, + // qr=1, + // qd=scapy.DNSQR(qname="hello.example.com"), + // an=scapy.DNSRR(rrname="hello.example.com", type="CNAME", rdata='test.com') / + // scapy.DNSRR(rrname="hello.example.com", rdata='1.2.3.4')) + // scapy.hexdump(dns_r) + // dns_r.show2() + // Note that since the synthesizing does not support name compression yet, the domain + // name of the sample need to be uncompressed when generating. + final byte[] v4BlobUncompressed = new byte[]{ + /* Header */ + (byte) 0xbe, (byte) 0xef, /* Transaction ID */ + (byte) 0x81, 0x00, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x02, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, + 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name: hello.example.com */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + /* Answers */ + 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, + 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name: hello.example.com */ + 0x00, 0x05, /* Type */ + 0x00, 0x01, /* Class */ + 0x00, 0x00, 0x00, 0x00, /* TTL */ + 0x00, 0x0A, /* Data length */ + 0x04, 0x74, 0x65, 0x73, 0x74, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Alias: test.com */ + 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, + 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name: hello.example.com */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + 0x00, 0x00, 0x00, 0x00, /* TTL */ + 0x00, 0x04, /* Data length */ + 0x01, 0x02, 0x03, 0x04, /* Address: 1.2.3.4 */ + }; + + // Forge one via constructors. + final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(0xbeef, + 0x8100, 1 /* qcount */, 2 /* ancount */); + final ArrayList qlist = new ArrayList<>(); + final ArrayList alist = new ArrayList<>(); + qlist.add(DnsPacket.DnsRecord.makeQuestion( + "hello.example.com", TYPE_A, CLASS_IN)); + alist.add(DnsPacket.DnsRecord.makeCNameRecord( + DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */, "test.com")); + alist.add(DnsPacket.DnsRecord.makeAOrAAAARecord( + DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */, + InetAddressUtils.parseNumericAddress("1.2.3.4"))); + final TestDnsPacket testPacket = new TestDnsPacket(testHeader, qlist, alist); + + // Assert content equals in both ways. + assertTrue(Arrays.equals(v4BlobUncompressed, testPacket.getBytes())); + assertEquals(new TestDnsPacket(v4BlobUncompressed), testPacket); + } + + @Test + public void testDnsPacketSynthesize_recordCountMismatch() throws IOException { + final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(0xbeef, + 0x8100, 1 /* qcount */, 1 /* ancount */); + final ArrayList qlist = new ArrayList<>(); + final ArrayList alist = new ArrayList<>(); + qlist.add(DnsPacket.DnsRecord.makeQuestion( + "hello.example.com", TYPE_A, CLASS_IN)); + + // Assert throws if the supplied answer records fewer than the declared count. + assertThrows(IllegalArgumentException.class, () -> + new TestDnsPacket(testHeader, qlist, alist)); + + // Assert throws if the supplied answer records more than the declared count. + alist.add(DnsPacket.DnsRecord.makeCNameRecord( + DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */, "test.com")); + alist.add(DnsPacket.DnsRecord.makeAOrAAAARecord( + DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */, + InetAddressUtils.parseNumericAddress("1.2.3.4"))); + assertThrows(IllegalArgumentException.class, () -> + new TestDnsPacket(testHeader, qlist, alist)); + + // Assert counts matched if the byte buffer still has data when parsing ended. + final byte[] blobTooMuchData = new byte[]{ + /* Header */ + (byte) 0xbe, (byte) 0xef, /* Transaction ID */ + (byte) 0x81, 0x00, /* Flags */ + 0x00, 0x00, /* Questions */ + 0x00, 0x00, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, + 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + }; + final TestDnsPacket packetFromTooMuchData = new TestDnsPacket(blobTooMuchData); + for (int i = 0; i < DnsPacket.NUM_SECTIONS; i++) { + assertEquals(0, packetFromTooMuchData.getRecordList(i).size()); + assertEquals(0, packetFromTooMuchData.getHeader().getRecordCount(i)); + } + + // Assert throws if the byte buffer ended when expecting more records. + final byte[] blobNotEnoughData = new byte[]{ + /* Header */ + (byte) 0xbe, (byte) 0xef, /* Transaction ID */ + (byte) 0x81, 0x00, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x02, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, + 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + /* Answers */ + 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, + 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + 0x00, 0x00, 0x00, 0x00, /* TTL */ + 0x00, 0x04, /* Data length */ + 0x01, 0x02, 0x03, 0x04, /* Address */ + }; + assertThrows(DnsPacket.ParseException.class, () -> new TestDnsPacket(blobNotEnoughData)); + } + + @Test + public void testEqualsAndHashCode() throws IOException { + // Verify DnsHeader equals and hashCode. + final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(TEST_DNS_PACKET_ID, + TEST_DNS_PACKET_FLAGS, 1 /* qcount */, 1 /* ancount */); + final DnsPacket.DnsHeader emptyHeader = new DnsPacket.DnsHeader(TEST_DNS_PACKET_ID + 1, + TEST_DNS_PACKET_FLAGS + 0x08, 0 /* qcount */, 0 /* ancount */); + final DnsPacket.DnsHeader headerFromBytes = + new DnsPacket.DnsHeader(ByteBuffer.wrap(testHeader.getBytes())); + assertEquals(testHeader, headerFromBytes); + assertEquals(testHeader.hashCode(), headerFromBytes.hashCode()); + assertNotEquals(testHeader, emptyHeader); + assertNotEquals(testHeader.hashCode(), emptyHeader.hashCode()); + assertNotEquals(headerFromBytes, emptyHeader); + assertNotEquals(headerFromBytes.hashCode(), emptyHeader.hashCode()); + + // Verify DnsRecord equals and hashCode. + final DnsPacket.DnsRecord testQuestion = DnsPacket.DnsRecord.makeQuestion( + "test.com", TYPE_AAAA, CLASS_IN); + final DnsPacket.DnsRecord testAnswer = DnsPacket.DnsRecord.makeCNameRecord( + DnsPacket.ANSECTION, "test.com", CLASS_IN, 9, "www.test.com"); + final DnsPacket.DnsRecord questionFromBytes = new DnsPacket.DnsRecord(DnsPacket.QDSECTION, + ByteBuffer.wrap(testQuestion.getBytes())); + assertEquals(testQuestion, questionFromBytes); + assertEquals(testQuestion.hashCode(), questionFromBytes.hashCode()); + assertNotEquals(testQuestion, testAnswer); + assertNotEquals(testQuestion.hashCode(), testAnswer.hashCode()); + assertNotEquals(questionFromBytes, testAnswer); + assertNotEquals(questionFromBytes.hashCode(), testAnswer.hashCode()); + + // Verify DnsPacket equals and hashCode. + final ArrayList qlist = new ArrayList<>(); + final ArrayList alist = new ArrayList<>(); + qlist.add(testQuestion); + alist.add(testAnswer); + final TestDnsPacket testPacket = new TestDnsPacket(testHeader, qlist, alist); + final TestDnsPacket emptyPacket = new TestDnsPacket( + emptyHeader, new ArrayList<>(), new ArrayList<>()); + final TestDnsPacket packetFromBytes = new TestDnsPacket(testPacket.getBytes()); + assertEquals(testPacket, packetFromBytes); + assertEquals(testPacket.hashCode(), packetFromBytes.hashCode()); + assertNotEquals(testPacket, emptyPacket); + assertNotEquals(testPacket.hashCode(), emptyPacket.hashCode()); + assertNotEquals(packetFromBytes, emptyPacket); + assertNotEquals(packetFromBytes.hashCode(), emptyPacket.hashCode()); + + // Verify DnsPacket with empty list. + final TestDnsPacket emptyPacketFromBytes = new TestDnsPacket(emptyPacket.getBytes()); + assertEquals(emptyPacket, emptyPacketFromBytes); + assertEquals(emptyPacket.hashCode(), emptyPacketFromBytes.hashCode()); + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java index 48777acc7f..9e1ab8249a 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java @@ -18,12 +18,20 @@ package com.android.net.module.util; import static com.android.net.module.util.DnsPacketUtils.DnsRecordParser; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThrows; +import android.net.ParseException; +import android.os.Build; + import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.testutils.DevSdkIgnoreRule; + +import org.junit.Assert; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -32,6 +40,8 @@ import java.nio.ByteBuffer; @RunWith(AndroidJUnit4.class) @SmallTest public class DnsPacketUtilsTest { + @Rule + public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); /** * Verifies that the compressed NAME field in the answer section of the DNS message is parsed @@ -116,4 +126,31 @@ public class DnsPacketUtilsTest { notNameCompressedBuf, /* depth= */ 0, /* isNameCompressionSupported= */ false); assertEquals(domainName, "www.google.com"); } + + // Skip test on R- devices since ParseException only available on S+ devices. + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) + @Test + public void testDomainNameToLabels() throws Exception { + assertArrayEquals( + new byte[]{3, 'w', 'w', 'w', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm', 0}, + DnsRecordParser.domainNameToLabels("www.google.com")); + assertThrows(ParseException.class, () -> + DnsRecordParser.domainNameToLabels("aaa.")); + assertThrows(ParseException.class, () -> + DnsRecordParser.domainNameToLabels("aaa")); + assertThrows(ParseException.class, () -> + DnsRecordParser.domainNameToLabels(".")); + assertThrows(ParseException.class, () -> + DnsRecordParser.domainNameToLabels("")); + } + + @Test + public void testIsHostName() { + Assert.assertTrue(DnsRecordParser.isHostName("www.google.com")); + Assert.assertFalse(DnsRecordParser.isHostName("com")); + Assert.assertFalse(DnsRecordParser.isHostName("1.2.3.4")); + Assert.assertFalse(DnsRecordParser.isHostName("1234::5678")); + Assert.assertFalse(DnsRecordParser.isHostName(null)); + Assert.assertFalse(DnsRecordParser.isHostName("")); + } } From ea0fcc94eca5e2a09b3655b2b9e36995e3e48d8d Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Tue, 16 Aug 2022 03:46:15 +0000 Subject: [PATCH 553/777] Add idiag_sock_id to InetDiagMessage class Bug: 217624062 Test: atest NetworkStaticLibTests Change-Id: I9dc5b1d5b2d3da9ab21ce92b3f88d3f9d4d842f1 --- .../module/util/netlink/InetDiagMessage.java | 18 ++++++++++------ .../util/netlink/StructInetDiagMsg.java | 19 ++++++++++++++++- .../util/netlink/StructInetDiagSockId.java | 4 ++-- .../util/netlink/InetDiagSocketTest.java | 21 ++++++++++++++----- 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java index a8aef7b434..eff1f25dbe 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java @@ -106,21 +106,24 @@ public class InetDiagMessage extends NetlinkMessage { return bytes; } - public StructInetDiagMsg mStructInetDiagMsg; + public StructInetDiagMsg inetDiagMsg; private InetDiagMessage(@NonNull StructNlMsgHdr header) { super(header); - mStructInetDiagMsg = new StructInetDiagMsg(); + inetDiagMsg = new StructInetDiagMsg(); } /** * Parse an inet_diag_req_v2 message from buffer. */ - @NonNull + @Nullable public static InetDiagMessage parse(@NonNull StructNlMsgHdr header, @NonNull ByteBuffer byteBuffer) { final InetDiagMessage msg = new InetDiagMessage(header); - msg.mStructInetDiagMsg = StructInetDiagMsg.parse(byteBuffer); + msg.inetDiagMsg = StructInetDiagMsg.parse(byteBuffer); + if (msg.inetDiagMsg == null) { + return null; + } return msg; } @@ -133,12 +136,15 @@ public class InetDiagMessage extends NetlinkMessage { ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT_MS); final NetlinkMessage nlMsg = NetlinkMessage.parse(response, NETLINK_INET_DIAG); + if (nlMsg == null) { + return INVALID_UID; + } final StructNlMsgHdr hdr = nlMsg.getHeader(); if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) { return INVALID_UID; } if (nlMsg instanceof InetDiagMessage) { - return ((InetDiagMessage) nlMsg).mStructInetDiagMsg.idiag_uid; + return ((InetDiagMessage) nlMsg).inetDiagMsg.idiag_uid; } return INVALID_UID; } @@ -228,7 +234,7 @@ public class InetDiagMessage extends NetlinkMessage { + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString(NETLINK_INET_DIAG)) + "}, " + "inet_diag_msg{" - + (mStructInetDiagMsg == null ? "" : mStructInetDiagMsg.toString()) + "} " + + (inetDiagMsg == null ? "" : inetDiagMsg.toString()) + "} " + "}"; } } diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagMsg.java index 205656e3b5..ea018cf692 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagMsg.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagMsg.java @@ -16,6 +16,9 @@ package com.android.net.module.util.netlink; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.nio.ByteBuffer; /** @@ -40,15 +43,28 @@ import java.nio.ByteBuffer; */ public class StructInetDiagMsg { public static final int STRUCT_SIZE = 4 + StructInetDiagSockId.STRUCT_SIZE + 20; + private static final int IDIAG_SOCK_ID_OFFSET = StructNlMsgHdr.STRUCT_SIZE + 4; private static final int IDIAG_UID_OFFSET = StructNlMsgHdr.STRUCT_SIZE + 4 + StructInetDiagSockId.STRUCT_SIZE + 12; public int idiag_uid; + @NonNull + public StructInetDiagSockId id; /** * Parse inet diag netlink message from buffer. */ - public static StructInetDiagMsg parse(ByteBuffer byteBuffer) { + @Nullable + public static StructInetDiagMsg parse(@NonNull ByteBuffer byteBuffer) { + if (byteBuffer.remaining() < STRUCT_SIZE) { + return null; + } StructInetDiagMsg struct = new StructInetDiagMsg(); + final byte family = byteBuffer.get(); + byteBuffer.position(IDIAG_SOCK_ID_OFFSET); + struct.id = StructInetDiagSockId.parse(byteBuffer, family); + if (struct.id == null) { + return null; + } struct.idiag_uid = byteBuffer.getInt(IDIAG_UID_OFFSET); return struct; } @@ -57,6 +73,7 @@ public class StructInetDiagMsg { public String toString() { return "StructInetDiagMsg{ " + "idiag_uid{" + idiag_uid + "}, " + + "id{" + id + "}, " + "}"; } } diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java index 95723cbffd..648a020188 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java @@ -106,7 +106,7 @@ public class StructInetDiagSockId { byteBuffer.get(srcAddrByte); byteBuffer.get(dstAddrByte); } else { - Log.e(TAG, "Invalid address family: " + family); + Log.wtf(TAG, "Invalid address family: " + family); return null; } @@ -118,7 +118,7 @@ public class StructInetDiagSockId { } catch (UnknownHostException e) { // Should not happen. UnknownHostException is thrown only if addr byte array is of // illegal length. - Log.e(TAG, "Failed to parse address: " + e); + Log.wtf(TAG, "Failed to parse address: " + e); return null; } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java index 6b1482d839..c7e2a4db00 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java @@ -31,6 +31,8 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.net.InetAddresses; + import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -235,10 +237,10 @@ public class InetDiagSocketTest { // inet_diag_sockid "a817" + // idiag_sport = 43031 "960f" + // idiag_dport = 38415 - "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b - "00000000000000000000ffff08080808" + // idiag_dst = 8.8.8.8 - "00000000" + // idiag_if - "ffffffffffffffff" + // idiag_cookie = INET_DIAG_NOCOOKIE + "20010db8000000000000000000000001" + // idiag_src = 2001:db8::1 + "20010db8000000000000000000000002" + // idiag_dst = 2001:db8::2 + "07000000" + // idiag_if = 7 + "5800000000000000" + // idiag_cookie = 88 "00000000" + // idiag_expires "00000000" + // idiag_rqueue "00000000" + // idiag_wqueue @@ -256,7 +258,16 @@ public class InetDiagSocketTest { assertTrue(msg instanceof InetDiagMessage); final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg; - assertEquals(10147, inetDiagMsg.mStructInetDiagMsg.idiag_uid); + assertEquals(10147, inetDiagMsg.inetDiagMsg.idiag_uid); + final StructInetDiagSockId sockId = inetDiagMsg.inetDiagMsg.id; + assertEquals(43031, sockId.locSocketAddress.getPort()); + assertEquals(InetAddresses.parseNumericAddress("2001:db8::1"), + sockId.locSocketAddress.getAddress()); + assertEquals(38415, sockId.remSocketAddress.getPort()); + assertEquals(InetAddresses.parseNumericAddress("2001:db8::2"), + sockId.remSocketAddress.getAddress()); + assertEquals(7, sockId.ifIndex); + assertEquals(88, sockId.cookie); final StructNlMsgHdr hdr = inetDiagMsg.getHeader(); assertNotNull(hdr); From e301436409f9f7c8e3ab96fef865d82b231f3d64 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 6 Sep 2022 11:20:19 +0900 Subject: [PATCH 554/777] Introduce getResIntegerConfig This is a symmetric to getResBooleanConfig for integers. Test: new test in this patch Change-Id: I36cb910acb59c3211ba2c77dd3784fefa93545d9 --- .../android/net/module/util/DeviceConfigUtils.java | 13 +++++++++++++ .../net/module/util/DeviceConfigUtilsTest.java | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index 30a1c33208..f8f250d745 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -259,4 +259,17 @@ public final class DeviceConfigUtils { return defaultValue; } } + + /** + * Gets int config from resources. + */ + public static int getResIntegerConfig(@NonNull final Context context, + @BoolRes int configResource, final int defaultValue) { + final Resources res = context.getResources(); + try { + return res.getInteger(configResource); + } catch (Resources.NotFoundException e) { + return defaultValue; + } + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java index c65f79340a..a8e7993ae9 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -283,4 +283,13 @@ public class DeviceConfigUtilsTest { doThrow(new Resources.NotFoundException()).when(mResources).getBoolean(someResId); assertFalse(DeviceConfigUtils.getResBooleanConfig(mContext, someResId, false)); } + + @Test + public void testGetResIntegerConfig() { + final int someResId = 1234; + doReturn(2097).when(mResources).getInteger(someResId); + assertEquals(2097, DeviceConfigUtils.getResIntegerConfig(mContext, someResId, 2098)); + doThrow(new Resources.NotFoundException()).when(mResources).getInteger(someResId); + assertEquals(2098, DeviceConfigUtils.getResIntegerConfig(mContext, someResId, 2098)); + } } From f53c488b93e1bf1bb0ee26fe576b466042df712c Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 8 Sep 2022 11:01:05 +0000 Subject: [PATCH 555/777] Revert "[ST02] Add methods for synthesizing DNS packets" Revert "[ST02.1] Add TYPE_CNAME constant to DnsResolver" Revert submission 1387135-st02 Reason for revert: Usage of TYPE_CNAME in a library shared among modules does not interact well with current module release process Reverted Changes: Ib5616c65c:[ST02.2] Use the getters of DnsHeader I5e58f99b0:[ST02.1] Add TYPE_CNAME constant to DnsResolver I0c1547cbc:[ST02] Add methods for synthesizing DNS packets Change-Id: I9f8de47c9ba9fb4db7cf3695966f222f68a9a290 --- staticlibs/Android.bp | 5 +- .../android/net/module/util/DnsPacket.java | 407 +----------------- .../net/module/util/DnsPacketUtils.java | 59 +-- .../net/module/util/DnsPacketTest.java | 273 +----------- .../net/module/util/DnsPacketUtilsTest.java | 37 -- 5 files changed, 26 insertions(+), 755 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index f4997a1691..4dfc752bb5 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -96,10 +96,7 @@ java_library { visibility: [ "//packages/services/Iwlan:__subpackages__", ], - libs: [ - "framework-annotations-lib", - "framework-connectivity.stubs.module_lib", - ], + libs: ["framework-annotations-lib"], } filegroup { diff --git a/staticlibs/framework/com/android/net/module/util/DnsPacket.java b/staticlibs/framework/com/android/net/module/util/DnsPacket.java index 13a83ad7de..080781c1ff 100644 --- a/staticlibs/framework/com/android/net/module/util/DnsPacket.java +++ b/staticlibs/framework/com/android/net/module/util/DnsPacket.java @@ -16,35 +16,15 @@ package com.android.net.module.util; -import static android.net.DnsResolver.TYPE_A; -import static android.net.DnsResolver.TYPE_AAAA; -import static android.net.DnsResolver.TYPE_CNAME; - -import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; -import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; -import static com.android.net.module.util.DnsPacketUtils.DnsRecordParser.domainNameToLabels; - -import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.text.TextUtils; -import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.DnsPacketUtils.DnsRecordParser; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.net.InetAddress; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.List; -import java.util.Objects; /** * Defines basic data for DNS protocol based on RFC 1035. @@ -70,29 +50,13 @@ public abstract class DnsPacket { } /** - * DNS header for DNS protocol based on RFC 1035 section 4.1.1. - * - * 1 1 1 1 1 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | ID | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * |QR| Opcode |AA|TC|RD|RA| Z | RCODE | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QDCOUNT | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | ANCOUNT | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | NSCOUNT | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | ARCOUNT | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * DNS header for DNS protocol based on RFC 1035. */ - public static class DnsHeader { + public class DnsHeader { private static final String TAG = "DnsHeader"; - private static final int SIZE_IN_BYTES = 12; - private final int mId; - private final int mFlags; + public final int id; + public final int flags; + public final int rcode; private final int[] mRecordCount; /* If this bit in the 'flags' field is set to 0, the DNS message corresponding to this @@ -109,11 +73,10 @@ public abstract class DnsPacket { * advanced to the end of the DNS header record. * This is meant to chain with other methods reading a DNS response in sequence. */ - @VisibleForTesting - public DnsHeader(@NonNull ByteBuffer buf) throws BufferUnderflowException { - Objects.requireNonNull(buf); - mId = Short.toUnsignedInt(buf.getShort()); - mFlags = Short.toUnsignedInt(buf.getShort()); + DnsHeader(@NonNull ByteBuffer buf) throws BufferUnderflowException { + id = Short.toUnsignedInt(buf.getShort()); + flags = Short.toUnsignedInt(buf.getShort()); + rcode = flags & 0xF; mRecordCount = new int[NUM_SECTIONS]; for (int i = 0; i < NUM_SECTIONS; ++i) { mRecordCount[i] = Short.toUnsignedInt(buf.getShort()); @@ -125,23 +88,7 @@ public abstract class DnsPacket { * RFC 1035 Section 4.1.1. */ public boolean isResponse() { - return (mFlags & (1 << FLAGS_SECTION_QR_BIT)) != 0; - } - - /** - * Create a new DnsHeader from specified parameters. - * - * This constructor only builds the question and answer sections. Authority - * and additional sections are not supported. Useful when synthesizing dns - * responses from query or reply packets. - */ - @VisibleForTesting - public DnsHeader(int id, int flags, int qdcount, int ancount) { - this.mId = id; - this.mFlags = flags; - mRecordCount = new int[NUM_SECTIONS]; - mRecordCount[QDSECTION] = qdcount; - mRecordCount[ANSECTION] = ancount; + return (flags & (1 << FLAGS_SECTION_QR_BIT)) != 0; } /** @@ -150,103 +97,15 @@ public abstract class DnsPacket { public int getRecordCount(int type) { return mRecordCount[type]; } - - /** - * Get flags of this instance. - */ - public int getFlags() { - return mFlags; - } - - /** - * Get id of this instance. - */ - public int getId() { - return mId; - } - - @Override - public String toString() { - return "DnsHeader{" + "id=" + mId + ", flags=" + mFlags - + ", recordCounts=" + Arrays.toString(mRecordCount) + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o.getClass() != getClass()) return false; - final DnsHeader other = (DnsHeader) o; - return mId == other.mId - && mFlags == other.mFlags - && Arrays.equals(mRecordCount, other.mRecordCount); - } - - @Override - public int hashCode() { - return 31 * mId + 37 * mFlags + Arrays.hashCode(mRecordCount); - } - - /** - * Get DnsHeader as byte array. - */ - @NonNull - public byte[] getBytes() { - // TODO: if this is called often, optimize the ByteBuffer out and write to the - // array directly. - final ByteBuffer buf = ByteBuffer.allocate(SIZE_IN_BYTES); - buf.putShort((short) mId); - buf.putShort((short) mFlags); - for (int i = 0; i < NUM_SECTIONS; ++i) { - buf.putShort((short) mRecordCount[i]); - } - return buf.array(); - } } /** * Superclass for DNS questions and DNS resource records. * - * DNS questions (No TTL/RDLENGTH/RDATA) based on RFC 1035 section 4.1.2. - * 1 1 1 1 1 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | | - * / QNAME / - * / / - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QTYPE | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QCLASS | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * - * DNS resource records (With TTL/RDLENGTH/RDATA) based on RFC 1035 section 4.1.3. - * 1 1 1 1 1 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | | - * / / - * / NAME / - * | | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | TYPE | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | CLASS | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | TTL | - * | | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | RDLENGTH | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - * / RDATA / - * / / - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * DNS questions (No TTL/RDATA) + * DNS resource records (With TTL/RDATA) */ - // TODO: Make DnsResourceRecord and DnsQuestion subclasses of DnsRecord, and construct - // corresponding object from factory methods. - public static class DnsRecord { - // Refer to RFC 1035 section 2.3.4 for MAXNAMESIZE. - // NAME_NORMAL and NAME_COMPRESSION are used for checking name compression, - // refer to rfc 1035 section 4.1.4. + public class DnsRecord { private static final int MAXNAMESIZE = 255; public static final int NAME_NORMAL = 0; public static final int NAME_COMPRESSION = 0xC0; @@ -258,31 +117,22 @@ public abstract class DnsPacket { public final int nsClass; public final long ttl; private final byte[] mRdata; - /** - * Type of this DNS record. - */ - @RecordType - public final int rType; /** * Create a new DnsRecord from a positioned ByteBuffer. * * Reads the passed ByteBuffer from its current position and decodes a DNS record. * When this constructor returns, the reading position of the ByteBuffer has been - * advanced to the end of the DNS resource record. + * advanced to the end of the DNS header record. * This is meant to chain with other methods reading a DNS response in sequence. * - * @param rType Type of the record. * @param buf ByteBuffer input of record, must be in network byte order * (which is the default). */ - @VisibleForTesting(visibility = PACKAGE) - public DnsRecord(@RecordType int rType, @NonNull ByteBuffer buf) + DnsRecord(int recordType, @NonNull ByteBuffer buf) throws BufferUnderflowException, ParseException { - Objects.requireNonNull(buf); - this.rType = rType; dName = DnsRecordParser.parseName(buf, 0 /* Parse depth */, - true /* isNameCompressionSupported */); + /* isNameCompressionSupported= */ true); if (dName.length() > MAXNAMESIZE) { throw new ParseException( "Parse name fail, name size is too long: " + dName.length()); @@ -290,7 +140,7 @@ public abstract class DnsPacket { nsType = Short.toUnsignedInt(buf.getShort()); nsClass = Short.toUnsignedInt(buf.getShort()); - if (rType != QDSECTION) { + if (recordType != QDSECTION) { ttl = Integer.toUnsignedLong(buf.getInt()); final int length = Short.toUnsignedInt(buf.getShort()); mRdata = new byte[length]; @@ -301,95 +151,6 @@ public abstract class DnsPacket { } } - /** - * Make an A or AAAA record based on the specified parameters. - * - * @param rType Type of the record, can be {@link #ANSECTION}, {@link #ARSECTION} - * or {@link #NSSECTION}. - * @param dName Domain name of the record. - * @param nsClass Class of the record. See RFC 1035 section 3.2.4. - * @param ttl time interval (in seconds) that the resource record may be - * cached before it should be discarded. Zero values are - * interpreted to mean that the RR can only be used for the - * transaction in progress, and should not be cached. - * @param address Instance of {@link InetAddress} - * @return A record if the {@code address} is an IPv4 address, or AAAA record if the - * {@code address} is an IPv6 address. - */ - public static DnsRecord makeAOrAAAARecord(int rType, @NonNull String dName, - int nsClass, long ttl, @NonNull InetAddress address) throws IOException { - final int nsType = (address.getAddress().length == 4) ? TYPE_A : TYPE_AAAA; - return new DnsRecord(rType, dName, nsType, nsClass, ttl, address, null /* rDataStr */); - } - - /** - * Make an CNAME record based on the specified parameters. - * - * @param rType Type of the record, can be {@link #ANSECTION}, {@link #ARSECTION} - * or {@link #NSSECTION}. - * @param dName Domain name of the record. - * @param nsClass Class of the record. See RFC 1035 section 3.2.4. - * @param ttl time interval (in seconds) that the resource record may be - * cached before it should be discarded. Zero values are - * interpreted to mean that the RR can only be used for the - * transaction in progress, and should not be cached. - * @param domainName Canonical name of the {@code dName}. - * @return A record if the {@code address} is an IPv4 address, or AAAA record if the - * {@code address} is an IPv6 address. - */ - public static DnsRecord makeCNameRecord(int rType, @NonNull String dName, int nsClass, - long ttl, @NonNull String domainName) throws IOException { - return new DnsRecord(rType, dName, TYPE_CNAME, nsClass, ttl, null /* address */, - domainName); - } - - /** - * Make a DNS question based on the specified parameters. - */ - public static DnsRecord makeQuestion(@NonNull String dName, int nsType, int nsClass) { - return new DnsRecord(dName, nsType, nsClass); - } - - private static String requireHostName(@NonNull String name) { - if (!DnsRecordParser.isHostName(name)) { - throw new IllegalArgumentException("Expected domain name but got " + name); - } - return name; - } - - /** - * Create a new query DnsRecord from specified parameters, useful when synthesizing - * dns response. - */ - private DnsRecord(@NonNull String dName, int nsType, int nsClass) { - this.rType = QDSECTION; - this.dName = requireHostName(dName); - this.nsType = nsType; - this.nsClass = nsClass; - mRdata = null; - this.ttl = 0; - } - - /** - * Create a new CNAME/A/AAAA DnsRecord from specified parameters. - * - * @param address The address only used when synthesizing A or AAAA record. - * @param rDataStr The alias of the domain, only used when synthesizing CNAME record. - */ - private DnsRecord(@RecordType int rType, @NonNull String dName, int nsType, int nsClass, - long ttl, @Nullable InetAddress address, @Nullable String rDataStr) - throws IOException { - this.rType = rType; - this.dName = requireHostName(dName); - this.nsType = nsType; - this.nsClass = nsClass; - if (rType < 0 || rType >= NUM_SECTIONS || rType == QDSECTION) { - throw new IllegalArgumentException("Unexpected record type: " + rType); - } - mRdata = nsType == TYPE_CNAME ? domainNameToLabels(rDataStr) : address.getAddress(); - this.ttl = ttl; - } - /** * Get a copy of rdata. */ @@ -398,84 +159,13 @@ public abstract class DnsPacket { return (mRdata == null) ? null : mRdata.clone(); } - /** - * Get DnsRecord as byte array. - */ - @NonNull - public byte[] getBytes() throws IOException { - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final DataOutputStream dos = new DataOutputStream(baos); - dos.write(domainNameToLabels(dName)); - dos.writeShort(nsType); - dos.writeShort(nsClass); - if (rType != QDSECTION) { - dos.writeInt((int) ttl); - if (mRdata == null) { - dos.writeShort(0); - } else { - dos.writeShort(mRdata.length); - dos.write(mRdata); - } - } - return baos.toByteArray(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o.getClass() != getClass()) return false; - final DnsRecord other = (DnsRecord) o; - return rType == other.rType - && nsType == other.nsType - && nsClass == other.nsClass - && ttl == other.ttl - && TextUtils.equals(dName, other.dName) - && Arrays.equals(mRdata, other.mRdata); - } - - @Override - public int hashCode() { - return 31 * Objects.hash(dName) - + 37 * ((int) (ttl & 0xFFFFFFFF)) - + 41 * ((int) (ttl >> 32)) - + 43 * nsType - + 47 * nsClass - + 53 * rType - + Arrays.hashCode(mRdata); - } - - @Override - public String toString() { - return "DnsRecord{" - + "rType=" + rType - + ", dName='" + dName + '\'' - + ", nsType=" + nsType - + ", nsClass=" + nsClass - + ", ttl=" + ttl - + ", mRdata=" + Arrays.toString(mRdata) - + '}'; - } } - /** - * Header section types, refer to RFC 1035 section 4.1.1. - */ public static final int QDSECTION = 0; public static final int ANSECTION = 1; public static final int NSSECTION = 2; public static final int ARSECTION = 3; - @VisibleForTesting(visibility = PRIVATE) - static final int NUM_SECTIONS = ARSECTION + 1; - - @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - QDSECTION, - ANSECTION, - NSSECTION, - ARSECTION, - }) - public @interface RecordType {} - + private static final int NUM_SECTIONS = ARSECTION + 1; private static final String TAG = DnsPacket.class.getSimpleName(); @@ -499,7 +189,9 @@ public abstract class DnsPacket { for (int i = 0; i < NUM_SECTIONS; ++i) { final int count = mHeader.getRecordCount(i); - mRecords[i] = new ArrayList(count); + if (count > 0) { + mRecords[i] = new ArrayList(count); + } for (int j = 0; j < count; ++j) { try { mRecords[i].add(new DnsRecord(i, buffer)); @@ -509,61 +201,4 @@ public abstract class DnsPacket { } } } - - /** - * Create a new {@link #DnsPacket} from specified parameters. - * - * Note that authority records section and additional records section is not supported. - */ - protected DnsPacket(@NonNull DnsHeader header, @NonNull List qd, - @NonNull List an) { - mHeader = Objects.requireNonNull(header); - mRecords = new List[NUM_SECTIONS]; - mRecords[QDSECTION] = Collections.unmodifiableList(new ArrayList<>(qd)); - mRecords[ANSECTION] = Collections.unmodifiableList(new ArrayList<>(an)); - mRecords[NSSECTION] = new ArrayList<>(); - mRecords[ARSECTION] = new ArrayList<>(); - for (int i = 0; i < NUM_SECTIONS; i++) { - if (mHeader.mRecordCount[i] != mRecords[i].size()) { - throw new IllegalArgumentException("Record count mismatch: expected " - + mHeader.mRecordCount[i] + " but was " + mRecords[i]); - } - } - } - - /** - * Get DnsPacket as byte array. - */ - public @NonNull byte[] getBytes() throws IOException { - final ByteArrayOutputStream buf = new ByteArrayOutputStream(); - buf.write(mHeader.getBytes()); - - for (int i = 0; i < NUM_SECTIONS; ++i) { - for (final DnsRecord record : mRecords[i]) { - buf.write(record.getBytes()); - } - } - return buf.toByteArray(); - } - - @Override - public String toString() { - return "DnsPacket{" + "header=" + mHeader + ", records='" + Arrays.toString(mRecords) + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o.getClass() != getClass()) return false; - final DnsPacket other = (DnsPacket) o; - return Objects.equals(mHeader, other.mHeader) - && Arrays.deepEquals(mRecords, other.mRecords); - } - - @Override - public int hashCode() { - int result = Objects.hash(mHeader); - result = 31 * result + Arrays.hashCode(mRecords); - return result; - } } diff --git a/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java b/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java index c47bfa0746..3448cadf6f 100644 --- a/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java +++ b/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java @@ -20,19 +20,10 @@ import static com.android.net.module.util.DnsPacket.DnsRecord.NAME_COMPRESSION; import static com.android.net.module.util.DnsPacket.DnsRecord.NAME_NORMAL; import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.InetAddresses; -import android.net.ParseException; import android.text.TextUtils; -import android.util.Patterns; -import com.android.internal.annotations.VisibleForTesting; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; import java.text.DecimalFormat; import java.text.FieldPosition; @@ -47,7 +38,6 @@ public final class DnsPacketUtils { */ public static class DnsRecordParser { private static final int MAXLABELSIZE = 63; - private static final int MAXNAMESIZE = 255; private static final int MAXLABELCOUNT = 128; private static final DecimalFormat sByteFormat = new DecimalFormat(); @@ -58,8 +48,7 @@ public final class DnsPacketUtils { * *

Follows the same conversion rules of the native code (ns_name.c in libc). */ - @VisibleForTesting - static String labelToString(@NonNull byte[] label) { + private static String labelToString(@NonNull byte[] label) { final StringBuffer sb = new StringBuffer(); for (int i = 0; i < label.length; ++i) { @@ -82,52 +71,6 @@ public final class DnsPacketUtils { return sb.toString(); } - /** - * Converts domain name to labels according to RFC 1035. - * - * @param name Domain name as String that needs to be converted to labels. - * @return An encoded byte array that is constructed out of labels, - * and ends with zero-length label. - * @throws ParseException if failed to parse the given domain name or - * IOException if failed to output labels. - */ - public static @NonNull byte[] domainNameToLabels(@NonNull String name) throws - IOException, ParseException { - if (name.length() > MAXNAMESIZE) { - throw new ParseException("Domain name exceeds max length: " + name.length()); - } - if (!isHostName(name)) { - throw new ParseException("Failed to parse domain name: " + name); - } - final ByteArrayOutputStream buf = new ByteArrayOutputStream(); - final String[] labels = name.split("\\."); - for (final String label : labels) { - if (label.length() > MAXLABELSIZE) { - throw new ParseException("label is too long: " + label); - } - buf.write(label.length()); - // Encode as UTF-8 as suggested in RFC 6055 section 3. - buf.write(label.getBytes(StandardCharsets.UTF_8)); - } - buf.write(0x00); // end with zero-length label - return buf.toByteArray(); - } - - /** - * Check whether the input is a valid hostname based on rfc 1035 section 3.3. - * - * @param hostName the target host name. - * @return true if the input is a valid hostname. - */ - public static boolean isHostName(@Nullable String hostName) { - // TODO: Use {@code Patterns.HOST_NAME} if available. - // Patterns.DOMAIN_NAME accepts host names or IP addresses, so reject - // IP addresses. - return hostName != null - && Patterns.DOMAIN_NAME.matcher(hostName).matches() - && !InetAddresses.isNumericAddress(hostName); - } - /** * Parses the domain / target name of a DNS record. * diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java index 409c1ebb77..1bbba08804 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java @@ -16,45 +16,26 @@ package com.android.net.module.util; -import static android.net.DnsResolver.CLASS_IN; -import static android.net.DnsResolver.TYPE_A; -import static android.net.DnsResolver.TYPE_AAAA; - import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import android.annotation.NonNull; -import android.annotation.Nullable; - import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import libcore.net.InetAddressUtils; - import org.junit.Test; import org.junit.runner.RunWith; -import java.io.IOException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; @RunWith(AndroidJUnit4.class) @SmallTest public class DnsPacketTest { - private static final int TEST_DNS_PACKET_ID = 0x7722; - private static final int TEST_DNS_PACKET_FLAGS = 0x8180; - private void assertHeaderParses(DnsPacket.DnsHeader header, int id, int flag, int qCount, int aCount, int nsCount, int arCount) { - assertEquals(header.getId(), id); - assertEquals(header.getFlags(), flag); + assertEquals(header.id, id); + assertEquals(header.flags, flag); assertEquals(header.getRecordCount(DnsPacket.QDSECTION), qCount); assertEquals(header.getRecordCount(DnsPacket.ANSECTION), aCount); assertEquals(header.getRecordCount(DnsPacket.NSSECTION), nsCount); @@ -70,16 +51,11 @@ public class DnsPacketTest { assertTrue(Arrays.equals(record.getRR(), rr)); } - static class TestDnsPacket extends DnsPacket { + class TestDnsPacket extends DnsPacket { TestDnsPacket(byte[] data) throws DnsPacket.ParseException { super(data); } - TestDnsPacket(@NonNull DnsHeader header, @Nullable ArrayList qd, - @Nullable ArrayList an) { - super(header, qd, an); - } - public DnsHeader getHeader() { return mHeader; } @@ -180,247 +156,4 @@ public class DnsPacketTest { new byte[]{ 0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 }); } - - /** Verifies that the synthesized {@link DnsPacket.DnsHeader} can be parsed correctly. */ - @Test - public void testDnsHeaderSynthesize() { - final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(TEST_DNS_PACKET_ID, - TEST_DNS_PACKET_FLAGS, 3 /* qcount */, 5 /* ancount */); - final DnsPacket.DnsHeader actualHeader = new DnsPacket.DnsHeader( - ByteBuffer.wrap(testHeader.getBytes())); - assertEquals(testHeader, actualHeader); - } - - /** Verifies that the synthesized {@link DnsPacket.DnsRecord} can be parsed correctly. */ - @Test - public void testDnsRecordSynthesize() throws IOException { - assertDnsRecordRoundTrip( - DnsPacket.DnsRecord.makeAOrAAAARecord(DnsPacket.ANSECTION, - "test.com", CLASS_IN, 5 /* ttl */, - InetAddressUtils.parseNumericAddress("abcd::fedc"))); - assertDnsRecordRoundTrip(DnsPacket.DnsRecord.makeQuestion("test.com", TYPE_AAAA, CLASS_IN)); - assertDnsRecordRoundTrip(DnsPacket.DnsRecord.makeCNameRecord(DnsPacket.ANSECTION, - "test.com", CLASS_IN, 0 /* ttl */, "example.com")); - } - - /** - * Verifies ttl/rData error handling when parsing - * {@link DnsPacket.DnsRecord} from bytes. - */ - @Test - public void testDnsRecordTTLRDataErrorHandling() throws IOException { - // Verify the constructor ignore ttl/rData of questions even if they are supplied. - final byte[] qdWithTTLRData = new byte[]{ - 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, - 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ - 0x00, 0x00, /* Type */ - 0x00, 0x01, /* Class */ - 0x00, 0x00, 0x01, 0x2b, /* TTL */ - 0x00, 0x04, /* Data length */ - (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 /* Address */}; - final DnsPacket.DnsRecord questionsFromBytes = - new DnsPacket.DnsRecord(DnsPacket.QDSECTION, ByteBuffer.wrap(qdWithTTLRData)); - assertEquals(0, questionsFromBytes.ttl); - assertNull(questionsFromBytes.getRR()); - - // Verify ANSECTION must have rData when constructing. - final byte[] anWithoutTTLRData = new byte[]{ - 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, - 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ - 0x00, 0x01, /* Type */ - 0x00, 0x01, /* Class */}; - assertThrows(BufferUnderflowException.class, () -> - new DnsPacket.DnsRecord(DnsPacket.ANSECTION, ByteBuffer.wrap(anWithoutTTLRData))); - } - - private void assertDnsRecordRoundTrip(DnsPacket.DnsRecord before) - throws IOException { - final DnsPacket.DnsRecord after = new DnsPacket.DnsRecord(before.rType, - ByteBuffer.wrap(before.getBytes())); - assertEquals(after, before); - } - - /** Verifies that the synthesized {@link DnsPacket} can be parsed correctly. */ - @Test - public void testDnsPacketSynthesize() throws IOException { - // Ipv4 dns response packet generated by scapy: - // dns_r = scapy.DNS( - // id=0xbeef, - // qr=1, - // qd=scapy.DNSQR(qname="hello.example.com"), - // an=scapy.DNSRR(rrname="hello.example.com", type="CNAME", rdata='test.com') / - // scapy.DNSRR(rrname="hello.example.com", rdata='1.2.3.4')) - // scapy.hexdump(dns_r) - // dns_r.show2() - // Note that since the synthesizing does not support name compression yet, the domain - // name of the sample need to be uncompressed when generating. - final byte[] v4BlobUncompressed = new byte[]{ - /* Header */ - (byte) 0xbe, (byte) 0xef, /* Transaction ID */ - (byte) 0x81, 0x00, /* Flags */ - 0x00, 0x01, /* Questions */ - 0x00, 0x02, /* Answer RRs */ - 0x00, 0x00, /* Authority RRs */ - 0x00, 0x00, /* Additional RRs */ - /* Queries */ - 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, - 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name: hello.example.com */ - 0x00, 0x01, /* Type */ - 0x00, 0x01, /* Class */ - /* Answers */ - 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, - 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name: hello.example.com */ - 0x00, 0x05, /* Type */ - 0x00, 0x01, /* Class */ - 0x00, 0x00, 0x00, 0x00, /* TTL */ - 0x00, 0x0A, /* Data length */ - 0x04, 0x74, 0x65, 0x73, 0x74, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Alias: test.com */ - 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, - 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name: hello.example.com */ - 0x00, 0x01, /* Type */ - 0x00, 0x01, /* Class */ - 0x00, 0x00, 0x00, 0x00, /* TTL */ - 0x00, 0x04, /* Data length */ - 0x01, 0x02, 0x03, 0x04, /* Address: 1.2.3.4 */ - }; - - // Forge one via constructors. - final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(0xbeef, - 0x8100, 1 /* qcount */, 2 /* ancount */); - final ArrayList qlist = new ArrayList<>(); - final ArrayList alist = new ArrayList<>(); - qlist.add(DnsPacket.DnsRecord.makeQuestion( - "hello.example.com", TYPE_A, CLASS_IN)); - alist.add(DnsPacket.DnsRecord.makeCNameRecord( - DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */, "test.com")); - alist.add(DnsPacket.DnsRecord.makeAOrAAAARecord( - DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */, - InetAddressUtils.parseNumericAddress("1.2.3.4"))); - final TestDnsPacket testPacket = new TestDnsPacket(testHeader, qlist, alist); - - // Assert content equals in both ways. - assertTrue(Arrays.equals(v4BlobUncompressed, testPacket.getBytes())); - assertEquals(new TestDnsPacket(v4BlobUncompressed), testPacket); - } - - @Test - public void testDnsPacketSynthesize_recordCountMismatch() throws IOException { - final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(0xbeef, - 0x8100, 1 /* qcount */, 1 /* ancount */); - final ArrayList qlist = new ArrayList<>(); - final ArrayList alist = new ArrayList<>(); - qlist.add(DnsPacket.DnsRecord.makeQuestion( - "hello.example.com", TYPE_A, CLASS_IN)); - - // Assert throws if the supplied answer records fewer than the declared count. - assertThrows(IllegalArgumentException.class, () -> - new TestDnsPacket(testHeader, qlist, alist)); - - // Assert throws if the supplied answer records more than the declared count. - alist.add(DnsPacket.DnsRecord.makeCNameRecord( - DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */, "test.com")); - alist.add(DnsPacket.DnsRecord.makeAOrAAAARecord( - DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */, - InetAddressUtils.parseNumericAddress("1.2.3.4"))); - assertThrows(IllegalArgumentException.class, () -> - new TestDnsPacket(testHeader, qlist, alist)); - - // Assert counts matched if the byte buffer still has data when parsing ended. - final byte[] blobTooMuchData = new byte[]{ - /* Header */ - (byte) 0xbe, (byte) 0xef, /* Transaction ID */ - (byte) 0x81, 0x00, /* Flags */ - 0x00, 0x00, /* Questions */ - 0x00, 0x00, /* Answer RRs */ - 0x00, 0x00, /* Authority RRs */ - 0x00, 0x00, /* Additional RRs */ - /* Queries */ - 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, - 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name */ - 0x00, 0x01, /* Type */ - 0x00, 0x01, /* Class */ - }; - final TestDnsPacket packetFromTooMuchData = new TestDnsPacket(blobTooMuchData); - for (int i = 0; i < DnsPacket.NUM_SECTIONS; i++) { - assertEquals(0, packetFromTooMuchData.getRecordList(i).size()); - assertEquals(0, packetFromTooMuchData.getHeader().getRecordCount(i)); - } - - // Assert throws if the byte buffer ended when expecting more records. - final byte[] blobNotEnoughData = new byte[]{ - /* Header */ - (byte) 0xbe, (byte) 0xef, /* Transaction ID */ - (byte) 0x81, 0x00, /* Flags */ - 0x00, 0x01, /* Questions */ - 0x00, 0x02, /* Answer RRs */ - 0x00, 0x00, /* Authority RRs */ - 0x00, 0x00, /* Additional RRs */ - /* Queries */ - 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, - 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name */ - 0x00, 0x01, /* Type */ - 0x00, 0x01, /* Class */ - /* Answers */ - 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, - 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name */ - 0x00, 0x01, /* Type */ - 0x00, 0x01, /* Class */ - 0x00, 0x00, 0x00, 0x00, /* TTL */ - 0x00, 0x04, /* Data length */ - 0x01, 0x02, 0x03, 0x04, /* Address */ - }; - assertThrows(DnsPacket.ParseException.class, () -> new TestDnsPacket(blobNotEnoughData)); - } - - @Test - public void testEqualsAndHashCode() throws IOException { - // Verify DnsHeader equals and hashCode. - final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(TEST_DNS_PACKET_ID, - TEST_DNS_PACKET_FLAGS, 1 /* qcount */, 1 /* ancount */); - final DnsPacket.DnsHeader emptyHeader = new DnsPacket.DnsHeader(TEST_DNS_PACKET_ID + 1, - TEST_DNS_PACKET_FLAGS + 0x08, 0 /* qcount */, 0 /* ancount */); - final DnsPacket.DnsHeader headerFromBytes = - new DnsPacket.DnsHeader(ByteBuffer.wrap(testHeader.getBytes())); - assertEquals(testHeader, headerFromBytes); - assertEquals(testHeader.hashCode(), headerFromBytes.hashCode()); - assertNotEquals(testHeader, emptyHeader); - assertNotEquals(testHeader.hashCode(), emptyHeader.hashCode()); - assertNotEquals(headerFromBytes, emptyHeader); - assertNotEquals(headerFromBytes.hashCode(), emptyHeader.hashCode()); - - // Verify DnsRecord equals and hashCode. - final DnsPacket.DnsRecord testQuestion = DnsPacket.DnsRecord.makeQuestion( - "test.com", TYPE_AAAA, CLASS_IN); - final DnsPacket.DnsRecord testAnswer = DnsPacket.DnsRecord.makeCNameRecord( - DnsPacket.ANSECTION, "test.com", CLASS_IN, 9, "www.test.com"); - final DnsPacket.DnsRecord questionFromBytes = new DnsPacket.DnsRecord(DnsPacket.QDSECTION, - ByteBuffer.wrap(testQuestion.getBytes())); - assertEquals(testQuestion, questionFromBytes); - assertEquals(testQuestion.hashCode(), questionFromBytes.hashCode()); - assertNotEquals(testQuestion, testAnswer); - assertNotEquals(testQuestion.hashCode(), testAnswer.hashCode()); - assertNotEquals(questionFromBytes, testAnswer); - assertNotEquals(questionFromBytes.hashCode(), testAnswer.hashCode()); - - // Verify DnsPacket equals and hashCode. - final ArrayList qlist = new ArrayList<>(); - final ArrayList alist = new ArrayList<>(); - qlist.add(testQuestion); - alist.add(testAnswer); - final TestDnsPacket testPacket = new TestDnsPacket(testHeader, qlist, alist); - final TestDnsPacket emptyPacket = new TestDnsPacket( - emptyHeader, new ArrayList<>(), new ArrayList<>()); - final TestDnsPacket packetFromBytes = new TestDnsPacket(testPacket.getBytes()); - assertEquals(testPacket, packetFromBytes); - assertEquals(testPacket.hashCode(), packetFromBytes.hashCode()); - assertNotEquals(testPacket, emptyPacket); - assertNotEquals(testPacket.hashCode(), emptyPacket.hashCode()); - assertNotEquals(packetFromBytes, emptyPacket); - assertNotEquals(packetFromBytes.hashCode(), emptyPacket.hashCode()); - - // Verify DnsPacket with empty list. - final TestDnsPacket emptyPacketFromBytes = new TestDnsPacket(emptyPacket.getBytes()); - assertEquals(emptyPacket, emptyPacketFromBytes); - assertEquals(emptyPacket.hashCode(), emptyPacketFromBytes.hashCode()); - } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java index 9e1ab8249a..48777acc7f 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java @@ -18,20 +18,12 @@ package com.android.net.module.util; import static com.android.net.module.util.DnsPacketUtils.DnsRecordParser; -import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThrows; -import android.net.ParseException; -import android.os.Build; - import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.testutils.DevSdkIgnoreRule; - -import org.junit.Assert; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -40,8 +32,6 @@ import java.nio.ByteBuffer; @RunWith(AndroidJUnit4.class) @SmallTest public class DnsPacketUtilsTest { - @Rule - public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); /** * Verifies that the compressed NAME field in the answer section of the DNS message is parsed @@ -126,31 +116,4 @@ public class DnsPacketUtilsTest { notNameCompressedBuf, /* depth= */ 0, /* isNameCompressionSupported= */ false); assertEquals(domainName, "www.google.com"); } - - // Skip test on R- devices since ParseException only available on S+ devices. - @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) - @Test - public void testDomainNameToLabels() throws Exception { - assertArrayEquals( - new byte[]{3, 'w', 'w', 'w', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm', 0}, - DnsRecordParser.domainNameToLabels("www.google.com")); - assertThrows(ParseException.class, () -> - DnsRecordParser.domainNameToLabels("aaa.")); - assertThrows(ParseException.class, () -> - DnsRecordParser.domainNameToLabels("aaa")); - assertThrows(ParseException.class, () -> - DnsRecordParser.domainNameToLabels(".")); - assertThrows(ParseException.class, () -> - DnsRecordParser.domainNameToLabels("")); - } - - @Test - public void testIsHostName() { - Assert.assertTrue(DnsRecordParser.isHostName("www.google.com")); - Assert.assertFalse(DnsRecordParser.isHostName("com")); - Assert.assertFalse(DnsRecordParser.isHostName("1.2.3.4")); - Assert.assertFalse(DnsRecordParser.isHostName("1234::5678")); - Assert.assertFalse(DnsRecordParser.isHostName(null)); - Assert.assertFalse(DnsRecordParser.isHostName("")); - } } From 8d88f8bb36299c20a2cb09c668c8dc9efb3ac71e Mon Sep 17 00:00:00 2001 From: Nandu Suram Date: Thu, 8 Sep 2022 22:34:47 +0000 Subject: [PATCH 556/777] include ats target fixes: 244138449 include ats target Change-Id: I462b13a5b1332c8afdf46761f1cbad545e7cf291 --- staticlibs/testutils/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index 642544ad87..c9b3d070f8 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -80,6 +80,6 @@ java_test_host { "host/**/*.kt", ], libs: ["tradefed"], - test_suites: ["device-tests", "general-tests", "cts", "mts-networking"], + test_suites: ["ats", "device-tests", "general-tests", "cts", "mts-networking"], data: [":ConnectivityChecker"], } From 1eb37922513f689d60ca3c5b67306291b93fd62a Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Fri, 26 Aug 2022 15:26:40 +0900 Subject: [PATCH 557/777] Add BpfDump#dumpMapStatus Test: atest NetworkStaticLibTests Change-Id: I77d397b16380a397573cc528fe7f15f381cda21f --- .../com/android/net/module/util/BpfDump.java | 20 +++++++++ .../android/net/module/util/BpfDumpTest.java | 42 +++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/BpfDump.java b/staticlibs/device/com/android/net/module/util/BpfDump.java index 2534d61612..7549e71230 100644 --- a/staticlibs/device/com/android/net/module/util/BpfDump.java +++ b/staticlibs/device/com/android/net/module/util/BpfDump.java @@ -15,6 +15,8 @@ */ package com.android.net.module.util; +import static android.system.OsConstants.R_OK; + import android.system.ErrnoException; import android.system.Os; import android.util.Base64; @@ -110,6 +112,24 @@ public class BpfDump { } } + /** + * Dump the BpfMap status + */ + public static void dumpMapStatus(IBpfMap map, + PrintWriter pw, String mapName, String path) { + if (map != null) { + pw.println(mapName + ": OK"); + return; + } + try { + Os.access(path, R_OK); + pw.println(mapName + ": NULL(map is pinned to " + path + ")"); + } catch (ErrnoException e) { + pw.println(mapName + ": NULL(map is not pinned to " + path + ": " + + Os.strerror(e.errno) + ")"); + } + } + // TODO: add a helper to dump bpf map content with the map name, the header line // (ex: "BPF ingress map: iif nat64Prefix v6Addr -> v4Addr oif"), a lambda that // knows how to dump each line, and the PrintWriter. diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java index 3932925874..4e483322d1 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java @@ -16,10 +16,19 @@ package com.android.net.module.util; +import static android.system.OsConstants.EPERM; +import static android.system.OsConstants.R_OK; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; +import android.system.ErrnoException; +import android.system.Os; import android.util.Pair; import androidx.test.filters.SmallTest; @@ -29,6 +38,7 @@ import com.android.testutils.TestBpfMap; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.MockitoSession; import java.io.PrintWriter; import java.io.StringWriter; @@ -118,4 +128,36 @@ public class BpfDumpTest { assertTrue(dump.contains("key=123, val=456")); assertTrue(dump.contains("key=789, val=123")); } + + private String getDumpMapStatus(final IBpfMap map) { + final StringWriter sw = new StringWriter(); + BpfDump.dumpMapStatus(map, new PrintWriter(sw), "mapName", "mapPath"); + return sw.toString(); + } + + @Test + public void testGetMapStatus() { + final IBpfMap map = + new TestBpfMap<>(Struct.U32.class, Struct.U32.class); + assertEquals("mapName: OK\n", getDumpMapStatus(map)); + } + + @Test + public void testGetMapStatusNull() { + final MockitoSession session = mockitoSession() + .spyStatic(Os.class) + .startMocking(); + try { + // Os.access succeeds + doReturn(true).when(() -> Os.access("mapPath", R_OK)); + assertEquals("mapName: NULL(map is pinned to mapPath)\n", getDumpMapStatus(null)); + + // Os.access throws EPERM + doThrow(new ErrnoException("", EPERM)).when(() -> Os.access("mapPath", R_OK)); + assertEquals("mapName: NULL(map is not pinned to mapPath: Operation not permitted)\n", + getDumpMapStatus(null)); + } finally { + session.finishMocking(); + } + } } From 1bff3fb28fbff30ad48acda3f70998b47120a4c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 16 Sep 2022 05:03:53 +0000 Subject: [PATCH 558/777] NetlinkSocketTest.java - replace U32 ifindex with S32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are allocated in order by the kernel, if we go over 2 billion, we've got other problems... besides U32 to S32 conversion will work just fine anyway. (apparently this field is never accessed, as the test only looks at family) Bug: 245472520 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I879c1637a87587b7bc1c13013ea9c5e655c141eb --- .../android/net/module/util/netlink/NetlinkSocketTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkSocketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkSocketTest.java index 33ea602312..f4073b6dc0 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkSocketTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkSocketTest.java @@ -236,7 +236,7 @@ public class NetlinkSocketTest { @Field(order = 3, type = Type.U8) public short scope; - @Field(order = 4, type = Type.U32) - public long index; + @Field(order = 4, type = Type.S32) + public int index; } } From 85e24e85b23943c998e6fab3bf6e0f78dff18a3d Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 15 Sep 2022 07:34:51 +0000 Subject: [PATCH 559/777] [ST02] Add methods for synthesizing DNS packets This re-submit aosp/1387135 but define TYPE_CNAME locally to prevent from using non-finalize API. Bug: 139774492 Test: atest NetworkStaticLibTests:com.android.net.moduletests.util.DnsPacketUtilsTest Change-Id: Ib2e98292be994ca09845c6857b8884f9bcdaba80 --- staticlibs/Android.bp | 5 +- .../android/net/module/util/DnsPacket.java | 412 +++++++++++++++++- .../net/module/util/DnsPacketUtils.java | 59 ++- .../net/module/util/DnsPacketTest.java | 273 +++++++++++- .../net/module/util/DnsPacketUtilsTest.java | 37 ++ 5 files changed, 760 insertions(+), 26 deletions(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 4dfc752bb5..f4997a1691 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -96,7 +96,10 @@ java_library { visibility: [ "//packages/services/Iwlan:__subpackages__", ], - libs: ["framework-annotations-lib"], + libs: [ + "framework-annotations-lib", + "framework-connectivity.stubs.module_lib", + ], } filegroup { diff --git a/staticlibs/framework/com/android/net/module/util/DnsPacket.java b/staticlibs/framework/com/android/net/module/util/DnsPacket.java index 080781c1ff..702d114e00 100644 --- a/staticlibs/framework/com/android/net/module/util/DnsPacket.java +++ b/staticlibs/framework/com/android/net/module/util/DnsPacket.java @@ -16,15 +16,34 @@ package com.android.net.module.util; +import static android.net.DnsResolver.TYPE_A; +import static android.net.DnsResolver.TYPE_AAAA; + +import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; +import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; +import static com.android.net.module.util.DnsPacketUtils.DnsRecordParser.domainNameToLabels; + +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.text.TextUtils; +import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.DnsPacketUtils.DnsRecordParser; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.net.InetAddress; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Objects; /** * Defines basic data for DNS protocol based on RFC 1035. @@ -33,6 +52,12 @@ import java.util.List; * @hide */ public abstract class DnsPacket { + /** + * Type of the canonical name for an alias. Refer to RFC 1035 section 3.2.2. + */ + // TODO: Define the constant as a public constant in DnsResolver since it can never change. + private static final int TYPE_CNAME = 5; + /** * Thrown when parsing packet failed. */ @@ -50,13 +75,29 @@ public abstract class DnsPacket { } /** - * DNS header for DNS protocol based on RFC 1035. + * DNS header for DNS protocol based on RFC 1035 section 4.1.1. + * + * 1 1 1 1 1 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | ID | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * |QR| Opcode |AA|TC|RD|RA| Z | RCODE | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | QDCOUNT | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | ANCOUNT | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | NSCOUNT | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | ARCOUNT | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ */ - public class DnsHeader { + public static class DnsHeader { private static final String TAG = "DnsHeader"; - public final int id; - public final int flags; - public final int rcode; + private static final int SIZE_IN_BYTES = 12; + private final int mId; + private final int mFlags; private final int[] mRecordCount; /* If this bit in the 'flags' field is set to 0, the DNS message corresponding to this @@ -73,10 +114,11 @@ public abstract class DnsPacket { * advanced to the end of the DNS header record. * This is meant to chain with other methods reading a DNS response in sequence. */ - DnsHeader(@NonNull ByteBuffer buf) throws BufferUnderflowException { - id = Short.toUnsignedInt(buf.getShort()); - flags = Short.toUnsignedInt(buf.getShort()); - rcode = flags & 0xF; + @VisibleForTesting + public DnsHeader(@NonNull ByteBuffer buf) throws BufferUnderflowException { + Objects.requireNonNull(buf); + mId = Short.toUnsignedInt(buf.getShort()); + mFlags = Short.toUnsignedInt(buf.getShort()); mRecordCount = new int[NUM_SECTIONS]; for (int i = 0; i < NUM_SECTIONS; ++i) { mRecordCount[i] = Short.toUnsignedInt(buf.getShort()); @@ -88,7 +130,23 @@ public abstract class DnsPacket { * RFC 1035 Section 4.1.1. */ public boolean isResponse() { - return (flags & (1 << FLAGS_SECTION_QR_BIT)) != 0; + return (mFlags & (1 << FLAGS_SECTION_QR_BIT)) != 0; + } + + /** + * Create a new DnsHeader from specified parameters. + * + * This constructor only builds the question and answer sections. Authority + * and additional sections are not supported. Useful when synthesizing dns + * responses from query or reply packets. + */ + @VisibleForTesting + public DnsHeader(int id, int flags, int qdcount, int ancount) { + this.mId = id; + this.mFlags = flags; + mRecordCount = new int[NUM_SECTIONS]; + mRecordCount[QDSECTION] = qdcount; + mRecordCount[ANSECTION] = ancount; } /** @@ -97,15 +155,103 @@ public abstract class DnsPacket { public int getRecordCount(int type) { return mRecordCount[type]; } + + /** + * Get flags of this instance. + */ + public int getFlags() { + return mFlags; + } + + /** + * Get id of this instance. + */ + public int getId() { + return mId; + } + + @Override + public String toString() { + return "DnsHeader{" + "id=" + mId + ", flags=" + mFlags + + ", recordCounts=" + Arrays.toString(mRecordCount) + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o.getClass() != getClass()) return false; + final DnsHeader other = (DnsHeader) o; + return mId == other.mId + && mFlags == other.mFlags + && Arrays.equals(mRecordCount, other.mRecordCount); + } + + @Override + public int hashCode() { + return 31 * mId + 37 * mFlags + Arrays.hashCode(mRecordCount); + } + + /** + * Get DnsHeader as byte array. + */ + @NonNull + public byte[] getBytes() { + // TODO: if this is called often, optimize the ByteBuffer out and write to the + // array directly. + final ByteBuffer buf = ByteBuffer.allocate(SIZE_IN_BYTES); + buf.putShort((short) mId); + buf.putShort((short) mFlags); + for (int i = 0; i < NUM_SECTIONS; ++i) { + buf.putShort((short) mRecordCount[i]); + } + return buf.array(); + } } /** * Superclass for DNS questions and DNS resource records. * - * DNS questions (No TTL/RDATA) - * DNS resource records (With TTL/RDATA) + * DNS questions (No TTL/RDLENGTH/RDATA) based on RFC 1035 section 4.1.2. + * 1 1 1 1 1 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | | + * / QNAME / + * / / + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | QTYPE | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | QCLASS | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * + * DNS resource records (With TTL/RDLENGTH/RDATA) based on RFC 1035 section 4.1.3. + * 1 1 1 1 1 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | | + * / / + * / NAME / + * | | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | TYPE | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | CLASS | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | TTL | + * | | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * | RDLENGTH | + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + * / RDATA / + * / / + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ */ - public class DnsRecord { + // TODO: Make DnsResourceRecord and DnsQuestion subclasses of DnsRecord, and construct + // corresponding object from factory methods. + public static class DnsRecord { + // Refer to RFC 1035 section 2.3.4 for MAXNAMESIZE. + // NAME_NORMAL and NAME_COMPRESSION are used for checking name compression, + // refer to rfc 1035 section 4.1.4. private static final int MAXNAMESIZE = 255; public static final int NAME_NORMAL = 0; public static final int NAME_COMPRESSION = 0xC0; @@ -117,22 +263,31 @@ public abstract class DnsPacket { public final int nsClass; public final long ttl; private final byte[] mRdata; + /** + * Type of this DNS record. + */ + @RecordType + public final int rType; /** * Create a new DnsRecord from a positioned ByteBuffer. * * Reads the passed ByteBuffer from its current position and decodes a DNS record. * When this constructor returns, the reading position of the ByteBuffer has been - * advanced to the end of the DNS header record. + * advanced to the end of the DNS resource record. * This is meant to chain with other methods reading a DNS response in sequence. * + * @param rType Type of the record. * @param buf ByteBuffer input of record, must be in network byte order * (which is the default). */ - DnsRecord(int recordType, @NonNull ByteBuffer buf) + @VisibleForTesting(visibility = PACKAGE) + public DnsRecord(@RecordType int rType, @NonNull ByteBuffer buf) throws BufferUnderflowException, ParseException { + Objects.requireNonNull(buf); + this.rType = rType; dName = DnsRecordParser.parseName(buf, 0 /* Parse depth */, - /* isNameCompressionSupported= */ true); + true /* isNameCompressionSupported */); if (dName.length() > MAXNAMESIZE) { throw new ParseException( "Parse name fail, name size is too long: " + dName.length()); @@ -140,7 +295,7 @@ public abstract class DnsPacket { nsType = Short.toUnsignedInt(buf.getShort()); nsClass = Short.toUnsignedInt(buf.getShort()); - if (recordType != QDSECTION) { + if (rType != QDSECTION) { ttl = Integer.toUnsignedLong(buf.getInt()); final int length = Short.toUnsignedInt(buf.getShort()); mRdata = new byte[length]; @@ -151,6 +306,95 @@ public abstract class DnsPacket { } } + /** + * Make an A or AAAA record based on the specified parameters. + * + * @param rType Type of the record, can be {@link #ANSECTION}, {@link #ARSECTION} + * or {@link #NSSECTION}. + * @param dName Domain name of the record. + * @param nsClass Class of the record. See RFC 1035 section 3.2.4. + * @param ttl time interval (in seconds) that the resource record may be + * cached before it should be discarded. Zero values are + * interpreted to mean that the RR can only be used for the + * transaction in progress, and should not be cached. + * @param address Instance of {@link InetAddress} + * @return A record if the {@code address} is an IPv4 address, or AAAA record if the + * {@code address} is an IPv6 address. + */ + public static DnsRecord makeAOrAAAARecord(int rType, @NonNull String dName, + int nsClass, long ttl, @NonNull InetAddress address) throws IOException { + final int nsType = (address.getAddress().length == 4) ? TYPE_A : TYPE_AAAA; + return new DnsRecord(rType, dName, nsType, nsClass, ttl, address, null /* rDataStr */); + } + + /** + * Make an CNAME record based on the specified parameters. + * + * @param rType Type of the record, can be {@link #ANSECTION}, {@link #ARSECTION} + * or {@link #NSSECTION}. + * @param dName Domain name of the record. + * @param nsClass Class of the record. See RFC 1035 section 3.2.4. + * @param ttl time interval (in seconds) that the resource record may be + * cached before it should be discarded. Zero values are + * interpreted to mean that the RR can only be used for the + * transaction in progress, and should not be cached. + * @param domainName Canonical name of the {@code dName}. + * @return A record if the {@code address} is an IPv4 address, or AAAA record if the + * {@code address} is an IPv6 address. + */ + public static DnsRecord makeCNameRecord(int rType, @NonNull String dName, int nsClass, + long ttl, @NonNull String domainName) throws IOException { + return new DnsRecord(rType, dName, TYPE_CNAME, nsClass, ttl, null /* address */, + domainName); + } + + /** + * Make a DNS question based on the specified parameters. + */ + public static DnsRecord makeQuestion(@NonNull String dName, int nsType, int nsClass) { + return new DnsRecord(dName, nsType, nsClass); + } + + private static String requireHostName(@NonNull String name) { + if (!DnsRecordParser.isHostName(name)) { + throw new IllegalArgumentException("Expected domain name but got " + name); + } + return name; + } + + /** + * Create a new query DnsRecord from specified parameters, useful when synthesizing + * dns response. + */ + private DnsRecord(@NonNull String dName, int nsType, int nsClass) { + this.rType = QDSECTION; + this.dName = requireHostName(dName); + this.nsType = nsType; + this.nsClass = nsClass; + mRdata = null; + this.ttl = 0; + } + + /** + * Create a new CNAME/A/AAAA DnsRecord from specified parameters. + * + * @param address The address only used when synthesizing A or AAAA record. + * @param rDataStr The alias of the domain, only used when synthesizing CNAME record. + */ + private DnsRecord(@RecordType int rType, @NonNull String dName, int nsType, int nsClass, + long ttl, @Nullable InetAddress address, @Nullable String rDataStr) + throws IOException { + this.rType = rType; + this.dName = requireHostName(dName); + this.nsType = nsType; + this.nsClass = nsClass; + if (rType < 0 || rType >= NUM_SECTIONS || rType == QDSECTION) { + throw new IllegalArgumentException("Unexpected record type: " + rType); + } + mRdata = nsType == TYPE_CNAME ? domainNameToLabels(rDataStr) : address.getAddress(); + this.ttl = ttl; + } + /** * Get a copy of rdata. */ @@ -159,13 +403,84 @@ public abstract class DnsPacket { return (mRdata == null) ? null : mRdata.clone(); } + /** + * Get DnsRecord as byte array. + */ + @NonNull + public byte[] getBytes() throws IOException { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final DataOutputStream dos = new DataOutputStream(baos); + dos.write(domainNameToLabels(dName)); + dos.writeShort(nsType); + dos.writeShort(nsClass); + if (rType != QDSECTION) { + dos.writeInt((int) ttl); + if (mRdata == null) { + dos.writeShort(0); + } else { + dos.writeShort(mRdata.length); + dos.write(mRdata); + } + } + return baos.toByteArray(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o.getClass() != getClass()) return false; + final DnsRecord other = (DnsRecord) o; + return rType == other.rType + && nsType == other.nsType + && nsClass == other.nsClass + && ttl == other.ttl + && TextUtils.equals(dName, other.dName) + && Arrays.equals(mRdata, other.mRdata); + } + + @Override + public int hashCode() { + return 31 * Objects.hash(dName) + + 37 * ((int) (ttl & 0xFFFFFFFF)) + + 41 * ((int) (ttl >> 32)) + + 43 * nsType + + 47 * nsClass + + 53 * rType + + Arrays.hashCode(mRdata); + } + + @Override + public String toString() { + return "DnsRecord{" + + "rType=" + rType + + ", dName='" + dName + '\'' + + ", nsType=" + nsType + + ", nsClass=" + nsClass + + ", ttl=" + ttl + + ", mRdata=" + Arrays.toString(mRdata) + + '}'; + } } + /** + * Header section types, refer to RFC 1035 section 4.1.1. + */ public static final int QDSECTION = 0; public static final int ANSECTION = 1; public static final int NSSECTION = 2; public static final int ARSECTION = 3; - private static final int NUM_SECTIONS = ARSECTION + 1; + @VisibleForTesting(visibility = PRIVATE) + static final int NUM_SECTIONS = ARSECTION + 1; + + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + QDSECTION, + ANSECTION, + NSSECTION, + ARSECTION, + }) + public @interface RecordType {} + private static final String TAG = DnsPacket.class.getSimpleName(); @@ -189,9 +504,7 @@ public abstract class DnsPacket { for (int i = 0; i < NUM_SECTIONS; ++i) { final int count = mHeader.getRecordCount(i); - if (count > 0) { - mRecords[i] = new ArrayList(count); - } + mRecords[i] = new ArrayList(count); for (int j = 0; j < count; ++j) { try { mRecords[i].add(new DnsRecord(i, buffer)); @@ -201,4 +514,61 @@ public abstract class DnsPacket { } } } + + /** + * Create a new {@link #DnsPacket} from specified parameters. + * + * Note that authority records section and additional records section is not supported. + */ + protected DnsPacket(@NonNull DnsHeader header, @NonNull List qd, + @NonNull List an) { + mHeader = Objects.requireNonNull(header); + mRecords = new List[NUM_SECTIONS]; + mRecords[QDSECTION] = Collections.unmodifiableList(new ArrayList<>(qd)); + mRecords[ANSECTION] = Collections.unmodifiableList(new ArrayList<>(an)); + mRecords[NSSECTION] = new ArrayList<>(); + mRecords[ARSECTION] = new ArrayList<>(); + for (int i = 0; i < NUM_SECTIONS; i++) { + if (mHeader.mRecordCount[i] != mRecords[i].size()) { + throw new IllegalArgumentException("Record count mismatch: expected " + + mHeader.mRecordCount[i] + " but was " + mRecords[i]); + } + } + } + + /** + * Get DnsPacket as byte array. + */ + public @NonNull byte[] getBytes() throws IOException { + final ByteArrayOutputStream buf = new ByteArrayOutputStream(); + buf.write(mHeader.getBytes()); + + for (int i = 0; i < NUM_SECTIONS; ++i) { + for (final DnsRecord record : mRecords[i]) { + buf.write(record.getBytes()); + } + } + return buf.toByteArray(); + } + + @Override + public String toString() { + return "DnsPacket{" + "header=" + mHeader + ", records='" + Arrays.toString(mRecords) + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o.getClass() != getClass()) return false; + final DnsPacket other = (DnsPacket) o; + return Objects.equals(mHeader, other.mHeader) + && Arrays.deepEquals(mRecords, other.mRecords); + } + + @Override + public int hashCode() { + int result = Objects.hash(mHeader); + result = 31 * result + Arrays.hashCode(mRecords); + return result; + } } diff --git a/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java b/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java index 3448cadf6f..c47bfa0746 100644 --- a/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java +++ b/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java @@ -20,10 +20,19 @@ import static com.android.net.module.util.DnsPacket.DnsRecord.NAME_COMPRESSION; import static com.android.net.module.util.DnsPacket.DnsRecord.NAME_NORMAL; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.InetAddresses; +import android.net.ParseException; import android.text.TextUtils; +import android.util.Patterns; +import com.android.internal.annotations.VisibleForTesting; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.text.DecimalFormat; import java.text.FieldPosition; @@ -38,6 +47,7 @@ public final class DnsPacketUtils { */ public static class DnsRecordParser { private static final int MAXLABELSIZE = 63; + private static final int MAXNAMESIZE = 255; private static final int MAXLABELCOUNT = 128; private static final DecimalFormat sByteFormat = new DecimalFormat(); @@ -48,7 +58,8 @@ public final class DnsPacketUtils { * *

Follows the same conversion rules of the native code (ns_name.c in libc). */ - private static String labelToString(@NonNull byte[] label) { + @VisibleForTesting + static String labelToString(@NonNull byte[] label) { final StringBuffer sb = new StringBuffer(); for (int i = 0; i < label.length; ++i) { @@ -71,6 +82,52 @@ public final class DnsPacketUtils { return sb.toString(); } + /** + * Converts domain name to labels according to RFC 1035. + * + * @param name Domain name as String that needs to be converted to labels. + * @return An encoded byte array that is constructed out of labels, + * and ends with zero-length label. + * @throws ParseException if failed to parse the given domain name or + * IOException if failed to output labels. + */ + public static @NonNull byte[] domainNameToLabels(@NonNull String name) throws + IOException, ParseException { + if (name.length() > MAXNAMESIZE) { + throw new ParseException("Domain name exceeds max length: " + name.length()); + } + if (!isHostName(name)) { + throw new ParseException("Failed to parse domain name: " + name); + } + final ByteArrayOutputStream buf = new ByteArrayOutputStream(); + final String[] labels = name.split("\\."); + for (final String label : labels) { + if (label.length() > MAXLABELSIZE) { + throw new ParseException("label is too long: " + label); + } + buf.write(label.length()); + // Encode as UTF-8 as suggested in RFC 6055 section 3. + buf.write(label.getBytes(StandardCharsets.UTF_8)); + } + buf.write(0x00); // end with zero-length label + return buf.toByteArray(); + } + + /** + * Check whether the input is a valid hostname based on rfc 1035 section 3.3. + * + * @param hostName the target host name. + * @return true if the input is a valid hostname. + */ + public static boolean isHostName(@Nullable String hostName) { + // TODO: Use {@code Patterns.HOST_NAME} if available. + // Patterns.DOMAIN_NAME accepts host names or IP addresses, so reject + // IP addresses. + return hostName != null + && Patterns.DOMAIN_NAME.matcher(hostName).matches() + && !InetAddresses.isNumericAddress(hostName); + } + /** * Parses the domain / target name of a DNS record. * diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java index 1bbba08804..409c1ebb77 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java @@ -16,26 +16,45 @@ package com.android.net.module.util; +import static android.net.DnsResolver.CLASS_IN; +import static android.net.DnsResolver.TYPE_A; +import static android.net.DnsResolver.TYPE_AAAA; + import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.annotation.NonNull; +import android.annotation.Nullable; + import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import libcore.net.InetAddressUtils; + import org.junit.Test; import org.junit.runner.RunWith; +import java.io.IOException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @RunWith(AndroidJUnit4.class) @SmallTest public class DnsPacketTest { + private static final int TEST_DNS_PACKET_ID = 0x7722; + private static final int TEST_DNS_PACKET_FLAGS = 0x8180; + private void assertHeaderParses(DnsPacket.DnsHeader header, int id, int flag, int qCount, int aCount, int nsCount, int arCount) { - assertEquals(header.id, id); - assertEquals(header.flags, flag); + assertEquals(header.getId(), id); + assertEquals(header.getFlags(), flag); assertEquals(header.getRecordCount(DnsPacket.QDSECTION), qCount); assertEquals(header.getRecordCount(DnsPacket.ANSECTION), aCount); assertEquals(header.getRecordCount(DnsPacket.NSSECTION), nsCount); @@ -51,11 +70,16 @@ public class DnsPacketTest { assertTrue(Arrays.equals(record.getRR(), rr)); } - class TestDnsPacket extends DnsPacket { + static class TestDnsPacket extends DnsPacket { TestDnsPacket(byte[] data) throws DnsPacket.ParseException { super(data); } + TestDnsPacket(@NonNull DnsHeader header, @Nullable ArrayList qd, + @Nullable ArrayList an) { + super(header, qd, an); + } + public DnsHeader getHeader() { return mHeader; } @@ -156,4 +180,247 @@ public class DnsPacketTest { new byte[]{ 0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 }); } + + /** Verifies that the synthesized {@link DnsPacket.DnsHeader} can be parsed correctly. */ + @Test + public void testDnsHeaderSynthesize() { + final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(TEST_DNS_PACKET_ID, + TEST_DNS_PACKET_FLAGS, 3 /* qcount */, 5 /* ancount */); + final DnsPacket.DnsHeader actualHeader = new DnsPacket.DnsHeader( + ByteBuffer.wrap(testHeader.getBytes())); + assertEquals(testHeader, actualHeader); + } + + /** Verifies that the synthesized {@link DnsPacket.DnsRecord} can be parsed correctly. */ + @Test + public void testDnsRecordSynthesize() throws IOException { + assertDnsRecordRoundTrip( + DnsPacket.DnsRecord.makeAOrAAAARecord(DnsPacket.ANSECTION, + "test.com", CLASS_IN, 5 /* ttl */, + InetAddressUtils.parseNumericAddress("abcd::fedc"))); + assertDnsRecordRoundTrip(DnsPacket.DnsRecord.makeQuestion("test.com", TYPE_AAAA, CLASS_IN)); + assertDnsRecordRoundTrip(DnsPacket.DnsRecord.makeCNameRecord(DnsPacket.ANSECTION, + "test.com", CLASS_IN, 0 /* ttl */, "example.com")); + } + + /** + * Verifies ttl/rData error handling when parsing + * {@link DnsPacket.DnsRecord} from bytes. + */ + @Test + public void testDnsRecordTTLRDataErrorHandling() throws IOException { + // Verify the constructor ignore ttl/rData of questions even if they are supplied. + final byte[] qdWithTTLRData = new byte[]{ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x00, /* Type */ + 0x00, 0x01, /* Class */ + 0x00, 0x00, 0x01, 0x2b, /* TTL */ + 0x00, 0x04, /* Data length */ + (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 /* Address */}; + final DnsPacket.DnsRecord questionsFromBytes = + new DnsPacket.DnsRecord(DnsPacket.QDSECTION, ByteBuffer.wrap(qdWithTTLRData)); + assertEquals(0, questionsFromBytes.ttl); + assertNull(questionsFromBytes.getRR()); + + // Verify ANSECTION must have rData when constructing. + final byte[] anWithoutTTLRData = new byte[]{ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */}; + assertThrows(BufferUnderflowException.class, () -> + new DnsPacket.DnsRecord(DnsPacket.ANSECTION, ByteBuffer.wrap(anWithoutTTLRData))); + } + + private void assertDnsRecordRoundTrip(DnsPacket.DnsRecord before) + throws IOException { + final DnsPacket.DnsRecord after = new DnsPacket.DnsRecord(before.rType, + ByteBuffer.wrap(before.getBytes())); + assertEquals(after, before); + } + + /** Verifies that the synthesized {@link DnsPacket} can be parsed correctly. */ + @Test + public void testDnsPacketSynthesize() throws IOException { + // Ipv4 dns response packet generated by scapy: + // dns_r = scapy.DNS( + // id=0xbeef, + // qr=1, + // qd=scapy.DNSQR(qname="hello.example.com"), + // an=scapy.DNSRR(rrname="hello.example.com", type="CNAME", rdata='test.com') / + // scapy.DNSRR(rrname="hello.example.com", rdata='1.2.3.4')) + // scapy.hexdump(dns_r) + // dns_r.show2() + // Note that since the synthesizing does not support name compression yet, the domain + // name of the sample need to be uncompressed when generating. + final byte[] v4BlobUncompressed = new byte[]{ + /* Header */ + (byte) 0xbe, (byte) 0xef, /* Transaction ID */ + (byte) 0x81, 0x00, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x02, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, + 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name: hello.example.com */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + /* Answers */ + 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, + 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name: hello.example.com */ + 0x00, 0x05, /* Type */ + 0x00, 0x01, /* Class */ + 0x00, 0x00, 0x00, 0x00, /* TTL */ + 0x00, 0x0A, /* Data length */ + 0x04, 0x74, 0x65, 0x73, 0x74, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Alias: test.com */ + 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, + 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name: hello.example.com */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + 0x00, 0x00, 0x00, 0x00, /* TTL */ + 0x00, 0x04, /* Data length */ + 0x01, 0x02, 0x03, 0x04, /* Address: 1.2.3.4 */ + }; + + // Forge one via constructors. + final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(0xbeef, + 0x8100, 1 /* qcount */, 2 /* ancount */); + final ArrayList qlist = new ArrayList<>(); + final ArrayList alist = new ArrayList<>(); + qlist.add(DnsPacket.DnsRecord.makeQuestion( + "hello.example.com", TYPE_A, CLASS_IN)); + alist.add(DnsPacket.DnsRecord.makeCNameRecord( + DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */, "test.com")); + alist.add(DnsPacket.DnsRecord.makeAOrAAAARecord( + DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */, + InetAddressUtils.parseNumericAddress("1.2.3.4"))); + final TestDnsPacket testPacket = new TestDnsPacket(testHeader, qlist, alist); + + // Assert content equals in both ways. + assertTrue(Arrays.equals(v4BlobUncompressed, testPacket.getBytes())); + assertEquals(new TestDnsPacket(v4BlobUncompressed), testPacket); + } + + @Test + public void testDnsPacketSynthesize_recordCountMismatch() throws IOException { + final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(0xbeef, + 0x8100, 1 /* qcount */, 1 /* ancount */); + final ArrayList qlist = new ArrayList<>(); + final ArrayList alist = new ArrayList<>(); + qlist.add(DnsPacket.DnsRecord.makeQuestion( + "hello.example.com", TYPE_A, CLASS_IN)); + + // Assert throws if the supplied answer records fewer than the declared count. + assertThrows(IllegalArgumentException.class, () -> + new TestDnsPacket(testHeader, qlist, alist)); + + // Assert throws if the supplied answer records more than the declared count. + alist.add(DnsPacket.DnsRecord.makeCNameRecord( + DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */, "test.com")); + alist.add(DnsPacket.DnsRecord.makeAOrAAAARecord( + DnsPacket.ANSECTION, "hello.example.com", CLASS_IN, 0 /* ttl */, + InetAddressUtils.parseNumericAddress("1.2.3.4"))); + assertThrows(IllegalArgumentException.class, () -> + new TestDnsPacket(testHeader, qlist, alist)); + + // Assert counts matched if the byte buffer still has data when parsing ended. + final byte[] blobTooMuchData = new byte[]{ + /* Header */ + (byte) 0xbe, (byte) 0xef, /* Transaction ID */ + (byte) 0x81, 0x00, /* Flags */ + 0x00, 0x00, /* Questions */ + 0x00, 0x00, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, + 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + }; + final TestDnsPacket packetFromTooMuchData = new TestDnsPacket(blobTooMuchData); + for (int i = 0; i < DnsPacket.NUM_SECTIONS; i++) { + assertEquals(0, packetFromTooMuchData.getRecordList(i).size()); + assertEquals(0, packetFromTooMuchData.getHeader().getRecordCount(i)); + } + + // Assert throws if the byte buffer ended when expecting more records. + final byte[] blobNotEnoughData = new byte[]{ + /* Header */ + (byte) 0xbe, (byte) 0xef, /* Transaction ID */ + (byte) 0x81, 0x00, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x02, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, + 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + /* Answers */ + 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x07, 0x65, 0x78, 0x61, + 0x6D, 0x70, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01, /* Class */ + 0x00, 0x00, 0x00, 0x00, /* TTL */ + 0x00, 0x04, /* Data length */ + 0x01, 0x02, 0x03, 0x04, /* Address */ + }; + assertThrows(DnsPacket.ParseException.class, () -> new TestDnsPacket(blobNotEnoughData)); + } + + @Test + public void testEqualsAndHashCode() throws IOException { + // Verify DnsHeader equals and hashCode. + final DnsPacket.DnsHeader testHeader = new DnsPacket.DnsHeader(TEST_DNS_PACKET_ID, + TEST_DNS_PACKET_FLAGS, 1 /* qcount */, 1 /* ancount */); + final DnsPacket.DnsHeader emptyHeader = new DnsPacket.DnsHeader(TEST_DNS_PACKET_ID + 1, + TEST_DNS_PACKET_FLAGS + 0x08, 0 /* qcount */, 0 /* ancount */); + final DnsPacket.DnsHeader headerFromBytes = + new DnsPacket.DnsHeader(ByteBuffer.wrap(testHeader.getBytes())); + assertEquals(testHeader, headerFromBytes); + assertEquals(testHeader.hashCode(), headerFromBytes.hashCode()); + assertNotEquals(testHeader, emptyHeader); + assertNotEquals(testHeader.hashCode(), emptyHeader.hashCode()); + assertNotEquals(headerFromBytes, emptyHeader); + assertNotEquals(headerFromBytes.hashCode(), emptyHeader.hashCode()); + + // Verify DnsRecord equals and hashCode. + final DnsPacket.DnsRecord testQuestion = DnsPacket.DnsRecord.makeQuestion( + "test.com", TYPE_AAAA, CLASS_IN); + final DnsPacket.DnsRecord testAnswer = DnsPacket.DnsRecord.makeCNameRecord( + DnsPacket.ANSECTION, "test.com", CLASS_IN, 9, "www.test.com"); + final DnsPacket.DnsRecord questionFromBytes = new DnsPacket.DnsRecord(DnsPacket.QDSECTION, + ByteBuffer.wrap(testQuestion.getBytes())); + assertEquals(testQuestion, questionFromBytes); + assertEquals(testQuestion.hashCode(), questionFromBytes.hashCode()); + assertNotEquals(testQuestion, testAnswer); + assertNotEquals(testQuestion.hashCode(), testAnswer.hashCode()); + assertNotEquals(questionFromBytes, testAnswer); + assertNotEquals(questionFromBytes.hashCode(), testAnswer.hashCode()); + + // Verify DnsPacket equals and hashCode. + final ArrayList qlist = new ArrayList<>(); + final ArrayList alist = new ArrayList<>(); + qlist.add(testQuestion); + alist.add(testAnswer); + final TestDnsPacket testPacket = new TestDnsPacket(testHeader, qlist, alist); + final TestDnsPacket emptyPacket = new TestDnsPacket( + emptyHeader, new ArrayList<>(), new ArrayList<>()); + final TestDnsPacket packetFromBytes = new TestDnsPacket(testPacket.getBytes()); + assertEquals(testPacket, packetFromBytes); + assertEquals(testPacket.hashCode(), packetFromBytes.hashCode()); + assertNotEquals(testPacket, emptyPacket); + assertNotEquals(testPacket.hashCode(), emptyPacket.hashCode()); + assertNotEquals(packetFromBytes, emptyPacket); + assertNotEquals(packetFromBytes.hashCode(), emptyPacket.hashCode()); + + // Verify DnsPacket with empty list. + final TestDnsPacket emptyPacketFromBytes = new TestDnsPacket(emptyPacket.getBytes()); + assertEquals(emptyPacket, emptyPacketFromBytes); + assertEquals(emptyPacket.hashCode(), emptyPacketFromBytes.hashCode()); + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java index 48777acc7f..9e1ab8249a 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketUtilsTest.java @@ -18,12 +18,20 @@ package com.android.net.module.util; import static com.android.net.module.util.DnsPacketUtils.DnsRecordParser; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThrows; +import android.net.ParseException; +import android.os.Build; + import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.testutils.DevSdkIgnoreRule; + +import org.junit.Assert; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -32,6 +40,8 @@ import java.nio.ByteBuffer; @RunWith(AndroidJUnit4.class) @SmallTest public class DnsPacketUtilsTest { + @Rule + public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); /** * Verifies that the compressed NAME field in the answer section of the DNS message is parsed @@ -116,4 +126,31 @@ public class DnsPacketUtilsTest { notNameCompressedBuf, /* depth= */ 0, /* isNameCompressionSupported= */ false); assertEquals(domainName, "www.google.com"); } + + // Skip test on R- devices since ParseException only available on S+ devices. + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) + @Test + public void testDomainNameToLabels() throws Exception { + assertArrayEquals( + new byte[]{3, 'w', 'w', 'w', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm', 0}, + DnsRecordParser.domainNameToLabels("www.google.com")); + assertThrows(ParseException.class, () -> + DnsRecordParser.domainNameToLabels("aaa.")); + assertThrows(ParseException.class, () -> + DnsRecordParser.domainNameToLabels("aaa")); + assertThrows(ParseException.class, () -> + DnsRecordParser.domainNameToLabels(".")); + assertThrows(ParseException.class, () -> + DnsRecordParser.domainNameToLabels("")); + } + + @Test + public void testIsHostName() { + Assert.assertTrue(DnsRecordParser.isHostName("www.google.com")); + Assert.assertFalse(DnsRecordParser.isHostName("com")); + Assert.assertFalse(DnsRecordParser.isHostName("1.2.3.4")); + Assert.assertFalse(DnsRecordParser.isHostName("1234::5678")); + Assert.assertFalse(DnsRecordParser.isHostName(null)); + Assert.assertFalse(DnsRecordParser.isHostName("")); + } } From 6573c64f394fcd3f851a7e14822080e29a0b46ea Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Fri, 16 Sep 2022 20:19:38 +0800 Subject: [PATCH 560/777] NetworkStackConstants: add ICMP checksum offset constant Bug: 237369591 Test: NetworkStaticLibTests Change-Id: I7175c9ae3c547639fcfe2e252dad591ad2c3ec8a --- .../android/net/module/util/NetworkStackConstants.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 1ad9c35910..ebef1557bf 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -126,6 +126,14 @@ public final class NetworkStackConstants { public static final Inet6Address IPV6_ADDR_ALL_HOSTS_MULTICAST = (Inet6Address) InetAddresses.parseNumericAddress("ff02::3"); + /** + * ICMP constants. + * + * See also: + * - https://tools.ietf.org/html/rfc792 + */ + public static final int ICMP_CHECKSUM_OFFSET = 2; + /** * ICMPv6 constants. * From 0aa70a097353251340fafb28872d3522d6c0a113 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Fri, 16 Sep 2022 19:38:58 +0800 Subject: [PATCH 561/777] IpUtils: add ICMP checksum calculation function Bug: 237369591 Test: NetworkStaticLibTests Change-Id: If45de190872cad588f9b9104828a0d8116fc158b --- .../com/android/net/module/util/IpUtils.java | 10 +++- .../android/net/module/util/IpUtilsTest.java | 49 ++++++++++++++++++- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/IpUtils.java b/staticlibs/framework/com/android/net/module/util/IpUtils.java index dbc22854ac..569733edad 100644 --- a/staticlibs/framework/com/android/net/module/util/IpUtils.java +++ b/staticlibs/framework/com/android/net/module/util/IpUtils.java @@ -39,7 +39,7 @@ public class IpUtils { /** * Performs an IP checksum (used in IP header and across UDP - * payload) on the specified portion of a ByteBuffer. The seed + * payload) or ICMP checksum on the specified portion of a ByteBuffer. The seed * allows the checksum to commence with a specified value. */ private static int checksum(ByteBuffer buf, int seed, int start, int end) { @@ -144,6 +144,14 @@ public class IpUtils { return transportChecksum(buf, IPPROTO_TCP, ipOffset, transportOffset, transportLen); } + /** + * Calculate the ICMP checksum for an ICMPv4 packet. + */ + public static short icmpChecksum(ByteBuffer buf, int transportOffset, int transportLen) { + // ICMP checksum doesn't include pseudo-header. See RFC 792. + return (short) checksum(buf, 0, transportOffset, transportOffset + transportLen); + } + /** * Calculate the ICMPv6 checksum for an ICMPv6 packet. */ diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/IpUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/IpUtilsTest.java index 34683090ad..20555b353b 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/IpUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/IpUtilsTest.java @@ -16,6 +16,9 @@ package com.android.net.module.util; +import static com.android.net.module.util.NetworkStackConstants.ICMP_CHECKSUM_OFFSET; +import static com.android.net.module.util.NetworkStackConstants.IPV4_CHECKSUM_OFFSET; + import static org.junit.Assert.assertEquals; import androidx.test.filters.SmallTest; @@ -34,7 +37,6 @@ public class IpUtilsTest { private static final int IPV6_HEADER_LENGTH = 40; private static final int TCP_HEADER_LENGTH = 20; private static final int UDP_HEADER_LENGTH = 8; - private static final int IP_CHECKSUM_OFFSET = 10; private static final int TCP_CHECKSUM_OFFSET = 16; private static final int UDP_CHECKSUM_OFFSET = 6; @@ -141,7 +143,7 @@ public class IpUtilsTest { assertEquals((short) 0xffff, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH)); // Check that we can calculate the checksums from scratch. - final int ipSumOffset = IP_CHECKSUM_OFFSET; + final int ipSumOffset = IPV4_CHECKSUM_OFFSET; final int ipSum = getChecksum(packet, ipSumOffset); assertEquals(0xf68b, ipSum); @@ -163,4 +165,47 @@ public class IpUtilsTest { assertEquals(0, IpUtils.ipChecksum(packet, 0)); assertEquals((short) 0xffff, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH)); } + + @Test + public void testIpv4IcmpChecksum() throws Exception { + // packet = (scapy.IP(src="192.0.2.1", dst="192.0.2.2", tos=0x40) / + // scapy.ICMP(type=0x8, id=0x1234, seq=0x5678) / + // "hello, world") + ByteBuffer packet = ByteBuffer.wrap(new byte[] { + /* IPv4 */ + (byte) 0x45, (byte) 0x40, (byte) 0x00, (byte) 0x28, + (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, + (byte) 0x40, (byte) 0x01, (byte) 0xf6, (byte) 0x90, + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x02, + /* ICMP */ + (byte) 0x08, /* type: echo-request */ + (byte) 0x00, /* code: 0 */ + (byte) 0x4f, (byte) 0x07, /* chksum: 0x4f07 */ + (byte) 0x12, (byte) 0x34, /* id: 0x1234 */ + (byte) 0x56, (byte) 0x78, /* seq: 0x5678 */ + (byte) 0x68, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, /* data: hello, world */ + (byte) 0x6f, (byte) 0x2c, (byte) 0x20, (byte) 0x77, + (byte) 0x6f, (byte) 0x72, (byte) 0x6c, (byte) 0x64 + }); + + // Check that a valid packet has checksum 0. + int transportLen = packet.limit() - IPV4_HEADER_LENGTH; + assertEquals(0, IpUtils.icmpChecksum(packet, IPV4_HEADER_LENGTH, transportLen)); + + // Check that we can calculate the checksum from scratch. + int sumOffset = IPV4_HEADER_LENGTH + ICMP_CHECKSUM_OFFSET; + int sum = getUnsignedByte(packet, sumOffset) * 256 + getUnsignedByte(packet, sumOffset + 1); + assertEquals(0x4f07, sum); + + packet.put(sumOffset, (byte) 0); + packet.put(sumOffset + 1, (byte) 0); + assertChecksumEquals(sum, IpUtils.icmpChecksum(packet, IPV4_HEADER_LENGTH, transportLen)); + + // Check that writing the checksum back into the packet results in a valid packet. + packet.putShort( + sumOffset, + IpUtils.icmpChecksum(packet, IPV4_HEADER_LENGTH, transportLen)); + assertEquals(0, IpUtils.icmpChecksum(packet, IPV4_HEADER_LENGTH, transportLen)); + } } From c5dcf2c8ea0a104143f6ffdcb8ef2816c1f2cc33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 27 Sep 2022 23:13:21 +0000 Subject: [PATCH 562/777] add bpf_for_each_map_elem() helper definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See 5.12+ kernel's include/uapi/linux/bpf.h (note that since bpf is 64-bit, int and long are the same thing) Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ib340a619645ad5ab8e41ff76cb7b51671f496bc5 --- staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 35d9f31d1e..6eb8aa7f45 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -138,6 +138,10 @@ static int (*bpf_map_update_elem_unsafe)(const struct bpf_map_def* map, const vo static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, const void* key) = (void*)BPF_FUNC_map_delete_elem; +static int (*bpf_for_each_map_elem)(const struct bpf_map_def* map, void *callback_fn, + void *callback_ctx, unsigned long long flags) = (void*) + BPF_FUNC_for_each_map_elem; + #define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val) \ struct ____btf_map_##name { \ type_key key; \ From 561b97e711c0bb051c88b93db8582873f209bcbd Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Mon, 19 Sep 2022 10:22:14 +0800 Subject: [PATCH 563/777] Enlarge the TestableNetworkCallback default timeout TestableNetworkCallback is using on both unit and cts tests with same timeout 200ms. For unit tests, most of objects are mock, so the callback should respond quickly and this interval is fine. But for cts tests, they are running on the real system and the callback time will depend on the system which may be over 200 ms sometimes if the system is busy or has performance problems. So enlarge the Network Callback default timeout to 500ms that can reduce the test flake on cts tests. To ensure there is no impact on no callback check, add the no callback timeout 200ms which is the same timeout as before. Bug: 245000567 Test: Run the FrameworksNetTests CtsNetTestCases and check no running time increase. Change-Id: I31f8bc08f65a622f6ab9b6c7f0577f0b107440c1 --- .../testutils/TestableNetworkCallback.kt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index dffdbe8bba..4407714d87 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -168,16 +168,22 @@ open class RecorderCallback private constructor( } } -private const val DEFAULT_TIMEOUT = 200L // ms +private const val DEFAULT_TIMEOUT = 30_000L // ms +private const val DEFAULT_NO_CALLBACK_TIMEOUT = 200L // ms open class TestableNetworkCallback private constructor( src: TestableNetworkCallback?, - val defaultTimeoutMs: Long = DEFAULT_TIMEOUT + val defaultTimeoutMs: Long = DEFAULT_TIMEOUT, + val defaultNoCallbackTimeoutMs: Long = DEFAULT_NO_CALLBACK_TIMEOUT ) : RecorderCallback(src) { @JvmOverloads - constructor(timeoutMs: Long = DEFAULT_TIMEOUT): this(null, timeoutMs) + constructor( + timeoutMs: Long = DEFAULT_TIMEOUT, + noCallbackTimeoutMs: Long = DEFAULT_NO_CALLBACK_TIMEOUT + ): this(null, timeoutMs, noCallbackTimeoutMs) - fun createLinkedCopy() = TestableNetworkCallback(this, defaultTimeoutMs) + fun createLinkedCopy() = TestableNetworkCallback( + this, defaultTimeoutMs, defaultNoCallbackTimeoutMs) // The last available network, or null if any network was lost since the last call to // onAvailable. TODO : fix this by fixing the tests that rely on this behavior @@ -194,7 +200,7 @@ open class TestableNetworkCallback private constructor( // Make open for use in ConnectivityServiceTest which is the only one knowing its handlers. // TODO : remove the necessity to overload this, remove the open qualifier, and give a // default argument to assertNoCallback instead, possibly with @JvmOverloads if necessary. - open fun assertNoCallback() = assertNoCallback(defaultTimeoutMs) + open fun assertNoCallback() = assertNoCallback(defaultNoCallbackTimeoutMs) fun assertNoCallback(timeoutMs: Long) { val cb = history.poll(timeoutMs) @@ -202,7 +208,7 @@ open class TestableNetworkCallback private constructor( } fun assertNoCallbackThat( - timeoutMs: Long = defaultTimeoutMs, + timeoutMs: Long = defaultNoCallbackTimeoutMs, valid: (CallbackEntry) -> Boolean ) { val cb = history.poll(timeoutMs) { valid(it) }.let { From 2ecf12025684bceb89265187fca792aa8c6fdc90 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 12 Oct 2022 19:49:42 +0900 Subject: [PATCH 564/777] Move bit utility methods to a new BitUtils class. In particular this moves NetworkCapabilies# appendStringRepresentationOfBitMaskToStringBuilder to this class. It also moves some other NetworkCapabilitiesUtils methods that are better homed in this new class. Test: new test in this patch Change-Id: I16374d7ca1da92052bb814bde796602d62f5c42e --- .../com/android/net/module/util/BitUtils.java | 110 ++++++++++++++++++ .../module/util/NetworkCapabilitiesUtils.java | 48 +------- .../android/net/module/util/BitUtilsTests.kt | 61 ++++++++++ .../util/NetworkCapabilitiesUtilsTest.kt | 20 ---- 4 files changed, 174 insertions(+), 65 deletions(-) create mode 100644 staticlibs/framework/com/android/net/module/util/BitUtils.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/BitUtilsTests.kt diff --git a/staticlibs/framework/com/android/net/module/util/BitUtils.java b/staticlibs/framework/com/android/net/module/util/BitUtils.java new file mode 100644 index 0000000000..2b32e86023 --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/BitUtils.java @@ -0,0 +1,110 @@ +/* + * 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 com.android.net.module.util; + +import android.annotation.NonNull; + +/** + * @hide + */ +public class BitUtils { + /** + * Unpacks long value into an array of bits. + */ + public static int[] unpackBits(long val) { + int size = Long.bitCount(val); + int[] result = new int[size]; + int index = 0; + int bitPos = 0; + while (val != 0) { + if ((val & 1) == 1) result[index++] = bitPos; + val = val >>> 1; + bitPos++; + } + return result; + } + + /** + * Packs a list of ints in the same way as packBits() + * + * Each passed int is the rank of a bit that should be set in the returned long. + * Example : passing (1,3) will return in 0b00001010 and passing (5,6,0) will return 0b01100001 + * + * @param bits bits to pack + * @return a long with the specified bits set. + */ + public static long packBitList(int... bits) { + return packBits(bits); + } + + /** + * Packs array of bits into a long value. + * + * Each passed int is the rank of a bit that should be set in the returned long. + * Example : passing [1,3] will return in 0b00001010 and passing [5,6,0] will return 0b01100001 + * + * @param bits bits to pack + * @return a long with the specified bits set. + */ + public static long packBits(int[] bits) { + long packed = 0; + for (int b : bits) { + packed |= (1L << b); + } + return packed; + } + + /** + * An interface for a function that can retrieve a name associated with an int. + * + * This is useful for bitfields like network capabilities or network score policies. + */ + @FunctionalInterface + public interface NameOf { + /** Retrieve the name associated with the passed value */ + String nameOf(int value); + } + + /** + * Given a bitmask and a name fetcher, append names of all set bits to the builder + * + * This method takes all bit sets in the passed bitmask, will figure out the name associated + * with the weight of each bit with the passed name fetcher, and append each name to the + * passed StringBuilder, separated by the passed separator. + * + * For example, if the bitmask is 0110, and the name fetcher return "BIT_1" to "BIT_4" for + * numbers from 1 to 4, and the separator is "&", this method appends "BIT_2&BIT3" to the + * StringBuilder. + */ + public static void appendStringRepresentationOfBitMaskToStringBuilder(@NonNull StringBuilder sb, + long bitMask, @NonNull NameOf nameFetcher, @NonNull String separator) { + int bitPos = 0; + boolean firstElementAdded = false; + while (bitMask != 0) { + if ((bitMask & 1) != 0) { + if (firstElementAdded) { + sb.append(separator); + } else { + firstElementAdded = true; + } + sb.append(nameFetcher.nameOf(bitPos)); + } + bitMask >>>= 1; + ++bitPos; + } + } +} diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java index 26c24f8daa..54ce01ecbd 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java @@ -44,6 +44,9 @@ import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; +import static com.android.net.module.util.BitUtils.packBitList; +import static com.android.net.module.util.BitUtils.unpackBits; + import android.annotation.NonNull; import android.net.NetworkCapabilities; @@ -181,49 +184,4 @@ public final class NetworkCapabilitiesUtils { return false; } - /** - * Unpacks long value into an array of bits. - */ - public static int[] unpackBits(long val) { - int size = Long.bitCount(val); - int[] result = new int[size]; - int index = 0; - int bitPos = 0; - while (val != 0) { - if ((val & 1) == 1) result[index++] = bitPos; - val = val >>> 1; - bitPos++; - } - return result; - } - - /** - * Packs a list of ints in the same way as packBits() - * - * Each passed int is the rank of a bit that should be set in the returned long. - * Example : passing (1,3) will return in 0b00001010 and passing (5,6,0) will return 0b01100001 - * - * @param bits bits to pack - * @return a long with the specified bits set. - */ - public static long packBitList(int... bits) { - return packBits(bits); - } - - /** - * Packs array of bits into a long value. - * - * Each passed int is the rank of a bit that should be set in the returned long. - * Example : passing [1,3] will return in 0b00001010 and passing [5,6,0] will return 0b01100001 - * - * @param bits bits to pack - * @return a long with the specified bits set. - */ - public static long packBits(int[] bits) { - long packed = 0; - for (int b : bits) { - packed |= (1L << b); - } - return packed; - } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/BitUtilsTests.kt b/staticlibs/tests/unit/src/com/android/net/module/util/BitUtilsTests.kt new file mode 100644 index 0000000000..02367162a5 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/BitUtilsTests.kt @@ -0,0 +1,61 @@ +/* + * 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 com.android.net.module.util + +import com.android.net.module.util.BitUtils.appendStringRepresentationOfBitMaskToStringBuilder +import com.android.net.module.util.BitUtils.packBits +import com.android.net.module.util.BitUtils.unpackBits +import org.junit.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class BitUtilsTests { + @Test + fun testBitPackingTestCase() { + runBitPackingTestCase(0, intArrayOf()) + runBitPackingTestCase(1, intArrayOf(0)) + runBitPackingTestCase(3, intArrayOf(0, 1)) + runBitPackingTestCase(4, intArrayOf(2)) + runBitPackingTestCase(63, intArrayOf(0, 1, 2, 3, 4, 5)) + runBitPackingTestCase(Long.MAX_VALUE.inv(), intArrayOf(63)) + runBitPackingTestCase(Long.MAX_VALUE.inv() + 1, intArrayOf(0, 63)) + runBitPackingTestCase(Long.MAX_VALUE.inv() + 2, intArrayOf(1, 63)) + } + + fun runBitPackingTestCase(packedBits: Long, bits: IntArray) { + assertEquals(packedBits, packBits(bits)) + assertTrue(bits contentEquals unpackBits(packedBits)) + } + + @Test + fun testAppendStringRepresentationOfBitMaskToStringBuilder() { + runTestAppendStringRepresentationOfBitMaskToStringBuilder("", 0) + runTestAppendStringRepresentationOfBitMaskToStringBuilder("BIT0", 0b1) + runTestAppendStringRepresentationOfBitMaskToStringBuilder("BIT1&BIT2&BIT4", 0b10110) + runTestAppendStringRepresentationOfBitMaskToStringBuilder( + "BIT0&BIT60&BIT61&BIT62&BIT63", + (0b11110000_00000000_00000000_00000000 shl 32) + + 0b00000000_00000000_00000000_00000001) + } + + fun runTestAppendStringRepresentationOfBitMaskToStringBuilder(expected: String, bitMask: Long) { + StringBuilder().let { + appendStringRepresentationOfBitMaskToStringBuilder(it, bitMask, { i -> "BIT$i" }, "&") + assertEquals(expected, it.toString()) + } + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt index 256ea1e8a6..958f45f46e 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt @@ -22,7 +22,6 @@ import android.net.NetworkCapabilities.NET_CAPABILITY_BIP import android.net.NetworkCapabilities.NET_CAPABILITY_CBS import android.net.NetworkCapabilities.NET_CAPABILITY_EIMS import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET -import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET import android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH import android.net.NetworkCapabilities.TRANSPORT_CELLULAR @@ -38,8 +37,6 @@ import com.android.modules.utils.build.SdkLevel import com.android.net.module.util.NetworkCapabilitiesUtils.RESTRICTED_CAPABILITIES import com.android.net.module.util.NetworkCapabilitiesUtils.UNRESTRICTED_CAPABILITIES import com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport -import com.android.net.module.util.NetworkCapabilitiesUtils.packBits -import com.android.net.module.util.NetworkCapabilitiesUtils.unpackBits import org.junit.Test import org.junit.runner.RunWith import java.lang.IllegalArgumentException @@ -75,23 +72,6 @@ class NetworkCapabilitiesUtilsTest { } } - @Test - fun testBitPackingTestCase() { - runBitPackingTestCase(0, intArrayOf()) - runBitPackingTestCase(1, intArrayOf(0)) - runBitPackingTestCase(3, intArrayOf(0, 1)) - runBitPackingTestCase(4, intArrayOf(2)) - runBitPackingTestCase(63, intArrayOf(0, 1, 2, 3, 4, 5)) - runBitPackingTestCase(Long.MAX_VALUE.inv(), intArrayOf(63)) - runBitPackingTestCase(Long.MAX_VALUE.inv() + 1, intArrayOf(0, 63)) - runBitPackingTestCase(Long.MAX_VALUE.inv() + 2, intArrayOf(1, 63)) - } - - fun runBitPackingTestCase(packedBits: Long, bits: IntArray) { - assertEquals(packedBits, packBits(bits)) - assertTrue(bits contentEquals unpackBits(packedBits)) - } - // NetworkCapabilities constructor and Builder are not available until R. Mark TargetApi to // ignore the linter error since it's used in only unit test. @Test @TargetApi(Build.VERSION_CODES.R) From 8d656995338f63354fdcf8519eab406419b3e294 Mon Sep 17 00:00:00 2001 From: chiachangwang Date: Wed, 12 Oct 2022 14:10:29 +0000 Subject: [PATCH 565/777] Correct failed log in ensureWifiConnected() The timeout is used in the test should be WIFI_CONNECT_TIMEOUT_MS but log shows WIFI_CONNECT_INTERVAL_MS instead. The debug log is confusing. Correct it to right variable. Test: atest CtsNetTestCases Change-Id: I4cedaa6e03aea6cc02a07bdbea2f0b1e7f5076e1 --- .../testutils/devicetests/com/android/testutils/ConnectUtil.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt index fc951d862e..7e92af112c 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt @@ -75,7 +75,7 @@ class ConnectUtil(private val context: Context) { timeoutMs = WIFI_CONNECT_TIMEOUT_MS) assertNotNull(cb, "Could not connect to a wifi access point within " + - "$WIFI_CONNECT_INTERVAL_MS ms. Check that the test device has a wifi network " + + "$WIFI_CONNECT_TIMEOUT_MS ms. Check that the test device has a wifi network " + "configured, and that the test access point is functioning properly.") return cb.network } finally { From cd0fc3d71b3ef5168d5c92e801dfec24618093be Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 13 Oct 2022 16:01:25 +0900 Subject: [PATCH 566/777] Move TestableNetworkCallbackTest to f/l/n This tests a utility in f/l/n, so it should live together with it and not in the network stack tests Test: NetworkStaticLibTests NetworkStackTests Change-Id: I90d12933e3a82eba4b565022d3df1e7c1d503f56 --- .../testutils/TestableNetworkCallbackTest.kt | 385 ++++++++++++++++++ 1 file changed, 385 insertions(+) create mode 100644 staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt new file mode 100644 index 0000000000..b532ee8b38 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt @@ -0,0 +1,385 @@ +/* + * 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 com.android.testutils + +import android.annotation.SuppressLint +import android.net.LinkAddress +import android.net.LinkProperties +import android.net.Network +import android.net.NetworkCapabilities +import com.android.testutils.RecorderCallback.CallbackEntry +import com.android.testutils.RecorderCallback.CallbackEntry.Companion.AVAILABLE +import com.android.testutils.RecorderCallback.CallbackEntry.Companion.BLOCKED_STATUS +import com.android.testutils.RecorderCallback.CallbackEntry.Companion.LINK_PROPERTIES_CHANGED +import com.android.testutils.RecorderCallback.CallbackEntry.Companion.LOSING +import com.android.testutils.RecorderCallback.CallbackEntry.Companion.NETWORK_CAPS_UPDATED +import com.android.testutils.RecorderCallback.CallbackEntry.Companion.LOST +import com.android.testutils.RecorderCallback.CallbackEntry.Companion.RESUMED +import com.android.testutils.RecorderCallback.CallbackEntry.Companion.SUSPENDED +import com.android.testutils.RecorderCallback.CallbackEntry.Companion.UNAVAILABLE +import com.android.testutils.RecorderCallback.CallbackEntry.Available +import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatus +import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import kotlin.reflect.KClass +import kotlin.test.assertEquals +import kotlin.test.assertFails +import kotlin.test.assertNull +import kotlin.test.assertTrue +import kotlin.test.fail + +const val SHORT_TIMEOUT_MS = 20L +const val DEFAULT_LINGER_DELAY_MS = 30000 +const val NOT_METERED = NetworkCapabilities.NET_CAPABILITY_NOT_METERED +const val WIFI = NetworkCapabilities.TRANSPORT_WIFI +const val CELLULAR = NetworkCapabilities.TRANSPORT_CELLULAR +const val TEST_INTERFACE_NAME = "testInterfaceName" + +@RunWith(JUnit4::class) +@SuppressLint("NewApi") // Uses hidden APIs, which the linter would identify as missing APIs. +class TestableNetworkCallbackTest { + private lateinit var mCallback: TestableNetworkCallback + + private fun makeHasNetwork(netId: Int) = object : TestableNetworkCallback.HasNetwork { + override val network: Network = Network(netId) + } + + @Before + fun setUp() { + mCallback = TestableNetworkCallback() + } + + @Test + fun testLastAvailableNetwork() { + // Make sure there is no last available network at first, then the last available network + // is returned after onAvailable is called. + val net2097 = Network(2097) + assertNull(mCallback.lastAvailableNetwork) + mCallback.onAvailable(net2097) + assertEquals(mCallback.lastAvailableNetwork, net2097) + + // Make sure calling onCapsChanged/onLinkPropertiesChanged don't affect the last available + // network. + mCallback.onCapabilitiesChanged(net2097, NetworkCapabilities()) + mCallback.onLinkPropertiesChanged(net2097, LinkProperties()) + assertEquals(mCallback.lastAvailableNetwork, net2097) + + // Make sure onLost clears the last available network. + mCallback.onLost(net2097) + assertNull(mCallback.lastAvailableNetwork) + + // Do the same but with a different network after onLost : make sure the last available + // network is the new one, not the original one. + val net2098 = Network(2098) + mCallback.onAvailable(net2098) + mCallback.onCapabilitiesChanged(net2098, NetworkCapabilities()) + mCallback.onLinkPropertiesChanged(net2098, LinkProperties()) + assertEquals(mCallback.lastAvailableNetwork, net2098) + + // Make sure onAvailable changes the last available network even if onLost was not called. + val net2099 = Network(2099) + mCallback.onAvailable(net2099) + assertEquals(mCallback.lastAvailableNetwork, net2099) + + // For legacy reasons, lastAvailableNetwork is null as soon as any is lost, not necessarily + // the last available one. Check that behavior. + mCallback.onLost(net2098) + assertNull(mCallback.lastAvailableNetwork) + + // Make sure that losing the really last available one still results in null. + mCallback.onLost(net2099) + assertNull(mCallback.lastAvailableNetwork) + + // Make sure multiple onAvailable in a row then onLost still results in null. + mCallback.onAvailable(net2097) + mCallback.onAvailable(net2098) + mCallback.onAvailable(net2099) + mCallback.onLost(net2097) + assertNull(mCallback.lastAvailableNetwork) + } + + @Test + fun testAssertNoCallback() { + mCallback.assertNoCallback(SHORT_TIMEOUT_MS) + mCallback.onAvailable(Network(100)) + assertFails { mCallback.assertNoCallback(SHORT_TIMEOUT_MS) } + } + + @Test + fun testAssertNoCallbackThat() { + val net = Network(101) + mCallback.assertNoCallbackThat { it is Available } + mCallback.onAvailable(net) + // Expect no blocked status change. Receive other callback does not fail the test. + mCallback.assertNoCallbackThat { it is BlockedStatus } + mCallback.onBlockedStatusChanged(net, true) + assertFails { mCallback.assertNoCallbackThat { it is BlockedStatus } } + mCallback.onBlockedStatusChanged(net, false) + mCallback.onCapabilitiesChanged(net, NetworkCapabilities()) + assertFails { mCallback.assertNoCallbackThat { it is CapabilitiesChanged } } + } + + @Test + fun testCapabilitiesWithAndWithout() { + val net = Network(101) + val matcher = makeHasNetwork(101) + val meteredNc = NetworkCapabilities() + val unmeteredNc = NetworkCapabilities().addCapability(NOT_METERED) + // Check that expecting caps (with or without) fails when no callback has been received. + assertFails { mCallback.expectCapabilitiesWith(NOT_METERED, matcher, SHORT_TIMEOUT_MS) } + assertFails { mCallback.expectCapabilitiesWithout(NOT_METERED, matcher, SHORT_TIMEOUT_MS) } + + // Add NOT_METERED and check that With succeeds and Without fails. + mCallback.onCapabilitiesChanged(net, unmeteredNc) + mCallback.expectCapabilitiesWith(NOT_METERED, matcher) + mCallback.onCapabilitiesChanged(net, unmeteredNc) + assertFails { mCallback.expectCapabilitiesWithout(NOT_METERED, matcher, SHORT_TIMEOUT_MS) } + + // Don't add NOT_METERED and check that With fails and Without succeeds. + mCallback.onCapabilitiesChanged(net, meteredNc) + assertFails { mCallback.expectCapabilitiesWith(NOT_METERED, matcher, SHORT_TIMEOUT_MS) } + mCallback.onCapabilitiesChanged(net, meteredNc) + mCallback.expectCapabilitiesWithout(NOT_METERED, matcher) + } + + @Test + fun testExpectCallbackThat() { + val net = Network(193) + val netCaps = NetworkCapabilities().addTransportType(CELLULAR) + // Check that expecting callbackThat anything fails when no callback has been received. + assertFails { mCallback.expectCallbackThat(SHORT_TIMEOUT_MS) { true } } + + // Basic test for true and false + mCallback.onAvailable(net) + mCallback.expectCallbackThat { true } + mCallback.onAvailable(net) + assertFails { mCallback.expectCallbackThat(SHORT_TIMEOUT_MS) { false } } + + // Try a positive and a negative case + mCallback.onBlockedStatusChanged(net, true) + mCallback.expectCallbackThat { cb -> cb is BlockedStatus && cb.blocked } + mCallback.onCapabilitiesChanged(net, netCaps) + assertFails { mCallback.expectCallbackThat(SHORT_TIMEOUT_MS) { cb -> + cb is CapabilitiesChanged && cb.caps.hasTransport(WIFI) + } } + } + + @Test + fun testCapabilitiesThat() { + val net = Network(101) + val netCaps = NetworkCapabilities().addCapability(NOT_METERED).addTransportType(WIFI) + // Check that expecting capabilitiesThat anything fails when no callback has been received. + assertFails { mCallback.expectCapabilitiesThat(net, SHORT_TIMEOUT_MS) { true } } + + // Basic test for true and false + mCallback.onCapabilitiesChanged(net, netCaps) + mCallback.expectCapabilitiesThat(net) { true } + mCallback.onCapabilitiesChanged(net, netCaps) + assertFails { mCallback.expectCapabilitiesThat(net, SHORT_TIMEOUT_MS) { false } } + + // Try a positive and a negative case + mCallback.onCapabilitiesChanged(net, netCaps) + mCallback.expectCapabilitiesThat(net) { caps -> + caps.hasCapability(NOT_METERED) && + caps.hasTransport(WIFI) && + !caps.hasTransport(CELLULAR) + } + mCallback.onCapabilitiesChanged(net, netCaps) + assertFails { mCallback.expectCapabilitiesThat(net, SHORT_TIMEOUT_MS) { caps -> + caps.hasTransport(CELLULAR) + } } + + // Try a matching callback on the wrong network + mCallback.onCapabilitiesChanged(net, netCaps) + assertFails { mCallback.expectCapabilitiesThat(Network(100), SHORT_TIMEOUT_MS) { true } } + } + + @Test + fun testLinkPropertiesThat() { + val net = Network(112) + val linkAddress = LinkAddress("fe80::ace:d00d/64") + val mtu = 1984 + val linkProps = LinkProperties().apply { + this.mtu = mtu + interfaceName = TEST_INTERFACE_NAME + addLinkAddress(linkAddress) + } + + // Check that expecting linkPropsThat anything fails when no callback has been received. + assertFails { mCallback.expectLinkPropertiesThat(net, SHORT_TIMEOUT_MS) { true } } + + // Basic test for true and false + mCallback.onLinkPropertiesChanged(net, linkProps) + mCallback.expectLinkPropertiesThat(net) { true } + mCallback.onLinkPropertiesChanged(net, linkProps) + assertFails { mCallback.expectLinkPropertiesThat(net, SHORT_TIMEOUT_MS) { false } } + + // Try a positive and negative case + mCallback.onLinkPropertiesChanged(net, linkProps) + mCallback.expectLinkPropertiesThat(net) { lp -> + lp.interfaceName == TEST_INTERFACE_NAME && + lp.linkAddresses.contains(linkAddress) && + lp.mtu == mtu + } + mCallback.onLinkPropertiesChanged(net, linkProps) + assertFails { mCallback.expectLinkPropertiesThat(net, SHORT_TIMEOUT_MS) { lp -> + lp.interfaceName != TEST_INTERFACE_NAME + } } + + // Try a matching callback on the wrong network + mCallback.onLinkPropertiesChanged(net, linkProps) + assertFails { mCallback.expectLinkPropertiesThat(Network(114), SHORT_TIMEOUT_MS) { lp -> + lp.interfaceName == TEST_INTERFACE_NAME + } } + } + + @Test + fun testExpectCallback() { + val net = Network(103) + // Test expectCallback fails when nothing was sent. + assertFails { mCallback.expectCallback(net, SHORT_TIMEOUT_MS) } + + // Test onAvailable is seen and can be expected + mCallback.onAvailable(net) + mCallback.expectCallback(net, SHORT_TIMEOUT_MS) + + // Test onAvailable won't return calls with a different network + mCallback.onAvailable(Network(106)) + assertFails { mCallback.expectCallback(net, SHORT_TIMEOUT_MS) } + + // Test onAvailable won't return calls with a different callback + mCallback.onAvailable(net) + assertFails { mCallback.expectCallback(net, SHORT_TIMEOUT_MS) } + } + + @Test + fun testPollForNextCallback() { + assertFails { mCallback.pollForNextCallback(SHORT_TIMEOUT_MS) } + TNCInterpreter.interpretTestSpec(initial = mCallback, lineShift = 1, + threadTransform = { cb -> cb.createLinkedCopy() }, spec = """ + sleep; onAvailable(133) | poll(2) = Available(133) time 1..4 + | poll(1) fails + onCapabilitiesChanged(108) | poll(1) = CapabilitiesChanged(108) time 0..3 + onBlockedStatus(199) | poll(1) = BlockedStatus(199) time 0..3 + """) + } + + @Test + fun testEventuallyExpect() { + // TODO: Current test does not verify the inline one. Also verify the behavior after + // aligning two eventuallyExpect() + val net1 = Network(100) + val net2 = Network(101) + mCallback.onAvailable(net1) + mCallback.onCapabilitiesChanged(net1, NetworkCapabilities()) + mCallback.onLinkPropertiesChanged(net1, LinkProperties()) + mCallback.eventuallyExpect(LINK_PROPERTIES_CHANGED) { + net1.equals(it.network) + } + // No further new callback. Expect no callback. + assertFails { mCallback.eventuallyExpect(LINK_PROPERTIES_CHANGED) } + + // Verify no predicate set. + mCallback.onAvailable(net2) + mCallback.onLinkPropertiesChanged(net2, LinkProperties()) + mCallback.onBlockedStatusChanged(net1, false) + mCallback.eventuallyExpect(BLOCKED_STATUS) { net1.equals(it.network) } + // Verify no callback received if the callback does not happen. + assertFails { mCallback.eventuallyExpect(LOSING) } + } + + @Test + fun testEventuallyExpectOnMultiThreads() { + TNCInterpreter.interpretTestSpec(initial = mCallback, lineShift = 1, + threadTransform = { cb -> cb.createLinkedCopy() }, spec = """ + onAvailable(100) | eventually(CapabilitiesChanged(100), 1) fails + sleep ; onCapabilitiesChanged(100) | eventually(CapabilitiesChanged(100), 2) + onAvailable(101) ; onBlockedStatus(101) | eventually(BlockedStatus(100), 2) fails + onSuspended(100) ; sleep ; onLost(100) | eventually(Lost(100), 2) + """) + } +} + +private object TNCInterpreter : ConcurrentInterpreter(interpretTable) + +val EntryList = CallbackEntry::class.sealedSubclasses.map { it.simpleName }.joinToString("|") +private fun callbackEntryFromString(name: String): KClass { + return CallbackEntry::class.sealedSubclasses.first { it.simpleName == name } +} + +@SuppressLint("NewApi") // Uses hidden APIs, which the linter would identify as missing APIs. +private val interpretTable = listOf>( + // Interpret "Available(xx)" as "call to onAvailable with netId xx", and likewise for + // all callback types. This is implemented above by enumerating the subclasses of + // CallbackEntry and reading their simpleName. + Regex("""(.*)\s+=\s+($EntryList)\((\d+)\)""") to { i, cb, t -> + val record = i.interpret(t.strArg(1), cb) + assertTrue(callbackEntryFromString(t.strArg(2)).isInstance(record)) + // Strictly speaking testing for is CallbackEntry is useless as it's been tested above + // but the compiler can't figure things out from the isInstance call. It does understand + // from the assertTrue(is CallbackEntry) that this is true, which allows to access + // the 'network' member below. + assertTrue(record is CallbackEntry) + assertEquals(record.network.netId, t.intArg(3)) + }, + // Interpret "onAvailable(xx)" as calling "onAvailable" with a netId of xx, and likewise for + // all callback types. NetworkCapabilities and LinkProperties just get an empty object + // as their argument. Losing gets the default linger timer. Blocked gets false. + Regex("""on($EntryList)\((\d+)\)""") to { i, cb, t -> + val net = Network(t.intArg(2)) + when (t.strArg(1)) { + "Available" -> cb.onAvailable(net) + // PreCheck not used in tests. Add it here if it becomes useful. + "CapabilitiesChanged" -> cb.onCapabilitiesChanged(net, NetworkCapabilities()) + "LinkPropertiesChanged" -> cb.onLinkPropertiesChanged(net, LinkProperties()) + "Suspended" -> cb.onNetworkSuspended(net) + "Resumed" -> cb.onNetworkResumed(net) + "Losing" -> cb.onLosing(net, DEFAULT_LINGER_DELAY_MS) + "Lost" -> cb.onLost(net) + "Unavailable" -> cb.onUnavailable() + "BlockedStatus" -> cb.onBlockedStatusChanged(net, false) + else -> fail("Unknown callback type") + } + }, + Regex("""poll\((\d+)\)""") to { i, cb, t -> + cb.pollForNextCallback(t.timeArg(1)) + }, + // Interpret "eventually(Available(xx), timeout)" as calling eventuallyExpect that expects + // CallbackEntry.AVAILABLE with netId of xx within timeout*INTERPRET_TIME_UNIT timeout, and + // likewise for all callback types. + Regex("""eventually\(($EntryList)\((\d+)\),\s+(\d+)\)""") to { i, cb, t -> + val net = Network(t.intArg(2)) + val timeout = t.timeArg(3) + when (t.strArg(1)) { + "Available" -> cb.eventuallyExpect(AVAILABLE, timeout) { net == it.network } + "Suspended" -> cb.eventuallyExpect(SUSPENDED, timeout) { net == it.network } + "Resumed" -> cb.eventuallyExpect(RESUMED, timeout) { net == it.network } + "Losing" -> cb.eventuallyExpect(LOSING, timeout) { net == it.network } + "Lost" -> cb.eventuallyExpect(LOST, timeout) { net == it.network } + "Unavailable" -> cb.eventuallyExpect(UNAVAILABLE, timeout) { net == it.network } + "BlockedStatus" -> cb.eventuallyExpect(BLOCKED_STATUS, timeout) { net == it.network } + "CapabilitiesChanged" -> + cb.eventuallyExpect(NETWORK_CAPS_UPDATED, timeout) { net == it.network } + "LinkPropertiesChanged" -> + cb.eventuallyExpect(LINK_PROPERTIES_CHANGED, timeout) { net == it.network } + else -> fail("Unknown callback type") + } + } +) From 5c6f7809e261055440b87044259f2b231d229e55 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 13 Oct 2022 16:39:05 +0900 Subject: [PATCH 567/777] Save one minute in executing NetworkStaticLibTests The default timeout for expectEventually is 30 seconds, so this test used to take one minute. With this change, it now only takes 50ms, with virtually no change in safety. Test: NetworkStaticLibTests Change-Id: Id8d6a738ea6a70f7d901a7659b2160c2f3d7d2c0 --- .../src/com/android/testutils/TestableNetworkCallbackTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt index b532ee8b38..557f1fdbb7 100644 --- a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt +++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt @@ -294,7 +294,7 @@ class TestableNetworkCallbackTest { net1.equals(it.network) } // No further new callback. Expect no callback. - assertFails { mCallback.eventuallyExpect(LINK_PROPERTIES_CHANGED) } + assertFails { mCallback.eventuallyExpect(LINK_PROPERTIES_CHANGED, SHORT_TIMEOUT_MS) } // Verify no predicate set. mCallback.onAvailable(net2) @@ -302,7 +302,7 @@ class TestableNetworkCallbackTest { mCallback.onBlockedStatusChanged(net1, false) mCallback.eventuallyExpect(BLOCKED_STATUS) { net1.equals(it.network) } // Verify no callback received if the callback does not happen. - assertFails { mCallback.eventuallyExpect(LOSING) } + assertFails { mCallback.eventuallyExpect(LOSING, SHORT_TIMEOUT_MS) } } @Test From f4dd77109e7c0c65f7d8d1882c401a275d1c7692 Mon Sep 17 00:00:00 2001 From: Cole Faust Date: Sat, 15 Oct 2022 21:33:31 -0700 Subject: [PATCH 568/777] Fix errorprone warnings that should be errors This commit is part of a large scale change to fix errorprone errors that have been downgraded to warnings in the android source tree, so that they can be promoted to errors again. The full list of changes include the following, but not all will be present in any one individual commit: BadAnnotationImplementation BadShiftAmount BanJNDI BoxedPrimitiveEquality ComparableType ComplexBooleanConstant CollectionToArraySafeParameter ConditionalExpressionNumericPromotion DangerousLiteralNull DoubleBraceInitialization DurationFrom DurationTemporalUnit EmptyTopLevelDeclaration EqualsNull EqualsReference FormatString FromTemporalAccessor GetClassOnAnnotation GetClassOnClass HashtableContains IdentityBinaryExpression IdentityHashMapBoxing InstantTemporalUnit InvalidTimeZoneID InvalidZoneId IsInstanceIncompatibleType JUnitParameterMethodNotFound LockOnBoxedPrimitive MathRoundIntLong MislabeledAndroidString MisusedDayOfYear MissingSuperCall MisusedWeekYear ModifyingCollectionWithItself NoCanIgnoreReturnValueOnClasses NonRuntimeAnnotation NullableOnContainingClass NullTernary OverridesJavaxInjectableMethod ParcelableCreator PeriodFrom PreconditionsInvalidPlaceholder ProtoBuilderReturnValueIgnored ProtoFieldNullComparison RandomModInteger RectIntersectReturnValueIgnored ReturnValueIgnored SelfAssignment SelfComparison SelfEquals SizeGreaterThanOrEqualsZero StringBuilderInitWithChar TreeToString TryFailThrowable UnnecessaryCheckNotNull UnusedCollectionModifiedInPlace XorPower See https://errorprone.info/bugpatterns for more information on the checks. Bug: 253827323 Test: m RUN_ERROR_PRONE=true javac-check Change-Id: I772563b5e54b468a755520d2ed9b78bcb5fc3ad6 --- .../devicetests/com/android/testutils/DeviceInfoUtils.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java b/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java index ea89edaa34..ce55fdc1d3 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java @@ -20,6 +20,7 @@ import android.os.VintfRuntimeInfo; import android.text.TextUtils; import android.util.Pair; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -128,7 +129,7 @@ public class DeviceInfoUtils { final Pair v1 = getMajorMinorVersion(s1); final Pair v2 = getMajorMinorVersion(s2); - if (v1.first == v2.first) { + if (Objects.equals(v1.first, v2.first)) { return Integer.compare(v1.second, v2.second); } else { return Integer.compare(v1.first, v2.first); From 70c62e594a0ec0afec617a3b1245fa25b6b944fa Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 29 Sep 2022 20:06:44 +0900 Subject: [PATCH 569/777] [CC01] Remove the confusing pollForNextCallback In Java, "poll" methods return null when the collection is empty. Respect this convention. Bug: 157405399 Test: FrameworksNetTests Change-Id: I3b17908f9ce1f60b18908605a645da3199c010b9 --- .../testutils/TestableNetworkCallbackTest.kt | 23 ++++++++++---- .../testutils/TestableNetworkCallback.kt | 31 ++++++++++++++----- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt index 557f1fdbb7..690ef2e6c2 100644 --- a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt +++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt @@ -270,17 +270,29 @@ class TestableNetworkCallbackTest { } @Test - fun testPollForNextCallback() { - assertFails { mCallback.pollForNextCallback(SHORT_TIMEOUT_MS) } + fun testPoll() { + assertNull(mCallback.poll(SHORT_TIMEOUT_MS)) TNCInterpreter.interpretTestSpec(initial = mCallback, lineShift = 1, threadTransform = { cb -> cb.createLinkedCopy() }, spec = """ sleep; onAvailable(133) | poll(2) = Available(133) time 1..4 - | poll(1) fails + | poll(1) = null onCapabilitiesChanged(108) | poll(1) = CapabilitiesChanged(108) time 0..3 onBlockedStatus(199) | poll(1) = BlockedStatus(199) time 0..3 """) } + @Test + fun testPollOrThrow() { + assertFails { mCallback.pollOrThrow(SHORT_TIMEOUT_MS) } + TNCInterpreter.interpretTestSpec(initial = mCallback, lineShift = 1, + threadTransform = { cb -> cb.createLinkedCopy() }, spec = """ + sleep; onAvailable(133) | pollOrThrow(2) = Available(133) time 1..4 + | pollOrThrow(1) fails + onCapabilitiesChanged(108) | pollOrThrow(1) = CapabilitiesChanged(108) time 0..3 + onBlockedStatus(199) | pollOrThrow(1) = BlockedStatus(199) time 0..3 + """) + } + @Test fun testEventuallyExpect() { // TODO: Current test does not verify the inline one. Also verify the behavior after @@ -358,9 +370,8 @@ private val interpretTable = listOf>( else -> fail("Unknown callback type") } }, - Regex("""poll\((\d+)\)""") to { i, cb, t -> - cb.pollForNextCallback(t.timeArg(1)) - }, + Regex("""poll\((\d+)\)""") to { i, cb, t -> cb.poll(t.timeArg(1)) }, + Regex("""pollOrThrow\((\d+)\)""") to { i, cb, t -> cb.pollOrThrow(t.timeArg(1)) }, // Interpret "eventually(Available(xx), timeout)" as calling eventuallyExpect that expects // CallbackEntry.AVAILABLE with netId of xx within timeout*INTERPRET_TIME_UNIT timeout, and // likewise for all callback types. diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index 4407714d87..0c16937856 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -43,8 +43,6 @@ object NULL_NETWORK : Network(-1) object ANY_NETWORK : Network(-2) fun anyNetwork() = ANY_NETWORK -private val Int.capabilityName get() = NetworkCapabilities.capabilityNameOf(this) - open class RecorderCallback private constructor( private val backingRecord: ArrayTrackRecord ) : NetworkCallback() { @@ -193,9 +191,26 @@ open class TestableNetworkCallback private constructor( else -> null } - fun pollForNextCallback(timeoutMs: Long = defaultTimeoutMs): CallbackEntry { - return history.poll(timeoutMs) ?: fail("Did not receive callback after ${timeoutMs}ms") - } + /** + * Get the next callback or null if timeout. + * + * With no argument, this method waits out the default timeout. To wait forever, pass + * Long.MAX_VALUE. + */ + @JvmOverloads + fun poll(timeoutMs: Long = defaultTimeoutMs): CallbackEntry? = history.poll(timeoutMs) + + /** + * Get the next callback or throw if timeout. + * + * With no argument, this method waits out the default timeout. To wait forever, pass + * Long.MAX_VALUE. + */ + @JvmOverloads + fun pollOrThrow( + timeoutMs: Long = defaultTimeoutMs, + errorMsg: String = "Did not receive callback after $timeoutMs" + ): CallbackEntry = poll(timeoutMs) ?: fail(errorMsg) // Make open for use in ConnectivityServiceTest which is the only one knowing its handlers. // TODO : remove the necessity to overload this, remove the open qualifier, and give a @@ -221,7 +236,7 @@ open class TestableNetworkCallback private constructor( inline fun expectCallback( network: Network = ANY_NETWORK, timeoutMs: Long = defaultTimeoutMs - ): T = pollForNextCallback(timeoutMs).let { + ): T = pollOrThrow(timeoutMs).let { if (it !is T || (ANY_NETWORK !== network && it.network != network)) { fail("Unexpected callback : $it, expected ${T::class} with Network[$network]") } else { @@ -258,7 +273,7 @@ open class TestableNetworkCallback private constructor( fun expectCallbackThat( timeoutMs: Long = defaultTimeoutMs, valid: (CallbackEntry) -> Boolean - ) = pollForNextCallback(timeoutMs).also { assertTrue(valid(it), "Unexpected callback : $it") } + ) = pollOrThrow(timeoutMs).also { assertTrue(valid(it), "Unexpected callback : $it") } fun expectCapabilitiesThat( net: Network, @@ -392,7 +407,7 @@ open class TestableNetworkCallback private constructor( type: KClass, n: Network?, timeoutMs: Long = defaultTimeoutMs - ) = pollForNextCallback(timeoutMs).also { + ) = pollOrThrow(timeoutMs).also { val network = n ?: NULL_NETWORK // TODO : remove this .java access if the tests ever use kotlin-reflect. At the time of // this writing this would be the only use of this library in the tests. From b7e2284acf6e5e70a5f3b10d361b94f4fe32f000 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 30 Sep 2022 13:39:30 +0900 Subject: [PATCH 570/777] [CC03] Replace expectCallback* with expect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "callback" is redundant – it's a TestCallback object and it takes a type of callback anyway. "assertNextIs" is shorter than expectCallback, and more directly explicit than "expect", but it's also 3 words and very different from previous usage. Using expect() is a little bit less in-your-face obvious, but it's simple, familiar, and short. Test: CtsNetTestCases FrameworksNetIntegrationTests FrameworksNetTests NetworkStackTests Bug: 157405399 Change-Id: I6c8c85a8be3895dd8f0ef681faa4a8b2b4f2f493 --- .../testutils/TestableNetworkCallback.kt | 239 +++++++++++++----- 1 file changed, 174 insertions(+), 65 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index 0c16937856..a40e57dfbe 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -36,7 +36,6 @@ import com.android.testutils.RecorderCallback.CallbackEntry.Unavailable import kotlin.reflect.KClass import kotlin.test.assertEquals import kotlin.test.assertNotNull -import kotlin.test.assertTrue import kotlin.test.fail object NULL_NETWORK : Network(-1) @@ -212,6 +211,162 @@ open class TestableNetworkCallback private constructor( errorMsg: String = "Did not receive callback after $timeoutMs" ): CallbackEntry = poll(timeoutMs) ?: fail(errorMsg) + /***** + * AssertNextIs family of methods. + * These methods fetch the next callback and assert it matches the conditions : type, + * passed predicate. If no callback is received within the timeout, these methods fail. + */ + fun expect( + type: KClass, + network: Network = ANY_NETWORK, + timeoutMs: Long = defaultTimeoutMs, + errorMsg: String? = null, + test: (T) -> Boolean = { true } + ) = expect(network, timeoutMs, errorMsg) { + test(it as? T ?: fail("Expected callback ${type.simpleName}, got $it")) + } as T + + fun expect( + type: KClass, + network: HasNetwork, + timeoutMs: Long = defaultTimeoutMs, + errorMsg: String? = null, + test: (T) -> Boolean = { true } + ) = expect(type, network.network, timeoutMs, errorMsg, test) + + // Java needs an explicit overload to let it omit arguments in the middle, so define these + // here. Note that @JvmOverloads give us the versions without the last arguments too, so + // there is no need to explicitly define versions without the test predicate. + // Without |network| + @JvmOverloads + fun expect( + type: KClass, + timeoutMs: Long, + errorMsg: String?, + test: (T) -> Boolean = { true } + ) = expect(type, ANY_NETWORK, timeoutMs, errorMsg, test) + + // Without |timeout|, in Network and HasNetwork versions + @JvmOverloads + fun expect( + type: KClass, + network: Network, + errorMsg: String?, + test: (T) -> Boolean = { true } + ) = expect(type, network, defaultTimeoutMs, errorMsg, test) + + @JvmOverloads + fun expect( + type: KClass, + network: HasNetwork, + errorMsg: String?, + test: (T) -> Boolean = { true } + ) = expect(type, network.network, defaultTimeoutMs, errorMsg, test) + + // Without |errorMsg|, in Network and HasNetwork versions + @JvmOverloads + fun expect( + type: KClass, + network: Network, + timeoutMs: Long, + test: (T) -> Boolean = { true } + ) = expect(type, network, timeoutMs, null, test) + + @JvmOverloads + fun expect( + type: KClass, + network: HasNetwork, + timeoutMs: Long, + test: (T) -> Boolean = { true } + ) = expect(type, network.network, timeoutMs, null, test) + + // Without |network| or |timeout| + @JvmOverloads + fun expect( + type: KClass, + errorMsg: String?, + test: (T) -> Boolean = { true } + ) = expect(type, ANY_NETWORK, defaultTimeoutMs, errorMsg, test) + + // Without |network| or |errorMsg| + @JvmOverloads + fun expect( + type: KClass, + timeoutMs: Long, + test: (T) -> Boolean = { true } + ) = expect(type, ANY_NETWORK, timeoutMs, null, test) + + // Without |timeout| or |errorMsg|, in Network and HasNetwork versions + @JvmOverloads + fun expect( + type: KClass, + network: Network, + test: (T) -> Boolean = { true } + ) = expect(type, network, defaultTimeoutMs, null, test) + + @JvmOverloads + fun expect( + type: KClass, + network: HasNetwork, + test: (T) -> Boolean = { true } + ) = expect(type, network.network, defaultTimeoutMs, null, test) + + // Without |network| or |timeout| or |errorMsg| + @JvmOverloads + fun expect( + type: KClass, + test: (T) -> Boolean = { true } + ) = expect(type, ANY_NETWORK, defaultTimeoutMs, null, test) + + // Kotlin reified versions. Don't call methods above, or the predicate would need to be noinline + inline fun expect( + network: Network = ANY_NETWORK, + timeoutMs: Long = defaultTimeoutMs, + errorMsg: String? = null, + test: (T) -> Boolean = { true } + ) = pollOrThrow(timeoutMs).also { + if (it !is T) fail("Expected callback ${T::class.simpleName}, got $it") + if (ANY_NETWORK !== network && it.network != network) { + fail("Expected network $network for callback : $it") + } + if (!test(it)) { + fail("${errorMsg ?: "Callback doesn't match predicate"} : $it") + } + } as T + + inline fun expect( + network: HasNetwork, + timeoutMs: Long = defaultTimeoutMs, + errorMsg: String? = null, + test: (T) -> Boolean = { true } + ) = expect(network.network, timeoutMs, errorMsg, test) + + // TODO : remove all expectCallback and expectCallbackThat methods after all callers have been + // migrated to expect(). + inline fun expectCallback( + network: Network = ANY_NETWORK, + timeoutMs: Long = defaultTimeoutMs + ): T = expect(network, timeoutMs) + + @JvmOverloads + open fun expectCallback( + type: KClass, + n: Network?, + timeoutMs: Long = defaultTimeoutMs + ) = expect(type, n ?: ANY_NETWORK, timeoutMs) + + @JvmOverloads + open fun expectCallback( + type: KClass, + n: HasNetwork?, + timeoutMs: Long = defaultTimeoutMs + ) = expect(type, n?.network ?: ANY_NETWORK, timeoutMs) + + fun expectCallbackThat( + timeoutMs: Long = defaultTimeoutMs, + valid: (CallbackEntry) -> Boolean + ) = expect(timeoutMs = timeoutMs, test = valid) + // Make open for use in ConnectivityServiceTest which is the only one knowing its handlers. // TODO : remove the necessity to overload this, remove the open qualifier, and give a // default argument to assertNoCallback instead, possibly with @JvmOverloads if necessary. @@ -231,19 +386,6 @@ open class TestableNetworkCallback private constructor( } } - // Expects a callback of the specified type on the specified network within the timeout. - // If no callback arrives, or a different callback arrives, fail. Returns the callback. - inline fun expectCallback( - network: Network = ANY_NETWORK, - timeoutMs: Long = defaultTimeoutMs - ): T = pollOrThrow(timeoutMs).let { - if (it !is T || (ANY_NETWORK !== network && it.network != network)) { - fail("Unexpected callback : $it, expected ${T::class} with Network[$network]") - } else { - it - } - } - // Expects a callback of the specified type matching the predicate within the timeout. // Any callback that doesn't match the predicate will be skipped. Fails only if // no matching callback is received within the timeout. @@ -270,30 +412,19 @@ open class TestableNetworkCallback private constructor( crossinline predicate: (T) -> Boolean = { true } ) = history.poll(timeoutMs, from) { it is T && predicate(it) } as T? - fun expectCallbackThat( - timeoutMs: Long = defaultTimeoutMs, - valid: (CallbackEntry) -> Boolean - ) = pollOrThrow(timeoutMs).also { assertTrue(valid(it), "Unexpected callback : $it") } - - fun expectCapabilitiesThat( + inline fun expectCapabilitiesThat( net: Network, tmt: Long = defaultTimeoutMs, valid: (NetworkCapabilities) -> Boolean - ): CapabilitiesChanged { - return expectCallback(net, tmt).also { - assertTrue(valid(it.caps), "Capabilities don't match expectations ${it.caps}") - } - } + ): CapabilitiesChanged = + expect(net, tmt, "Capabilities don't match expectations") { valid(it.caps) } - fun expectLinkPropertiesThat( + inline fun expectLinkPropertiesThat( net: Network, tmt: Long = defaultTimeoutMs, valid: (LinkProperties) -> Boolean - ): LinkPropertiesChanged { - return expectCallback(net, tmt).also { - assertTrue(valid(it.lp), "LinkProperties don't match expectations ${it.lp}") - } - } + ): LinkPropertiesChanged = + expect(net, tmt, "LinkProperties don't match expectations") { valid(it.lp) } // Expects onAvailable and the callbacks that follow it. These are: // - onSuspended, iff the network was suspended when the callbacks fire. @@ -334,16 +465,16 @@ open class TestableNetworkCallback private constructor( validated: Boolean?, tmt: Long ) { - expectCallback(net, tmt) + expect(net, tmt) if (suspended) { - expectCallback(net, tmt) + expect(net, tmt) } expectCapabilitiesThat(net, tmt) { validated == null || validated == it.hasCapability( NET_CAPABILITY_VALIDATED ) } - expectCallback(net, tmt) + expect(net, tmt) } // Backward compatibility for existing Java code. Use named arguments instead and remove all @@ -354,17 +485,15 @@ open class TestableNetworkCallback private constructor( tmt: Long = defaultTimeoutMs ) = expectAvailableCallbacks(net, suspended = true, validated = validated, tmt = tmt) - fun expectBlockedStatusCallback(blocked: Boolean, net: Network, tmt: Long = defaultTimeoutMs) { - expectCallback(net, tmt).also { - assertEquals(blocked, it.blocked, "Unexpected blocked status ${it.blocked}") - } - } + fun expectBlockedStatusCallback(blocked: Boolean, net: Network, tmt: Long = defaultTimeoutMs) = + expect(net, tmt, "Unexpected blocked status") { + it.blocked == blocked + } - fun expectBlockedStatusCallback(blocked: Int, net: Network, tmt: Long = defaultTimeoutMs) { - expectCallback(net, tmt).also { - assertEquals(blocked, it.blocked, "Unexpected blocked status ${it.blocked}") - } - } + fun expectBlockedStatusCallback(blocked: Int, net: Network, tmt: Long = defaultTimeoutMs) = + expect(net, tmt, "Unexpected blocked status") { + it.blocked == blocked + } // Expects the available callbacks (where the onCapabilitiesChanged must contain the // VALIDATED capability), plus another onCapabilitiesChanged which is identical to the @@ -374,7 +503,7 @@ open class TestableNetworkCallback private constructor( val mark = history.mark expectAvailableCallbacks(net, tmt = tmt) val firstCaps = history.poll(tmt, mark) { it is CapabilitiesChanged } - assertEquals(firstCaps, expectCallback(net, tmt)) + assertEquals(firstCaps, expect(net, tmt)) } // Expects the available callbacks where the onCapabilitiesChanged must not have validated, @@ -402,26 +531,6 @@ open class TestableNetworkCallback private constructor( val network: Network } - @JvmOverloads - open fun expectCallback( - type: KClass, - n: Network?, - timeoutMs: Long = defaultTimeoutMs - ) = pollOrThrow(timeoutMs).also { - val network = n ?: NULL_NETWORK - // TODO : remove this .java access if the tests ever use kotlin-reflect. At the time of - // this writing this would be the only use of this library in the tests. - assertTrue(type.java.isInstance(it) && (ANY_NETWORK === n || it.network == network), - "Unexpected callback : $it, expected ${type.java} with Network[$network]") - } as T - - @JvmOverloads - open fun expectCallback( - type: KClass, - n: HasNetwork?, - timeoutMs: Long = defaultTimeoutMs - ) = expectCallback(type, n?.network, timeoutMs) - fun expectAvailableCallbacks( n: HasNetwork, suspended: Boolean, From f79ca2809a9a7bc2f6b705ff558b7bf7984b79f7 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 19 Oct 2022 15:46:35 +0900 Subject: [PATCH 571/777] [CC04] Have TestNetworkTracker implement HasNetwork This already has all necessary methods, it only needs to declare it implements the interface. Test: ConnectivityServiceTest Change-Id: I8de643f2b8de9765c25c3efe934c94549f341a51 --- .../devicetests/com/android/testutils/TestNetworkTracker.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt index 5ae2439d9e..b743b6c922 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt @@ -111,12 +111,12 @@ class TestNetworkTracker internal constructor( val tnm: TestNetworkManager, val lp: LinkProperties?, setupTimeoutMs: Long -) { +) : TestableNetworkCallback.HasNetwork { private val cm = context.getSystemService(ConnectivityManager::class.java) private val binder = Binder() private val networkCallback: NetworkCallback - val network: Network + override val network: Network val testIface: TestNetworkInterface init { From dd3fe1d750c489917aaa341c924fa091e37f1062 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 20 Oct 2022 04:05:00 +0000 Subject: [PATCH 572/777] add DEFINE_BPF_MAP_RO for output maps which userspace should never modify MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 254543135 Signed-off-by: Maciej Żenczykowski Change-Id: I94c5e68e8941a264ea3671f75e3ad9c37ded8894 --- staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 6eb8aa7f45..2d51702cf5 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -209,6 +209,10 @@ static int (*bpf_for_each_map_elem)(const struct bpf_map_def* map, void *callbac DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \ DEFAULT_BPF_MAP_UID, AID_ROOT, 0600) +#define DEFINE_BPF_MAP_RO(the_map, TYPE, KeyType, ValueType, num_entries, gid) \ + DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \ + DEFAULT_BPF_MAP_UID, gid, 0440) + #define DEFINE_BPF_MAP_GWO(the_map, TYPE, KeyType, ValueType, num_entries, gid) \ DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \ DEFAULT_BPF_MAP_UID, gid, 0620) From 347dd8ded4225f2c21e2fddd867316e87f80d7a2 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 20 Oct 2022 16:29:06 +0900 Subject: [PATCH 573/777] Increase the timeout for eventuallyExpect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sometimes the tests are run under high load, e.g. immediately after boot while all apps that listen for the boot completed broadcast run their listeners. Under these circumstances, 40ms of leeway is tight ; on recent Android devices HZ is commonly 100 too, meaning a general time unit of 60 will give a little bit of air. The drawback in this is that the test is less stringent on TrackRecord, which as a multi-thread primitive should have really tight tests to make sure that a non-threading primitive (e.g. a polling implementation) doesn't pass. This patch makes the testing on that front a little bit less reliable. Note that this patch won't actually fix all flakes in that it isn't really possible to guarantee the device will have any CPU time to run the test at all anyway, but this should make most failures go away. Also, the argument for the time unit is never used, and can be removed ; at least, the possibility of the timeArg() func not using the same value as the sleep directive is scary, so that possibility should be removed. If the time unit argument is ever needed it can be added back, but considering the arg has been available for years and never used, it's unlikely. Test: NetworkStaticLibTests Fixes: 254188131 Change-Id: Ia7a4fe775942484dcd7dc223c7710e82a8329beb --- .../src/com/android/net/module/util/TrackRecordTest.kt | 3 ++- .../com/android/testutils/TestableNetworkCallbackTest.kt | 4 ++-- .../com/android/testutils/ConcurrentInterpreter.kt | 9 +++------ 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/TrackRecordTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/TrackRecordTest.kt index 9fb4d8caac..8e320d0d4e 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/TrackRecordTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/TrackRecordTest.kt @@ -17,6 +17,7 @@ package com.android.net.module.util import com.android.testutils.ConcurrentInterpreter +import com.android.testutils.INTERPRET_TIME_UNIT import com.android.testutils.InterpretException import com.android.testutils.InterpretMatcher import com.android.testutils.SyntaxException @@ -420,7 +421,7 @@ private val interpretTable = listOf>>( // the test code to not compile instead of throw, but it's vastly more complex and this will // fail 100% at runtime any test that would not have compiled. Regex("""poll\((\d+)?\)\s*(\{.*\})?""") to { i, t, r -> - (if (r.strArg(1).isEmpty()) i.interpretTimeUnit else r.timeArg(1)).let { time -> + (if (r.strArg(1).isEmpty()) INTERPRET_TIME_UNIT else r.timeArg(1)).let { time -> (t as ArrayTrackRecord.ReadHead).poll(time, makePredicate(r.strArg(2))) } }, diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt index 690ef2e6c2..a78a078e12 100644 --- a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt +++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt @@ -322,9 +322,9 @@ class TestableNetworkCallbackTest { TNCInterpreter.interpretTestSpec(initial = mCallback, lineShift = 1, threadTransform = { cb -> cb.createLinkedCopy() }, spec = """ onAvailable(100) | eventually(CapabilitiesChanged(100), 1) fails - sleep ; onCapabilitiesChanged(100) | eventually(CapabilitiesChanged(100), 2) + sleep ; onCapabilitiesChanged(100) | eventually(CapabilitiesChanged(100), 3) onAvailable(101) ; onBlockedStatus(101) | eventually(BlockedStatus(100), 2) fails - onSuspended(100) ; sleep ; onLost(100) | eventually(Lost(100), 2) + onSuspended(100) ; sleep ; onLost(100) | eventually(Lost(100), 3) """) } } diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt b/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt index cbdc01730f..9e72f4b4e6 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/ConcurrentInterpreter.kt @@ -13,7 +13,7 @@ import kotlin.test.assertTrue typealias InterpretMatcher = Pair, T, MatchResult) -> Any?> // The default unit of time for interpreted tests -val INTERPRET_TIME_UNIT = 40L // ms +const val INTERPRET_TIME_UNIT = 60L // ms /** * A small interpreter for testing parallel code. @@ -40,10 +40,7 @@ val INTERPRET_TIME_UNIT = 40L // ms * Some expressions already exist by default and can be used by all interpreters. Refer to * getDefaultInstructions() below for a list and documentation. */ -open class ConcurrentInterpreter( - localInterpretTable: List>, - val interpretTimeUnit: Long = INTERPRET_TIME_UNIT -) { +open class ConcurrentInterpreter(localInterpretTable: List>) { private val interpretTable: List> = localInterpretTable + getDefaultInstructions() // The last time the thread became blocked, with base System.currentTimeMillis(). This should @@ -211,7 +208,7 @@ private fun getDefaultInstructions() = listOf>( }, // Interpret sleep. Optional argument for the count, in INTERPRET_TIME_UNIT units. Regex("""sleep(\((\d+)\))?""") to { i, t, r -> - SystemClock.sleep(if (r.strArg(2).isEmpty()) i.interpretTimeUnit else r.timeArg(2)) + SystemClock.sleep(if (r.strArg(2).isEmpty()) INTERPRET_TIME_UNIT else r.timeArg(2)) }, Regex("""(.*)\s*fails""") to { i, t, r -> assertFails { i.interpret(r.strArg(1), t) } From 6f9830c342568c12bcf7e602eeff5444c5da7581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 20 Oct 2022 23:45:10 +0000 Subject: [PATCH 574/777] Disallow pre-T use of userspace writable bpf map arrays with more than 1 element. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 254543135 Signed-off-by: Maciej Żenczykowski Change-Id: I11ea5edaebf08f3492ad79f059afa98b50f80df3 --- .../bpf_headers/include/bpf/bpf_helpers.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 2d51702cf5..56bc7d0103 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -151,6 +151,23 @@ static int (*bpf_for_each_map_elem)(const struct bpf_map_def* map, void *callbac __attribute__ ((section(".maps." #name), used)) \ ____btf_map_##name = { } +/* There exist buggy kernels with pre-T OS, that due to + * kernel patch "[ALPS05162612] bpf: fix ubsan error" + * do not support userspace writes into non-zero index of bpf map arrays. + * + * We use this assert to prevent us from being able to define such a map. + */ + +#ifdef THIS_BPF_PROGRAM_IS_FOR_TEST_PURPOSES_ONLY +#define BPF_MAP_ASSERT_OK(type, entries, mode) +#elif BPFLOADER_MIN_VER >= BPFLOADER_T_BETA3_VERSION +#define BPF_MAP_ASSERT_OK(type, entries, mode) +#else +#define BPF_MAP_ASSERT_OK(type, entries, mode) \ + _Static_assert(((type) != BPF_MAP_TYPE_ARRAY) || ((entries) <= 1) || !((mode) & 0222), \ + "Writable arrays with more than 1 element not supported on pre-T devices.") +#endif + /* type safe macro to declare a map and related accessor functions */ #define DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, \ selinux, pindir, share) \ @@ -171,6 +188,7 @@ static int (*bpf_for_each_map_elem)(const struct bpf_map_def* map, void *callbac .pin_subdir = pindir, \ .shared = share, \ }; \ + BPF_MAP_ASSERT_OK(BPF_MAP_TYPE_##TYPE, (num_entries), (md)); \ BPF_ANNOTATE_KV_PAIR(the_map, KeyType, ValueType); \ \ static inline __always_inline __unused ValueType* bpf_##the_map##_lookup_elem( \ From 3ad176b03ac55f4252e23588e3b2617217906d7e Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 21 Oct 2022 11:53:13 +0900 Subject: [PATCH 575/777] [CC06] Move usage of expectCallback* to expect See CC03 (aosp/2255619) for details Test: NettworkStaticLibTests Change-Id: Id15560f5744024ff2ac2acbaf4de83818ce6efc5 --- .../testutils/TestableNetworkCallbackTest.kt | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt index a78a078e12..1866d2e643 100644 --- a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt +++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt @@ -160,23 +160,23 @@ class TestableNetworkCallbackTest { } @Test - fun testExpectCallbackThat() { + fun testExpectWithPredicate() { val net = Network(193) val netCaps = NetworkCapabilities().addTransportType(CELLULAR) // Check that expecting callbackThat anything fails when no callback has been received. - assertFails { mCallback.expectCallbackThat(SHORT_TIMEOUT_MS) { true } } + assertFails { mCallback.expect(timeoutMs = SHORT_TIMEOUT_MS) { true } } // Basic test for true and false mCallback.onAvailable(net) - mCallback.expectCallbackThat { true } + mCallback.expect { true } mCallback.onAvailable(net) - assertFails { mCallback.expectCallbackThat(SHORT_TIMEOUT_MS) { false } } + assertFails { mCallback.expect(timeoutMs = SHORT_TIMEOUT_MS) { false } } // Try a positive and a negative case mCallback.onBlockedStatusChanged(net, true) - mCallback.expectCallbackThat { cb -> cb is BlockedStatus && cb.blocked } + mCallback.expect { cb -> cb is BlockedStatus && cb.blocked } mCallback.onCapabilitiesChanged(net, netCaps) - assertFails { mCallback.expectCallbackThat(SHORT_TIMEOUT_MS) { cb -> + assertFails { mCallback.expect(timeoutMs = SHORT_TIMEOUT_MS) { cb -> cb is CapabilitiesChanged && cb.caps.hasTransport(WIFI) } } } @@ -251,22 +251,22 @@ class TestableNetworkCallbackTest { } @Test - fun testExpectCallback() { + fun testExpect() { val net = Network(103) // Test expectCallback fails when nothing was sent. - assertFails { mCallback.expectCallback(net, SHORT_TIMEOUT_MS) } + assertFails { mCallback.expect(net, SHORT_TIMEOUT_MS) } // Test onAvailable is seen and can be expected mCallback.onAvailable(net) - mCallback.expectCallback(net, SHORT_TIMEOUT_MS) + mCallback.expect(net, SHORT_TIMEOUT_MS) // Test onAvailable won't return calls with a different network mCallback.onAvailable(Network(106)) - assertFails { mCallback.expectCallback(net, SHORT_TIMEOUT_MS) } + assertFails { mCallback.expect(net, SHORT_TIMEOUT_MS) } // Test onAvailable won't return calls with a different callback mCallback.onAvailable(net) - assertFails { mCallback.expectCallback(net, SHORT_TIMEOUT_MS) } + assertFails { mCallback.expect(net, SHORT_TIMEOUT_MS) } } @Test From 6f8bcae7d0d3ff4935ef083831c1e80bd8d1f484 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 24 Oct 2022 17:52:57 +0900 Subject: [PATCH 576/777] [CC07] Add build tests for expect* versions Also address some comments left on a previous patchset. Test: NetworkStaticLibTests Change-Id: I3ea16bb54aec31ddb0368af980483109a1bdb49b --- .../testutils/TestableNetworkCallbackTest.kt | 81 +++++++++++++++++++ .../TestableNetworkCallbackTestJava.java | 76 +++++++++++++++++ .../testutils/TestableNetworkCallback.kt | 14 ++-- 3 files changed, 165 insertions(+), 6 deletions(-) create mode 100644 staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTestJava.java diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt index 1866d2e643..f8f2da085b 100644 --- a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt +++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt @@ -38,6 +38,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +import org.junit.Assume.assumeTrue import kotlin.reflect.KClass import kotlin.test.assertEquals import kotlin.test.assertFails @@ -269,6 +270,86 @@ class TestableNetworkCallbackTest { assertFails { mCallback.expect(net, SHORT_TIMEOUT_MS) } } + @Test + fun testAllExpectOverloads() { + // This test should never run, it only checks that all overloads exist and build + assumeTrue(false) + val hn = object : TestableNetworkCallback.HasNetwork { override val network = ANY_NETWORK } + + // Method with all arguments (version that takes a Network) + mCallback.expect(AVAILABLE, ANY_NETWORK, 10, "error") { true } + + // Java overloads omitting one argument. One line for omitting each argument, in positional + // order. Versions that take a Network. + mCallback.expect(AVAILABLE, 10, "error") { true } + mCallback.expect(AVAILABLE, ANY_NETWORK, "error") { true } + mCallback.expect(AVAILABLE, ANY_NETWORK, 10) { true } + mCallback.expect(AVAILABLE, ANY_NETWORK, 10, "error") + + // Java overloads for omitting two arguments. One line for omitting each pair of arguments. + // Versions that take a Network. + mCallback.expect(AVAILABLE, "error") { true } + mCallback.expect(AVAILABLE, 10) { true } + mCallback.expect(AVAILABLE, 10, "error") + mCallback.expect(AVAILABLE, ANY_NETWORK) { true } + mCallback.expect(AVAILABLE, ANY_NETWORK, "error") + mCallback.expect(AVAILABLE, ANY_NETWORK, 10) + + // Java overloads for omitting three arguments. One line for each remaining argument. + // Versions that take a Network. + mCallback.expect(AVAILABLE) { true } + mCallback.expect(AVAILABLE, "error") + mCallback.expect(AVAILABLE, 10) + mCallback.expect(AVAILABLE, ANY_NETWORK) + + // Java overload for omitting all four arguments. + mCallback.expect(AVAILABLE) + + // Same orders as above, but versions that take a HasNetwork. Except overloads that + // were already tested because they omitted the Network argument + mCallback.expect(AVAILABLE, hn, 10, "error") { true } + mCallback.expect(AVAILABLE, hn, "error") { true } + mCallback.expect(AVAILABLE, hn, 10) { true } + mCallback.expect(AVAILABLE, hn, 10, "error") + + mCallback.expect(AVAILABLE, hn) { true } + mCallback.expect(AVAILABLE, hn, "error") + mCallback.expect(AVAILABLE, hn, 10) + + mCallback.expect(AVAILABLE, hn) + + // Same as above but for reified versions. + mCallback.expect(ANY_NETWORK, 10, "error") { true } + mCallback.expect(timeoutMs = 10, errorMsg = "error") { true } + mCallback.expect(network = ANY_NETWORK, errorMsg = "error") { true } + mCallback.expect(network = ANY_NETWORK, timeoutMs = 10) { true } + mCallback.expect(network = ANY_NETWORK, timeoutMs = 10, errorMsg = "error") + + mCallback.expect(errorMsg = "error") { true } + mCallback.expect(timeoutMs = 10) { true } + mCallback.expect(timeoutMs = 10, errorMsg = "error") + mCallback.expect(network = ANY_NETWORK) { true } + mCallback.expect(network = ANY_NETWORK, errorMsg = "error") + mCallback.expect(network = ANY_NETWORK, timeoutMs = 10) + + mCallback.expect { true } + mCallback.expect(errorMsg = "error") + mCallback.expect(timeoutMs = 10) + mCallback.expect(network = ANY_NETWORK) + mCallback.expect() + + mCallback.expect(hn, 10, "error") { true } + mCallback.expect(network = hn, errorMsg = "error") { true } + mCallback.expect(network = hn, timeoutMs = 10) { true } + mCallback.expect(network = hn, timeoutMs = 10, errorMsg = "error") + + mCallback.expect(network = hn) { true } + mCallback.expect(network = hn, errorMsg = "error") + mCallback.expect(network = hn, timeoutMs = 10) + + mCallback.expect(network = hn) + } + @Test fun testPoll() { assertNull(mCallback.poll(SHORT_TIMEOUT_MS)) diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTestJava.java b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTestJava.java new file mode 100644 index 0000000000..4570d0aecb --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTestJava.java @@ -0,0 +1,76 @@ +/* + * 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 com.android.testutils; + +import static com.android.testutils.RecorderCallback.CallbackEntry.AVAILABLE; +import static com.android.testutils.TestableNetworkCallbackKt.anyNetwork; + +import static org.junit.Assume.assumeTrue; + +import org.junit.Test; + +public class TestableNetworkCallbackTestJava { + @Test + void testAllExpectOverloads() { + // This test should never run, it only checks that all overloads exist and build + assumeTrue(false); + final TestableNetworkCallback callback = new TestableNetworkCallback(); + TestableNetworkCallback.HasNetwork hn = TestableNetworkCallbackKt::anyNetwork; + + // Method with all arguments (version that takes a Network) + callback.expect(AVAILABLE, anyNetwork(), 10, "error", cb -> true); + + // Overloads omitting one argument. One line for omitting each argument, in positional + // order. Versions that take a Network. + callback.expect(AVAILABLE, 10, "error", cb -> true); + callback.expect(AVAILABLE, anyNetwork(), "error", cb -> true); + callback.expect(AVAILABLE, anyNetwork(), 10, cb -> true); + callback.expect(AVAILABLE, anyNetwork(), 10, "error"); + + // Overloads for omitting two arguments. One line for omitting each pair of arguments. + // Versions that take a Network. + callback.expect(AVAILABLE, "error", cb -> true); + callback.expect(AVAILABLE, 10, cb -> true); + callback.expect(AVAILABLE, 10, "error"); + callback.expect(AVAILABLE, anyNetwork(), cb -> true); + callback.expect(AVAILABLE, anyNetwork(), "error"); + callback.expect(AVAILABLE, anyNetwork(), 10); + + // Overloads for omitting three arguments. One line for each remaining argument. + // Versions that take a Network. + callback.expect(AVAILABLE, cb -> true); + callback.expect(AVAILABLE, "error"); + callback.expect(AVAILABLE, 10); + callback.expect(AVAILABLE, anyNetwork()); + + // Java overload for omitting all four arguments. + callback.expect(AVAILABLE); + + // Same orders as above, but versions that take a HasNetwork. Except overloads that + // were already tested because they omitted the Network argument + callback.expect(AVAILABLE, hn, 10, "error", cb -> true); + callback.expect(AVAILABLE, hn, "error", cb -> true); + callback.expect(AVAILABLE, hn, 10, cb -> true); + callback.expect(AVAILABLE, hn, 10, "error"); + + callback.expect(AVAILABLE, hn, cb -> true); + callback.expect(AVAILABLE, hn, "error"); + callback.expect(AVAILABLE, hn, 10); + + callback.expect(AVAILABLE, hn); + } +} diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index a40e57dfbe..406a179cd9 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -212,10 +212,11 @@ open class TestableNetworkCallback private constructor( ): CallbackEntry = poll(timeoutMs) ?: fail(errorMsg) /***** - * AssertNextIs family of methods. + * expect family of methods. * These methods fetch the next callback and assert it matches the conditions : type, * passed predicate. If no callback is received within the timeout, these methods fail. */ + @JvmOverloads fun expect( type: KClass, network: Network = ANY_NETWORK, @@ -226,6 +227,7 @@ open class TestableNetworkCallback private constructor( test(it as? T ?: fail("Expected callback ${type.simpleName}, got $it")) } as T + @JvmOverloads fun expect( type: KClass, network: HasNetwork, @@ -269,7 +271,7 @@ open class TestableNetworkCallback private constructor( type: KClass, network: Network, timeoutMs: Long, - test: (T) -> Boolean = { true } + test: (T) -> Boolean ) = expect(type, network, timeoutMs, null, test) @JvmOverloads @@ -277,7 +279,7 @@ open class TestableNetworkCallback private constructor( type: KClass, network: HasNetwork, timeoutMs: Long, - test: (T) -> Boolean = { true } + test: (T) -> Boolean ) = expect(type, network.network, timeoutMs, null, test) // Without |network| or |timeout| @@ -301,21 +303,21 @@ open class TestableNetworkCallback private constructor( fun expect( type: KClass, network: Network, - test: (T) -> Boolean = { true } + test: (T) -> Boolean ) = expect(type, network, defaultTimeoutMs, null, test) @JvmOverloads fun expect( type: KClass, network: HasNetwork, - test: (T) -> Boolean = { true } + test: (T) -> Boolean ) = expect(type, network.network, defaultTimeoutMs, null, test) // Without |network| or |timeout| or |errorMsg| @JvmOverloads fun expect( type: KClass, - test: (T) -> Boolean = { true } + test: (T) -> Boolean ) = expect(type, ANY_NETWORK, defaultTimeoutMs, null, test) // Kotlin reified versions. Don't call methods above, or the predicate would need to be noinline From 0eac837b012e93b6a48b0a648d4b1f63db3bd259 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 21 Oct 2022 11:54:55 +0900 Subject: [PATCH 577/777] [CC08] Remove expectCallback* These methods have been migrated to the shorter and better provisioned expect<> family of methods. Test: Builds Change-Id: I60c77bfeabe373557d61f0f8d0295b385fe5271e --- .../testutils/TestableNetworkCallback.kt | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index 406a179cd9..e86ea98279 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -343,32 +343,6 @@ open class TestableNetworkCallback private constructor( test: (T) -> Boolean = { true } ) = expect(network.network, timeoutMs, errorMsg, test) - // TODO : remove all expectCallback and expectCallbackThat methods after all callers have been - // migrated to expect(). - inline fun expectCallback( - network: Network = ANY_NETWORK, - timeoutMs: Long = defaultTimeoutMs - ): T = expect(network, timeoutMs) - - @JvmOverloads - open fun expectCallback( - type: KClass, - n: Network?, - timeoutMs: Long = defaultTimeoutMs - ) = expect(type, n ?: ANY_NETWORK, timeoutMs) - - @JvmOverloads - open fun expectCallback( - type: KClass, - n: HasNetwork?, - timeoutMs: Long = defaultTimeoutMs - ) = expect(type, n?.network ?: ANY_NETWORK, timeoutMs) - - fun expectCallbackThat( - timeoutMs: Long = defaultTimeoutMs, - valid: (CallbackEntry) -> Boolean - ) = expect(timeoutMs = timeoutMs, test = valid) - // Make open for use in ConnectivityServiceTest which is the only one knowing its handlers. // TODO : remove the necessity to overload this, remove the open qualifier, and give a // default argument to assertNoCallback instead, possibly with @JvmOverloads if necessary. From 528e675fdd0397c65b8edfd02aec34dfafb29f29 Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Thu, 20 Oct 2022 13:23:30 +0000 Subject: [PATCH 578/777] Add ByteUtils for byte utility functions Bug: 254155029 Test: atest NetworkStaticLibTests Change-Id: I996ead6f23698313828e844672de5917efdfce69 --- .../android/net/module/util/ByteUtils.java | 68 +++++++++++++++++++ .../android/net/module/util/ByteUtilsTests.kt | 54 +++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 staticlibs/framework/com/android/net/module/util/ByteUtils.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/ByteUtilsTests.kt diff --git a/staticlibs/framework/com/android/net/module/util/ByteUtils.java b/staticlibs/framework/com/android/net/module/util/ByteUtils.java new file mode 100644 index 0000000000..33249757ba --- /dev/null +++ b/staticlibs/framework/com/android/net/module/util/ByteUtils.java @@ -0,0 +1,68 @@ +/* + * 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 com.android.net.module.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +/** + * Byte utility functions. + * @hide + */ +public class ByteUtils { + /** + * Returns the index of the first appearance of the value {@code target} in {@code array}. + * + * @param array an array of {@code byte} values, possibly empty + * @param target a primitive {@code byte} value + * @return the least index {@code i} for which {@code array[i] == target}, or {@code -1} if no + * such index exists. + */ + public static int indexOf(@NonNull byte[] array, @Nullable byte target) { + return indexOf(array, target, 0, array.length); + } + + private static int indexOf(byte[] array, byte target, int start, int end) { + for (int i = start; i < end; i++) { + if (array[i] == target) { + return i; + } + } + return -1; + } + + /** + * Returns the values from each provided array combined into a single array. For example, {@code + * concat(new byte[] {a, b}, new byte[] {}, new byte[] {c}} returns the array {@code {a, b, c}}. + * + * @param arrays zero or more {@code byte} arrays + * @return a single array containing all the values from the source arrays, in order + */ + public static byte[] concat(@NonNull byte[]... arrays) { + int length = 0; + for (byte[] array : arrays) { + length += array.length; + } + byte[] result = new byte[length]; + int pos = 0; + for (byte[] array : arrays) { + System.arraycopy(array, 0, result, pos, array.length); + pos += array.length; + } + return result; + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/ByteUtilsTests.kt b/staticlibs/tests/unit/src/com/android/net/module/util/ByteUtilsTests.kt new file mode 100644 index 0000000000..e58adad3cc --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/ByteUtilsTests.kt @@ -0,0 +1,54 @@ +/* + * 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 com.android.net.module.util + +import com.android.net.module.util.ByteUtils.indexOf +import com.android.net.module.util.ByteUtils.concat +import org.junit.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertNotSame + +class ByteUtilsTests { + private val EMPTY = byteArrayOf() + private val ARRAY1 = byteArrayOf(1) + private val ARRAY234 = byteArrayOf(2, 3, 4) + + @Test + fun testIndexOf() { + assertEquals(-1, indexOf(EMPTY, 1)) + assertEquals(-1, indexOf(ARRAY1, 2)) + assertEquals(-1, indexOf(ARRAY234, 1)) + assertEquals(0, indexOf(byteArrayOf(-1), -1)) + assertEquals(0, indexOf(ARRAY234, 2)) + assertEquals(1, indexOf(ARRAY234, 3)) + assertEquals(2, indexOf(ARRAY234, 4)) + assertEquals(1, indexOf(byteArrayOf(2, 3, 2, 3), 3)) + } + + @Test + fun testConcat() { + assertContentEquals(EMPTY, concat()) + assertContentEquals(EMPTY, concat(EMPTY)) + assertContentEquals(EMPTY, concat(EMPTY, EMPTY, EMPTY)) + assertContentEquals(ARRAY1, concat(ARRAY1)) + assertNotSame(ARRAY1, concat(ARRAY1)) + assertContentEquals(ARRAY1, concat(EMPTY, ARRAY1, EMPTY)) + assertContentEquals(byteArrayOf(1, 1, 1), concat(ARRAY1, ARRAY1, ARRAY1)) + assertContentEquals(byteArrayOf(1, 2, 3, 4), concat(ARRAY1, ARRAY234)) + } +} \ No newline at end of file From 52605df5fd274a7a2e1aa2924a9c93a075e31a28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 25 Oct 2022 09:24:32 +0000 Subject: [PATCH 579/777] remove SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit as this does not appear to be used anywhere anymore Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I95939b0b6c66f41f776ca31ea7178bb30241b81f --- staticlibs/native/bpf_headers/include/bpf/BpfUtils.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index 4429164ee5..1eb3aebb47 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -127,12 +127,6 @@ static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsign GTEST_SKIP() << "Skip: bpf is not supported."; \ } while (0) -#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED \ - do { \ - if (!android::bpf::isAtLeastKernelVersion(4, 14, 0)) \ - GTEST_SKIP() << "Skip: extended bpf feature not supported."; \ - } while (0) - #define SKIP_IF_XDP_NOT_SUPPORTED \ do { \ if (!android::bpf::isAtLeastKernelVersion(5, 9, 0)) \ From 5897a805ea4f1347e259cb4c26b3a42da46e83ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 25 Oct 2022 09:26:52 +0000 Subject: [PATCH 580/777] remove SKIP_IF_BPF_SUPPORTED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit as this does not appear to be used anywhere anymore Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I6905c6fdb4daf48df07e758481368d441637ad13 --- staticlibs/native/bpf_headers/include/bpf/BpfUtils.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index 4429164ee5..0489a4c681 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -115,12 +115,6 @@ static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsign return kernelVersion() >= KVER(major, minor, sub); } -#define SKIP_IF_BPF_SUPPORTED \ - do { \ - if (android::bpf::isAtLeastKernelVersion(4, 9, 0)) \ - GTEST_SKIP() << "Skip: bpf is supported."; \ - } while (0) - #define SKIP_IF_BPF_NOT_SUPPORTED \ do { \ if (!android::bpf::isAtLeastKernelVersion(4, 9, 0)) \ From 33f1f3f74c7efc325211699eca3162b60f0cae9d Mon Sep 17 00:00:00 2001 From: Chris Sabotta Date: Tue, 25 Oct 2022 23:31:10 +0000 Subject: [PATCH 581/777] Bug: b/255652639 Revert "remove SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED" This reverts commit 319d8468ad90d33307ce764e7f6130587ce81419. Reason for revert: Build breakage, (First bad build: 9217822) Change-Id: I0db2bdb68006f9379bb149f7de9fa81ace501c3d --- staticlibs/native/bpf_headers/include/bpf/BpfUtils.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index 1eb3aebb47..4429164ee5 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -127,6 +127,12 @@ static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsign GTEST_SKIP() << "Skip: bpf is not supported."; \ } while (0) +#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED \ + do { \ + if (!android::bpf::isAtLeastKernelVersion(4, 14, 0)) \ + GTEST_SKIP() << "Skip: extended bpf feature not supported."; \ + } while (0) + #define SKIP_IF_XDP_NOT_SUPPORTED \ do { \ if (!android::bpf::isAtLeastKernelVersion(5, 9, 0)) \ From 203d5e0dcd6c735da39248c3ee13a5e3e8c662e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 26 Oct 2022 00:11:16 +0000 Subject: [PATCH 582/777] trivialize SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 255652639 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I3732bbd7ad9e4e06c914206560268bd1ce8204f4 --- staticlibs/native/bpf_headers/include/bpf/BpfUtils.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index 0489a4c681..157f210c83 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -121,11 +121,10 @@ static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsign GTEST_SKIP() << "Skip: bpf is not supported."; \ } while (0) -#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED \ - do { \ - if (!android::bpf::isAtLeastKernelVersion(4, 14, 0)) \ - GTEST_SKIP() << "Skip: extended bpf feature not supported."; \ - } while (0) +// Only used by tm-mainline-prod's system/netd/tests/bpf_base_test.cpp +// but platform and platform tests aren't expected to build/work in tm-mainline-prod +// so we can just trivialize this +#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED #define SKIP_IF_XDP_NOT_SUPPORTED \ do { \ From b5e9e3fc2b9aa514aff7f387746069c5dd12960b Mon Sep 17 00:00:00 2001 From: chiachangwang Date: Fri, 28 Oct 2022 00:36:54 +0000 Subject: [PATCH 583/777] Add debug log in ensureWifiConnected It's sometimes not clear that tests call ensureWifiConnected but no wifi enabled. It's hard to clarify design with wifi stack, so add the gotten wifi info in the log to help on debugging. Bug: 252869312 Test: atest CtsNetTestCases Change-Id: I3bc74dd38dd5a36a93510fc5d70c0fa00b66e842 --- .../testutils/devicetests/com/android/testutils/ConnectUtil.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt index 7e92af112c..7b5ad0107c 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt @@ -63,6 +63,7 @@ class ConnectUtil(private val context: Context) { try { val connInfo = wifiManager.connectionInfo + Log.d(TAG, "connInfo=" + connInfo) if (connInfo == null || connInfo.networkId == -1) { clearWifiBlocklist() val pfd = getInstrumentation().uiAutomation.executeShellCommand("svc wifi enable") From e57ae65216a976fc026c58166b129a0f7d911f96 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 31 Oct 2022 08:01:26 +0000 Subject: [PATCH 584/777] Remove @Nullable from byte Primitive types can't be null. Change-Id: Idc2a30b1faae69213bc3bd7262f72d4ec23e1c40 Test: m --- .../framework/com/android/net/module/util/ByteUtils.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/ByteUtils.java b/staticlibs/framework/com/android/net/module/util/ByteUtils.java index 33249757ba..290ed465c1 100644 --- a/staticlibs/framework/com/android/net/module/util/ByteUtils.java +++ b/staticlibs/framework/com/android/net/module/util/ByteUtils.java @@ -17,7 +17,6 @@ package com.android.net.module.util; import android.annotation.NonNull; -import android.annotation.Nullable; /** * Byte utility functions. @@ -32,7 +31,7 @@ public class ByteUtils { * @return the least index {@code i} for which {@code array[i] == target}, or {@code -1} if no * such index exists. */ - public static int indexOf(@NonNull byte[] array, @Nullable byte target) { + public static int indexOf(@NonNull byte[] array, byte target) { return indexOf(array, target, 0, array.length); } From be99103196c25c34ccd55d3a8af95479e52ecff1 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 9 Aug 2022 14:36:59 +0800 Subject: [PATCH 585/777] [ST03] Add test dns server for integration tests Bug: 139774492 Test: atest DnsAnswerProviderTest TestDnsServerTest Change-Id: Ia5039a47f4b818efb09aab8174beb9d921339c3d --- .../android/testutils/TestDnsServerTest.kt | 122 +++++++++++++ .../android/testutils/DnsAnswerProvider.kt | 65 +++++++ .../com/android/testutils/TestDnsServer.kt | 169 ++++++++++++++++++ 3 files changed, 356 insertions(+) create mode 100644 staticlibs/tests/unit/src/com/android/testutils/TestDnsServerTest.kt create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/DnsAnswerProvider.kt create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/TestDnsServer.kt diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestDnsServerTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestDnsServerTest.kt new file mode 100644 index 0000000000..6f4587b140 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/testutils/TestDnsServerTest.kt @@ -0,0 +1,122 @@ +/* + * 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 com.android.testutils + +import android.net.DnsResolver.CLASS_IN +import android.net.DnsResolver.TYPE_AAAA +import android.net.Network +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.net.module.util.DnsPacket +import com.android.net.module.util.DnsPacket.DnsRecord +import libcore.net.InetAddressUtils +import org.junit.After +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito +import java.net.DatagramPacket +import java.net.DatagramSocket +import java.net.InetAddress +import java.net.InetSocketAddress +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +val TEST_V6_ADDR = InetAddressUtils.parseNumericAddress("2001:db8::3") +const val TEST_DOMAIN = "hello.example.com" + +@RunWith(AndroidJUnit4::class) +@SmallTest +class TestDnsServerTest { + private val network = Mockito.mock(Network::class.java) + private val localAddr = InetSocketAddress(InetAddress.getLocalHost(), 0 /* port */) + private val testServer: TestDnsServer = TestDnsServer(network, localAddr) + + @After + fun tearDown() { + if (testServer.isAlive) testServer.stop() + } + + @Test + fun testStartStop() { + repeat(100) { + val server = TestDnsServer(network, localAddr) + server.start() + assertTrue(server.isAlive) + server.stop() + assertFalse(server.isAlive) + } + + // Test illegal start/stop. + assertFailsWith { testServer.stop() } + testServer.start() + assertTrue(testServer.isAlive) + assertFailsWith { testServer.start() } + testServer.stop() + assertFalse(testServer.isAlive) + assertFailsWith { testServer.stop() } + // TestDnsServer rejects start after stop. + assertFailsWith { testServer.start() } + } + + @Test + fun testHandleDnsQuery() { + testServer.setAnswer(TEST_DOMAIN, listOf(TEST_V6_ADDR)) + testServer.start() + + // Mock query and send it to the test server. + val queryHeader = DnsPacket.DnsHeader(0xbeef /* id */, + 0x0 /* flag */, 1 /* qcount */, 0 /* ancount */) + val qlist = listOf(DnsRecord.makeQuestion(TEST_DOMAIN, TYPE_AAAA, CLASS_IN)) + val queryPacket = TestDnsServer.DnsQueryPacket(queryHeader, qlist, emptyList()) + val response = resolve(queryPacket, testServer.port) + + // Verify expected answer packet. Set QR bit of flag to 1 for response packet + // according to RFC 1035 section 4.1.1. + val answerHeader = DnsPacket.DnsHeader(0xbeef, + 1 shl 15 /* flag */, 1 /* qcount */, 1 /* ancount */) + val alist = listOf(DnsRecord.makeAOrAAAARecord(DnsPacket.ANSECTION, TEST_DOMAIN, + CLASS_IN, DEFAULT_TTL_S, TEST_V6_ADDR)) + val expectedAnswerPacket = TestDnsServer.DnsAnswerPacket(answerHeader, qlist, alist) + assertEquals(expectedAnswerPacket, response) + + // Clean up the server in tearDown. + } + + private fun resolve(queryDnsPacket: DnsPacket, serverPort: Int): TestDnsServer.DnsAnswerPacket { + val bytes = queryDnsPacket.bytes + // Create a new client socket, the socket will be bound to a + // random port other than the server port. + val socket = DatagramSocket(localAddr).also { it.soTimeout = 100 } + val queryPacket = DatagramPacket(bytes, bytes.size, localAddr.address, serverPort) + + // Send query and wait for the reply. + socket.send(queryPacket) + val buffer = ByteArray(MAX_BUF_SIZE) + val reply = DatagramPacket(buffer, buffer.size) + socket.receive(reply) + return TestDnsServer.DnsAnswerPacket(reply.data) + } + + // TODO: Add more tests, which includes: + // * Empty question RR packet (or more unexpected states) + // * No answer found (setAnswer empty list at L.78) + // * Test one or multi A record(s) + // * Test multi AAAA records + // * Test CNAME records +} diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DnsAnswerProvider.kt b/staticlibs/testutils/devicetests/com/android/testutils/DnsAnswerProvider.kt new file mode 100644 index 0000000000..6a804bf937 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/DnsAnswerProvider.kt @@ -0,0 +1,65 @@ +/* + * 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 com.android.testutils + +import android.net.DnsResolver.CLASS_IN +import com.android.net.module.util.DnsPacket +import com.android.net.module.util.DnsPacket.ANSECTION +import java.net.InetAddress +import java.util.concurrent.ConcurrentHashMap + +const val DEFAULT_TTL_S = 5L + +/** + * Helper class to store the mapping of DNS queries. + * + * DnsAnswerProvider is built atop a ConcurrentHashMap and as such it provides the same + * guarantees as ConcurrentHashMap between writing and reading elements. Specifically : + * - Setting an answer happens-before reading the same answer. + * - Callers can read and write concurrently from DnsAnswerProvider and expect no + * ConcurrentModificationException. + * Freshness of the answers depends on ordering of the threads ; if callers need a + * freshness guarantee, they need to provide the happens-before relationship from a + * write that they want to observe to the read that they need to be observed. + */ +class DnsAnswerProvider { + private val mDnsKeyToRecords = ConcurrentHashMap>() + + /** + * Get answer for the specified hostname. + * + * @param query the target hostname. + * @param type type of record, could be A or AAAA. + * + * @return list of [DnsPacket.DnsRecord] associated to the query. Empty if no record matches. + */ + fun getAnswer(query: String, type: Int) = mDnsKeyToRecords[query] + .orEmpty().filter { it.nsType == type } + + /** Set answer for the specified {@code query}. + * + * @param query the target hostname + * @param addresses [List] which could be used to generate multiple A or AAAA + * RRs with the corresponding addresses. + */ + fun setAnswer(query: String, hosts: List) = mDnsKeyToRecords.put(query, hosts.map { + DnsPacket.DnsRecord.makeAOrAAAARecord(ANSECTION, query, CLASS_IN, DEFAULT_TTL_S, it) + }) + + fun clearAnswer(query: String) = mDnsKeyToRecords.remove(query) + fun clearAll() = mDnsKeyToRecords.clear() +} \ No newline at end of file diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestDnsServer.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestDnsServer.kt new file mode 100644 index 0000000000..c63b38f929 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestDnsServer.kt @@ -0,0 +1,169 @@ +/* + * 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 com.android.testutils + +import android.net.Network +import android.util.Log +import com.android.internal.annotations.GuardedBy +import com.android.internal.annotations.VisibleForTesting +import com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE +import com.android.net.module.util.DnsPacket +import java.net.DatagramPacket +import java.net.DatagramSocket +import java.net.InetAddress +import java.net.InetSocketAddress +import java.net.SocketAddress +import java.net.SocketException +import java.util.ArrayList + +private const val TAG = "TestDnsServer" +private const val VDBG = true +@VisibleForTesting(visibility = PRIVATE) +const val MAX_BUF_SIZE = 8192 + +/** + * A simple implementation of Dns Server that can be bound on specific address and Network. + * + * The caller should use start() to make the server start a new thread to receive DNS queries + * on the bound address, [isAlive] to check status, and stop() for stopping. + * The server allows user to manipulate the records to be answered through + * [setAnswer] at runtime. + * + * This server runs on its own thread. Please make sure writing the query to the socket + * happens-after using [setAnswer] to guarantee the correct answer is returned. If possible, + * use [setAnswer] before calling [start] for simplicity. + */ +class TestDnsServer(network: Network, addr: InetSocketAddress) { + enum class Status { + NOT_STARTED, STARTED, STOPPED + } + @GuardedBy("thread") + private var status: Status = Status.NOT_STARTED + private val thread = ReceivingThread() + private val socket = DatagramSocket(addr).also { network.bindSocket(it) } + private val ansProvider = DnsAnswerProvider() + + // The buffer to store the received packet. They are being reused for + // efficiency and it's fine because they are only ever accessed + // on the server thread in a sequential manner. + private val buffer = ByteArray(MAX_BUF_SIZE) + private val packet = DatagramPacket(buffer, buffer.size) + + fun setAnswer(hostname: String, answer: List) = + ansProvider.setAnswer(hostname, answer) + + private fun processPacket() { + // Blocking read and try construct a DnsQueryPacket object. + socket.receive(packet) + val q = DnsQueryPacket(packet.data) + handleDnsQuery(q, packet.socketAddress) + } + + // TODO: Add support to reply some error with a DNS reply packet with failure RCODE. + private fun handleDnsQuery(q: DnsQueryPacket, src: SocketAddress) { + val queryRecords = q.queryRecords + if (queryRecords.size != 1) { + throw IllegalArgumentException( + "Expected one dns query record but got ${queryRecords.size}" + ) + } + val answerRecords = queryRecords[0].let { ansProvider.getAnswer(it.dName, it.nsType) } + + if (VDBG) { + Log.v(TAG, "handleDnsPacket: " + + queryRecords.map { "${it.dName},${it.nsType}" }.joinToString() + + " ansCount=${answerRecords.size} socketAddress=$src") + } + + val bytes = q.getAnswerPacket(answerRecords).bytes + val reply = DatagramPacket(bytes, bytes.size, src) + socket.send(reply) + } + + fun start() { + synchronized(thread) { + if (status != Status.NOT_STARTED) { + throw IllegalStateException("unexpected status: $status") + } + thread.start() + status = Status.STARTED + } + } + fun stop() { + synchronized(thread) { + if (status != Status.STARTED) { + throw IllegalStateException("unexpected status: $status") + } + socket.close() + thread.interrupt() + thread.join() + status = Status.STOPPED + } + } + val isAlive get() = thread.isAlive + val port get() = socket.localPort + + inner class ReceivingThread : Thread() { + override fun run() { + Log.i(TAG, "starting addr={${socket.localSocketAddress}}") + while (!interrupted() && !socket.isClosed) { + try { + processPacket() + } catch (e: InterruptedException) { + // The caller terminated the server, exit. + break + } catch (e: SocketException) { + // The caller terminated the server, exit. + break + } + } + Log.i(TAG, "exiting socket={$socket}") + } + } + + @VisibleForTesting(visibility = PRIVATE) + class DnsQueryPacket : DnsPacket { + constructor(data: ByteArray) : super(data) + constructor(header: DnsHeader, qd: List, an: List) : + super(header, qd, an) + + init { + if (mHeader.isResponse) { + throw ParseException("Not a query packet") + } + } + + val queryRecords: List + get() = mRecords[QDSECTION] + + fun getAnswerPacket(ar: List): DnsAnswerPacket { + // Set QR bit of flag to 1 for response packet according to RFC 1035 section 4.1.1. + val flags = 1 shl 15 + val qr = ArrayList(mRecords[QDSECTION]) + // Copy the query packet header id to the answer packet as RFC 1035 section 4.1.1. + val header = DnsHeader(mHeader.id, flags, qr.size, ar.size) + return DnsAnswerPacket(header, qr, ar) + } + } + + class DnsAnswerPacket : DnsPacket { + constructor(header: DnsHeader, qr: List, ar: List) : + super(header, qr, ar) + @VisibleForTesting(visibility = PRIVATE) + constructor(bytes: ByteArray) : super(bytes) + } +} From 61e21fff0b3ae74a2044d9fd89b10e5bb192c625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 2 Nov 2022 08:38:49 +0000 Subject: [PATCH 586/777] Revert "add bpf_for_each_map_elem() helper definition" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 8711ae5494a3011f48543987fa08872d775df652. Bug: 256991746 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I4835904f906422d5927feef82459ce1adcebc90c --- staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 6eb8aa7f45..35d9f31d1e 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -138,10 +138,6 @@ static int (*bpf_map_update_elem_unsafe)(const struct bpf_map_def* map, const vo static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, const void* key) = (void*)BPF_FUNC_map_delete_elem; -static int (*bpf_for_each_map_elem)(const struct bpf_map_def* map, void *callback_fn, - void *callback_ctx, unsigned long long flags) = (void*) - BPF_FUNC_for_each_map_elem; - #define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val) \ struct ____btf_map_##name { \ type_key key; \ From 8076110105df80eca38aa297b860dfe04d75ed1b Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 24 Oct 2022 11:11:05 +0900 Subject: [PATCH 587/777] Add option to validate DUN networks When isDunValidationRequired is true, networks with DUN capability will always be validated. Otherwise previous behavior will apply. Bug: 253989196 Test: atest NetworkMonitorTests Change-Id: I6e8bc7fcbf561f636abbf42ca69749fd0eabfd6c --- .../com/android/net/module/util/NetworkMonitorUtils.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/NetworkMonitorUtils.java b/staticlibs/device/com/android/net/module/util/NetworkMonitorUtils.java index f6cd044e4e..5a4412f506 100644 --- a/staticlibs/device/com/android/net/module/util/NetworkMonitorUtils.java +++ b/staticlibs/device/com/android/net/module/util/NetworkMonitorUtils.java @@ -16,6 +16,7 @@ package com.android.net.module.util; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; @@ -102,9 +103,12 @@ public class NetworkMonitorUtils { * networks. * @param nc Network capabilities of the network to test. */ - public static boolean isValidationRequired(boolean isVpnValidationRequired, + public static boolean isValidationRequired(boolean isDunValidationRequired, + boolean isVpnValidationRequired, @NonNull final NetworkCapabilities nc) { - // TODO: Consider requiring validation for DUN networks. + if (isDunValidationRequired && nc.hasCapability(NET_CAPABILITY_DUN)) { + return true; + } if (!nc.hasCapability(NET_CAPABILITY_NOT_VPN)) { return isVpnValidationRequired; } From 53a6b7053dbb8f078f4538628d2bd0cc9061c42e Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 2 Nov 2022 18:01:51 +0800 Subject: [PATCH 588/777] Add eventuallyExpect method that takes mark Test: atest CtsNetTestCases:android.net.cts.ConnectivityManagerTest Fix: 254188130 Change-Id: I98ea8aef5cb21ee92ce47d97d2f9c81448b1cd9e --- .../android/testutils/TestableNetworkCallback.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index dffdbe8bba..3b24e0a422 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -237,8 +237,17 @@ open class TestableNetworkCallback private constructor( fun eventuallyExpect( type: KClass, timeoutMs: Long = defaultTimeoutMs, - predicate: (T: CallbackEntry) -> Boolean = { true } - ) = history.poll(timeoutMs) { type.java.isInstance(it) && predicate(it) }.also { + predicate: (cb: T) -> Boolean = { true } + ) = history.poll(timeoutMs) { type.java.isInstance(it) && predicate(it as T) }.also { + assertNotNull(it, "Callback ${type.java} not received within ${timeoutMs}ms") + } as T + + fun eventuallyExpect( + type: KClass, + timeoutMs: Long = defaultTimeoutMs, + from: Int = mark, + predicate: (cb: T) -> Boolean = { true } + ) = history.poll(timeoutMs, from) { type.java.isInstance(it) && predicate(it as T) }.also { assertNotNull(it, "Callback ${type.java} not received within ${timeoutMs}ms") } as T From 7356d356fbf299dc2af281ac4179be9f2462f331 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 8 Nov 2022 11:45:42 +0900 Subject: [PATCH 589/777] Move DeviceConfigRule to libs/net The utility can be useful for tests in several repositories, not just CTS. Test: m Change-Id: Id4c653793e58d91d604b388a06a7c137ed020110 --- .../com/android/testutils/DeviceConfigRule.kt | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/DeviceConfigRule.kt diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DeviceConfigRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/DeviceConfigRule.kt new file mode 100644 index 0000000000..3d98cc381b --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/DeviceConfigRule.kt @@ -0,0 +1,176 @@ +/* + * 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 com.android.testutils + +import android.Manifest.permission.READ_DEVICE_CONFIG +import android.Manifest.permission.WRITE_DEVICE_CONFIG +import android.provider.DeviceConfig +import android.util.Log +import com.android.modules.utils.build.SdkLevel +import com.android.testutils.FunctionalUtils.ThrowingRunnable +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runners.model.Statement +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Executor +import java.util.concurrent.TimeUnit + +private val TAG = DeviceConfigRule::class.simpleName + +private const val TIMEOUT_MS = 20_000L + +/** + * A [TestRule] that helps set [DeviceConfig] for tests and clean up the test configuration + * automatically on teardown. + * + * The rule can also optionally retry tests when they fail following an external change of + * DeviceConfig before S; this typically happens because device config flags are synced while the + * test is running, and DisableConfigSyncTargetPreparer is only usable starting from S. + * + * @param retryCountBeforeSIfConfigChanged if > 0, when the test fails before S, check if + * the configs that were set through this rule were changed, and retry the test + * up to the specified number of times if yes. + */ +class DeviceConfigRule @JvmOverloads constructor( + val retryCountBeforeSIfConfigChanged: Int = 0 +) : TestRule { + // Maps (namespace, key) -> value + private val originalConfig = mutableMapOf, String?>() + private val usedConfig = mutableMapOf, String?>() + + /** + * Actions to be run after cleanup of the config, for the current test only. + */ + private val currentTestCleanupActions = mutableListOf() + + override fun apply(base: Statement, description: Description): Statement { + return TestValidationUrlStatement(base, description) + } + + private inner class TestValidationUrlStatement( + private val base: Statement, + private val description: Description + ) : Statement() { + override fun evaluate() { + var retryCount = if (SdkLevel.isAtLeastS()) 1 else retryCountBeforeSIfConfigChanged + 1 + while (retryCount > 0) { + retryCount-- + tryTest { + base.evaluate() + // Can't use break/return out of a loop here because this is a tryTest lambda, + // so set retryCount to exit instead + retryCount = 0 + }.catch { e -> // junit AssertionFailedError does not extend Exception + if (retryCount == 0) throw e + usedConfig.forEach { (key, value) -> + val currentValue = runAsShell(READ_DEVICE_CONFIG) { + DeviceConfig.getProperty(key.first, key.second) + } + if (currentValue != value) { + Log.w(TAG, "Test failed with unexpected device config change, retrying") + return@catch + } + } + throw e + } cleanupStep { + runAsShell(WRITE_DEVICE_CONFIG) { + originalConfig.forEach { (key, value) -> + DeviceConfig.setProperty( + key.first, key.second, value, false /* makeDefault */) + } + } + } cleanupStep { + originalConfig.clear() + usedConfig.clear() + } cleanup { + // Fold all cleanup actions into cleanup steps of an empty tryTest, so they are + // all run even if exceptions are thrown, and exceptions are reported properly. + currentTestCleanupActions.fold(tryTest { }) { + tryBlock, action -> tryBlock.cleanupStep { action.run() } + }.cleanup { + currentTestCleanupActions.clear() + } + } + } + } + } + + /** + * Set a configuration key/value. After the test case ends, it will be restored to the value it + * had when this method was first called. + */ + fun setConfig(namespace: String, key: String, value: String?): String? { + Log.i(TAG, "Setting config \"$key\" to \"$value\"") + val readWritePermissions = arrayOf(READ_DEVICE_CONFIG, WRITE_DEVICE_CONFIG) + + val keyPair = Pair(namespace, key) + val existingValue = runAsShell(*readWritePermissions) { + DeviceConfig.getProperty(namespace, key) + } + if (!originalConfig.containsKey(keyPair)) { + originalConfig[keyPair] = existingValue + } + usedConfig[keyPair] = value + if (existingValue == value) { + // Already the correct value. There may be a race if a change is already in flight, + // but if multiple threads update the config there is no way to fix that anyway. + Log.i(TAG, "\"$key\" already had value \"$value\"") + return value + } + + val future = CompletableFuture() + val listener = DeviceConfig.OnPropertiesChangedListener { + // The listener receives updates for any change to any key, so don't react to + // changes that do not affect the relevant key + if (!it.keyset.contains(key)) return@OnPropertiesChangedListener + // "null" means absent in DeviceConfig : there is no such thing as a present but + // null value, so the following works even if |value| is null. + if (it.getString(key, null) == value) { + future.complete(value) + } + } + + return tryTest { + runAsShell(*readWritePermissions) { + DeviceConfig.addOnPropertiesChangedListener( + DeviceConfig.NAMESPACE_CONNECTIVITY, + inlineExecutor, + listener) + DeviceConfig.setProperty( + DeviceConfig.NAMESPACE_CONNECTIVITY, + key, + value, + false /* makeDefault */) + // Don't drop the permission until the config is applied, just in case + future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS) + }.also { + Log.i(TAG, "Config \"$key\" successfully set to \"$value\"") + } + } cleanup { + DeviceConfig.removeOnPropertiesChangedListener(listener) + } + } + + private val inlineExecutor get() = Executor { r -> r.run() } + + /** + * Add an action to be run after config cleanup when the current test case ends. + */ + fun runAfterNextCleanup(action: ThrowingRunnable) { + currentTestCleanupActions.add(action) + } +} From 43bb172e82ccd4267a611c864bce458334fe7b30 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 14 Nov 2022 18:18:20 +0900 Subject: [PATCH 590/777] Add useful utils to CollectionUtils Test: new tests in this patch Change-Id: I9cca999f9235d4d6508533230afcd8ee0c1c54c1 --- .../net/module/util/CollectionUtils.java | 99 +++++++++++++++++++ .../net/module/util/CollectionUtilsTest.kt | 49 +++++++++ 2 files changed, 148 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index 7cac90d598..f08880cbec 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -18,12 +18,15 @@ package com.android.net.module.util; import android.annotation.NonNull; import android.annotation.Nullable; +import android.util.ArrayMap; +import android.util.Pair; import android.util.SparseArray; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.function.Function; import java.util.function.Predicate; /** @@ -291,4 +294,100 @@ public final class CollectionUtils { @NonNull final Predicate condition) { return -1 != indexOf(haystack, condition); } + + /** + * Standard map function, but returns a new modifiable ArrayList + * + * This returns a new list that contains, for each element of the source collection, its + * image through the passed transform. + * Elements in the source can be null if the transform accepts null inputs. + * Elements in the output can be null if the transform ever returns null. + * This function never returns null. If the source collection is empty, it returns the + * empty list. + * Contract : this method calls the transform function exactly once for each element in the + * list, in iteration order. + * + * @param source the source collection + * @param transform the function to transform the elements + * @param type of source elements + * @param type of destination elements + * @return an unmodifiable list of transformed elements + */ + @NonNull + public static ArrayList map(@NonNull final Collection source, + @NonNull final Function transform) { + final ArrayList dest = new ArrayList<>(source.size()); + for (final T e : source) { + dest.add(transform.apply(e)); + } + return dest; + } + + /** + * Standard zip function, but returns a new modifiable ArrayList + * + * This returns a list of pairs containing, at each position, a pair of the element from the + * first list at that index and the element from the second list at that index. + * Both lists must be the same size. They may contain null. + * + * The easiest way to visualize what's happening is to think of two lists being laid out next + * to each other and stitched together with a zipper. + * + * Contract : this method will read each element of each list exactly once, in some unspecified + * order. If it throws, it will not read any element. + * + * @param first the first list of elements + * @param second the second list of elements + * @param the type of first elements + * @param the type of second elements + * @return the zipped list + */ + @NonNull + public static ArrayList> zip(@NonNull final List first, + @NonNull final List second) { + final int size = first.size(); + if (size != second.size()) { + throw new IllegalArgumentException("zip : collections must be the same size"); + } + final ArrayList> dest = new ArrayList<>(size); + for (int i = 0; i < size; ++i) { + dest.add(new Pair<>(first.get(i), second.get(i))); + } + return dest; + } + + /** + * Returns a new ArrayMap that associates each key with the value at the same index. + * + * Both lists must be the same size. + * Both keys and values may contain null. + * Keys may not contain the same value twice. + * + * Contract : this method will read each element of each list exactly once, but does not + * specify the order, except if it throws in which case the number of reads is undefined. + * + * @param keys The list of keys + * @param values The list of values + * @param The type of keys + * @param The type of values + * @return The associated map + */ + @NonNull + public static ArrayMap assoc( + @NonNull final List keys, @NonNull final List values) { + final int size = keys.size(); + if (size != values.size()) { + throw new IllegalArgumentException("assoc : collections must be the same size"); + } + final ArrayMap dest = new ArrayMap<>(size); + for (int i = 0; i < size; ++i) { + final T key = keys.get(i); + if (dest.containsKey(key)) { + throw new IllegalArgumentException( + "assoc : keys may not contain the same value twice"); + } + dest.put(key, values.get(i)); + } + return dest; + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt index 0f00d0b57b..9fb025b353 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt @@ -22,6 +22,7 @@ import com.android.testutils.assertThrows import org.junit.Test import org.junit.runner.RunWith import kotlin.test.assertEquals +import kotlin.test.assertFailsWith import kotlin.test.assertFalse import kotlin.test.assertNull import kotlin.test.assertSame @@ -133,4 +134,52 @@ class CollectionUtilsTest { assertSame(CollectionUtils.findLast(listMulti) { it == "E" }, listMulti[7]) assertNull(CollectionUtils.findLast(listMulti) { it == "F" }) } + + @Test + fun testMap() { + val listAE = listOf("A", "B", "C", "D", "E", null) + assertEquals(listAE.map { "-$it-" }, CollectionUtils.map(listAE) { "-$it-" }) + } + + @Test + fun testZip() { + val listAE = listOf("A", "B", "C", "D", "E") + val list15 = listOf(1, 2, 3, 4, 5) + // Normal #zip returns kotlin.Pair, not android.util.Pair + assertEquals(list15.zip(listAE).map { android.util.Pair(it.first, it.second) }, + CollectionUtils.zip(list15, listAE)) + val listNull = listOf("A", null, "B", "C", "D") + assertEquals(list15.zip(listNull).map { android.util.Pair(it.first, it.second) }, + CollectionUtils.zip(list15, listNull)) + assertEquals(emptyList>(), + CollectionUtils.zip(emptyList(), emptyList())) + assertFailsWith { + // Different size + CollectionUtils.zip(listOf(1, 2), list15) + } + } + + @Test + fun testAssoc() { + val listADA = listOf("A", "B", "C", "D", "A") + val list15 = listOf(1, 2, 3, 4, 5) + assertEquals(list15.zip(listADA).toMap(), CollectionUtils.assoc(list15, listADA)) + + // Null key is fine + val assoc = CollectionUtils.assoc(listOf(1, 2, null), listOf("A", "B", "C")) + assertEquals("C", assoc[null]) + + assertFailsWith { + // Same key multiple times + CollectionUtils.assoc(listOf("A", "B", "A"), listOf(1, 2, 3)) + } + assertFailsWith { + // Same key multiple times, but it's null + CollectionUtils.assoc(listOf(null, "B", null), listOf(1, 2, 3)) + } + assertFailsWith { + // Different size + CollectionUtils.assoc(listOf(1, 2), list15) + } + } } From 88c48e18e4eeddc2fc8e588ed42697680d79b6d4 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 15 Nov 2022 05:55:15 +0000 Subject: [PATCH 591/777] Revert "[ST03] Add test dns server for integration tests" Revert "[ST03.1] Add DnsAnswerProviderTest" Revert submission 1390056-st03 Reason for revert: test failed in presubmit, still under checking. Reverted Changes: Ia5039a47f:[ST03] Add test dns server for integration tests I9157e030c:[ST03.1] Add DnsAnswerProviderTest Change-Id: I1ff291ca62e2209343ed5c5e4aa3bf3e93229f47 --- .../android/testutils/TestDnsServerTest.kt | 122 ------------- .../android/testutils/DnsAnswerProvider.kt | 65 ------- .../com/android/testutils/TestDnsServer.kt | 169 ------------------ 3 files changed, 356 deletions(-) delete mode 100644 staticlibs/tests/unit/src/com/android/testutils/TestDnsServerTest.kt delete mode 100644 staticlibs/testutils/devicetests/com/android/testutils/DnsAnswerProvider.kt delete mode 100644 staticlibs/testutils/devicetests/com/android/testutils/TestDnsServer.kt diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestDnsServerTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestDnsServerTest.kt deleted file mode 100644 index 6f4587b140..0000000000 --- a/staticlibs/tests/unit/src/com/android/testutils/TestDnsServerTest.kt +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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 com.android.testutils - -import android.net.DnsResolver.CLASS_IN -import android.net.DnsResolver.TYPE_AAAA -import android.net.Network -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.net.module.util.DnsPacket -import com.android.net.module.util.DnsPacket.DnsRecord -import libcore.net.InetAddressUtils -import org.junit.After -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mockito -import java.net.DatagramPacket -import java.net.DatagramSocket -import java.net.InetAddress -import java.net.InetSocketAddress -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith -import kotlin.test.assertFalse -import kotlin.test.assertTrue - -val TEST_V6_ADDR = InetAddressUtils.parseNumericAddress("2001:db8::3") -const val TEST_DOMAIN = "hello.example.com" - -@RunWith(AndroidJUnit4::class) -@SmallTest -class TestDnsServerTest { - private val network = Mockito.mock(Network::class.java) - private val localAddr = InetSocketAddress(InetAddress.getLocalHost(), 0 /* port */) - private val testServer: TestDnsServer = TestDnsServer(network, localAddr) - - @After - fun tearDown() { - if (testServer.isAlive) testServer.stop() - } - - @Test - fun testStartStop() { - repeat(100) { - val server = TestDnsServer(network, localAddr) - server.start() - assertTrue(server.isAlive) - server.stop() - assertFalse(server.isAlive) - } - - // Test illegal start/stop. - assertFailsWith { testServer.stop() } - testServer.start() - assertTrue(testServer.isAlive) - assertFailsWith { testServer.start() } - testServer.stop() - assertFalse(testServer.isAlive) - assertFailsWith { testServer.stop() } - // TestDnsServer rejects start after stop. - assertFailsWith { testServer.start() } - } - - @Test - fun testHandleDnsQuery() { - testServer.setAnswer(TEST_DOMAIN, listOf(TEST_V6_ADDR)) - testServer.start() - - // Mock query and send it to the test server. - val queryHeader = DnsPacket.DnsHeader(0xbeef /* id */, - 0x0 /* flag */, 1 /* qcount */, 0 /* ancount */) - val qlist = listOf(DnsRecord.makeQuestion(TEST_DOMAIN, TYPE_AAAA, CLASS_IN)) - val queryPacket = TestDnsServer.DnsQueryPacket(queryHeader, qlist, emptyList()) - val response = resolve(queryPacket, testServer.port) - - // Verify expected answer packet. Set QR bit of flag to 1 for response packet - // according to RFC 1035 section 4.1.1. - val answerHeader = DnsPacket.DnsHeader(0xbeef, - 1 shl 15 /* flag */, 1 /* qcount */, 1 /* ancount */) - val alist = listOf(DnsRecord.makeAOrAAAARecord(DnsPacket.ANSECTION, TEST_DOMAIN, - CLASS_IN, DEFAULT_TTL_S, TEST_V6_ADDR)) - val expectedAnswerPacket = TestDnsServer.DnsAnswerPacket(answerHeader, qlist, alist) - assertEquals(expectedAnswerPacket, response) - - // Clean up the server in tearDown. - } - - private fun resolve(queryDnsPacket: DnsPacket, serverPort: Int): TestDnsServer.DnsAnswerPacket { - val bytes = queryDnsPacket.bytes - // Create a new client socket, the socket will be bound to a - // random port other than the server port. - val socket = DatagramSocket(localAddr).also { it.soTimeout = 100 } - val queryPacket = DatagramPacket(bytes, bytes.size, localAddr.address, serverPort) - - // Send query and wait for the reply. - socket.send(queryPacket) - val buffer = ByteArray(MAX_BUF_SIZE) - val reply = DatagramPacket(buffer, buffer.size) - socket.receive(reply) - return TestDnsServer.DnsAnswerPacket(reply.data) - } - - // TODO: Add more tests, which includes: - // * Empty question RR packet (or more unexpected states) - // * No answer found (setAnswer empty list at L.78) - // * Test one or multi A record(s) - // * Test multi AAAA records - // * Test CNAME records -} diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DnsAnswerProvider.kt b/staticlibs/testutils/devicetests/com/android/testutils/DnsAnswerProvider.kt deleted file mode 100644 index 6a804bf937..0000000000 --- a/staticlibs/testutils/devicetests/com/android/testutils/DnsAnswerProvider.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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 com.android.testutils - -import android.net.DnsResolver.CLASS_IN -import com.android.net.module.util.DnsPacket -import com.android.net.module.util.DnsPacket.ANSECTION -import java.net.InetAddress -import java.util.concurrent.ConcurrentHashMap - -const val DEFAULT_TTL_S = 5L - -/** - * Helper class to store the mapping of DNS queries. - * - * DnsAnswerProvider is built atop a ConcurrentHashMap and as such it provides the same - * guarantees as ConcurrentHashMap between writing and reading elements. Specifically : - * - Setting an answer happens-before reading the same answer. - * - Callers can read and write concurrently from DnsAnswerProvider and expect no - * ConcurrentModificationException. - * Freshness of the answers depends on ordering of the threads ; if callers need a - * freshness guarantee, they need to provide the happens-before relationship from a - * write that they want to observe to the read that they need to be observed. - */ -class DnsAnswerProvider { - private val mDnsKeyToRecords = ConcurrentHashMap>() - - /** - * Get answer for the specified hostname. - * - * @param query the target hostname. - * @param type type of record, could be A or AAAA. - * - * @return list of [DnsPacket.DnsRecord] associated to the query. Empty if no record matches. - */ - fun getAnswer(query: String, type: Int) = mDnsKeyToRecords[query] - .orEmpty().filter { it.nsType == type } - - /** Set answer for the specified {@code query}. - * - * @param query the target hostname - * @param addresses [List] which could be used to generate multiple A or AAAA - * RRs with the corresponding addresses. - */ - fun setAnswer(query: String, hosts: List) = mDnsKeyToRecords.put(query, hosts.map { - DnsPacket.DnsRecord.makeAOrAAAARecord(ANSECTION, query, CLASS_IN, DEFAULT_TTL_S, it) - }) - - fun clearAnswer(query: String) = mDnsKeyToRecords.remove(query) - fun clearAll() = mDnsKeyToRecords.clear() -} \ No newline at end of file diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestDnsServer.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestDnsServer.kt deleted file mode 100644 index c63b38f929..0000000000 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestDnsServer.kt +++ /dev/null @@ -1,169 +0,0 @@ -/* - * 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 com.android.testutils - -import android.net.Network -import android.util.Log -import com.android.internal.annotations.GuardedBy -import com.android.internal.annotations.VisibleForTesting -import com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE -import com.android.net.module.util.DnsPacket -import java.net.DatagramPacket -import java.net.DatagramSocket -import java.net.InetAddress -import java.net.InetSocketAddress -import java.net.SocketAddress -import java.net.SocketException -import java.util.ArrayList - -private const val TAG = "TestDnsServer" -private const val VDBG = true -@VisibleForTesting(visibility = PRIVATE) -const val MAX_BUF_SIZE = 8192 - -/** - * A simple implementation of Dns Server that can be bound on specific address and Network. - * - * The caller should use start() to make the server start a new thread to receive DNS queries - * on the bound address, [isAlive] to check status, and stop() for stopping. - * The server allows user to manipulate the records to be answered through - * [setAnswer] at runtime. - * - * This server runs on its own thread. Please make sure writing the query to the socket - * happens-after using [setAnswer] to guarantee the correct answer is returned. If possible, - * use [setAnswer] before calling [start] for simplicity. - */ -class TestDnsServer(network: Network, addr: InetSocketAddress) { - enum class Status { - NOT_STARTED, STARTED, STOPPED - } - @GuardedBy("thread") - private var status: Status = Status.NOT_STARTED - private val thread = ReceivingThread() - private val socket = DatagramSocket(addr).also { network.bindSocket(it) } - private val ansProvider = DnsAnswerProvider() - - // The buffer to store the received packet. They are being reused for - // efficiency and it's fine because they are only ever accessed - // on the server thread in a sequential manner. - private val buffer = ByteArray(MAX_BUF_SIZE) - private val packet = DatagramPacket(buffer, buffer.size) - - fun setAnswer(hostname: String, answer: List) = - ansProvider.setAnswer(hostname, answer) - - private fun processPacket() { - // Blocking read and try construct a DnsQueryPacket object. - socket.receive(packet) - val q = DnsQueryPacket(packet.data) - handleDnsQuery(q, packet.socketAddress) - } - - // TODO: Add support to reply some error with a DNS reply packet with failure RCODE. - private fun handleDnsQuery(q: DnsQueryPacket, src: SocketAddress) { - val queryRecords = q.queryRecords - if (queryRecords.size != 1) { - throw IllegalArgumentException( - "Expected one dns query record but got ${queryRecords.size}" - ) - } - val answerRecords = queryRecords[0].let { ansProvider.getAnswer(it.dName, it.nsType) } - - if (VDBG) { - Log.v(TAG, "handleDnsPacket: " + - queryRecords.map { "${it.dName},${it.nsType}" }.joinToString() + - " ansCount=${answerRecords.size} socketAddress=$src") - } - - val bytes = q.getAnswerPacket(answerRecords).bytes - val reply = DatagramPacket(bytes, bytes.size, src) - socket.send(reply) - } - - fun start() { - synchronized(thread) { - if (status != Status.NOT_STARTED) { - throw IllegalStateException("unexpected status: $status") - } - thread.start() - status = Status.STARTED - } - } - fun stop() { - synchronized(thread) { - if (status != Status.STARTED) { - throw IllegalStateException("unexpected status: $status") - } - socket.close() - thread.interrupt() - thread.join() - status = Status.STOPPED - } - } - val isAlive get() = thread.isAlive - val port get() = socket.localPort - - inner class ReceivingThread : Thread() { - override fun run() { - Log.i(TAG, "starting addr={${socket.localSocketAddress}}") - while (!interrupted() && !socket.isClosed) { - try { - processPacket() - } catch (e: InterruptedException) { - // The caller terminated the server, exit. - break - } catch (e: SocketException) { - // The caller terminated the server, exit. - break - } - } - Log.i(TAG, "exiting socket={$socket}") - } - } - - @VisibleForTesting(visibility = PRIVATE) - class DnsQueryPacket : DnsPacket { - constructor(data: ByteArray) : super(data) - constructor(header: DnsHeader, qd: List, an: List) : - super(header, qd, an) - - init { - if (mHeader.isResponse) { - throw ParseException("Not a query packet") - } - } - - val queryRecords: List - get() = mRecords[QDSECTION] - - fun getAnswerPacket(ar: List): DnsAnswerPacket { - // Set QR bit of flag to 1 for response packet according to RFC 1035 section 4.1.1. - val flags = 1 shl 15 - val qr = ArrayList(mRecords[QDSECTION]) - // Copy the query packet header id to the answer packet as RFC 1035 section 4.1.1. - val header = DnsHeader(mHeader.id, flags, qr.size, ar.size) - return DnsAnswerPacket(header, qr, ar) - } - } - - class DnsAnswerPacket : DnsPacket { - constructor(header: DnsHeader, qr: List, ar: List) : - super(header, qr, ar) - @VisibleForTesting(visibility = PRIVATE) - constructor(bytes: ByteArray) : super(bytes) - } -} From 47d424e49d7145a298b91a6a48ef46db8c11a59c Mon Sep 17 00:00:00 2001 From: Hassan Ali Date: Thu, 17 Nov 2022 16:34:31 +0000 Subject: [PATCH 592/777] Add ConfigInfrastructure lib to Android.bp As part of moving DeviceConfig.java to packages/modules/ConfigInfrastructure, We need to add ConfigInfrastructure lib dependency to Android.bp. Test: m bug: 253019048 Change-Id: Id35bec32e9b46ef6589034d442a767ce1a4aaac8 --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index f4997a1691..63c8b4e99d 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -70,6 +70,7 @@ java_library { libs: [ "androidx.annotation_annotation", "framework-annotations-lib", + "framework-configinfrastructure", "framework-connectivity.stubs.module_lib", ], lint: { strict_updatability_linting: true }, From c79a231a16fa6c28270b7e2aa759f44e27d6799f Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 25 Nov 2022 15:52:03 +0900 Subject: [PATCH 593/777] Add the name of the expected callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before : java.lang.AssertionError: Did not receive callback after 5000 After : java.lang.AssertionError: Did not receive Available after 5000ms Test: manual Change-Id: If46d52cb0db8ea3d418169ea330d915d835e4373 --- .../com/android/testutils/TestableNetworkCallback.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index b84f9a6ea1..92c83b7ff6 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -326,7 +326,7 @@ open class TestableNetworkCallback private constructor( timeoutMs: Long = defaultTimeoutMs, errorMsg: String? = null, test: (T) -> Boolean = { true } - ) = pollOrThrow(timeoutMs).also { + ) = pollOrThrow(timeoutMs, "Did not receive ${T::class.simpleName} after ${timeoutMs}ms").also { if (it !is T) fail("Expected callback ${T::class.simpleName}, got $it") if (ANY_NETWORK !== network && it.network != network) { fail("Expected network $network for callback : $it") From 79ce874e8f33b4b903adef9d0b4d59aed92bd31b Mon Sep 17 00:00:00 2001 From: Ryan Zuklie Date: Mon, 21 Nov 2022 17:19:25 -0800 Subject: [PATCH 594/777] Add macro to create BPF ring buffers. BPF ring buffers are defined like maps, but cannot specify a key or value size (attempting to do so is a verifier error). This change also adds the type-safe methods for interacting with the map (output, reserve and submit). Bug: 246985031 Test: local run of Network Tracing w/ ring buffers Change-Id: Ie8a47d987be6cb219fe7d73f2c61a56e3a3ab21a --- .../bpf_headers/include/bpf/bpf_helpers.h | 72 ++++++++++++++----- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index c652c769dc..ea5659354b 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -137,6 +137,14 @@ static int (*bpf_map_update_elem_unsafe)(const struct bpf_map_def* map, const vo BPF_FUNC_map_update_elem; static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, const void* key) = (void*)BPF_FUNC_map_delete_elem; +static int (*bpf_ringbuf_output_unsafe)(const struct bpf_map_def* ringbuf, + const void* data, __u64 size, __u64 flags) = (void*) + BPF_FUNC_ringbuf_output; +static void* (*bpf_ringbuf_reserve_unsafe)(const struct bpf_map_def* ringbuf, + __u64 size, __u64 flags) = (void*) + BPF_FUNC_ringbuf_reserve; +static void (*bpf_ringbuf_submit_unsafe)(const void* data, __u64 flags) = (void*) + BPF_FUNC_ringbuf_submit; #define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val) \ struct ____btf_map_##name { \ @@ -147,6 +155,50 @@ static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, __attribute__ ((section(".maps." #name), used)) \ ____btf_map_##name = { } +#define DEFINE_BPF_MAP_BASE(the_map, TYPE, keysize, valuesize, num_entries, \ + usr, grp, md, selinux, pindir, share, minkver, \ + maxkver) \ + const struct bpf_map_def SECTION("maps") the_map = { \ + .type = BPF_MAP_TYPE_##TYPE, \ + .key_size = (keysize), \ + .value_size = (valuesize), \ + .max_entries = (num_entries), \ + .map_flags = 0, \ + .uid = (usr), \ + .gid = (grp), \ + .mode = (md), \ + .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER, \ + .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER, \ + .min_kver = (minkver), \ + .max_kver = (maxkver), \ + .selinux_context = (selinux), \ + .pin_subdir = (pindir), \ + .shared = (share), \ + }; + +// Type safe macro to declare a ring buffer and related output functions. +// Compatibility: +// * BPF ring buffers are only available kernels 5.8 and above. Any program +// accessing the ring buffer should set a program level min_kver >= 5.8. +// * The definition below sets a map min_kver of 5.8 which requires targeting +// a BPFLOADER_MIN_VER >= BPFLOADER_S_VERSION. +#define DEFINE_BPF_RINGBUF(the_map, ValueType, size_bytes, usr, grp, md, \ + selinux, pindir, share) \ + DEFINE_BPF_MAP_BASE(the_map, RINGBUF, 0, 0, size_bytes, usr, grp, md, \ + selinux, pindir, share, KVER(5, 8, 0), KVER_INF); \ + static inline __always_inline __unused int bpf_##the_map##_output( \ + const ValueType* v) { \ + return bpf_ringbuf_output_unsafe(&the_map, v, sizeof(*v), 0); \ + } \ + static inline __always_inline __unused \ + ValueType* bpf_##the_map##_reserve() { \ + return bpf_ringbuf_reserve_unsafe(&the_map, sizeof(ValueType), 0); \ + } \ + static inline __always_inline __unused void bpf_##the_map##_submit( \ + const ValueType* v) { \ + bpf_ringbuf_submit_unsafe(v, 0); \ + } + /* There exist buggy kernels with pre-T OS, that due to * kernel patch "[ALPS05162612] bpf: fix ubsan error" * do not support userspace writes into non-zero index of bpf map arrays. @@ -167,23 +219,9 @@ static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map, /* type safe macro to declare a map and related accessor functions */ #define DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, \ selinux, pindir, share) \ - const struct bpf_map_def SECTION("maps") the_map = { \ - .type = BPF_MAP_TYPE_##TYPE, \ - .key_size = sizeof(KeyType), \ - .value_size = sizeof(ValueType), \ - .max_entries = (num_entries), \ - .map_flags = 0, \ - .uid = (usr), \ - .gid = (grp), \ - .mode = (md), \ - .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER, \ - .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER, \ - .min_kver = KVER_NONE, \ - .max_kver = KVER_INF, \ - .selinux_context = selinux, \ - .pin_subdir = pindir, \ - .shared = share, \ - }; \ + DEFINE_BPF_MAP_BASE(the_map, TYPE, sizeof(KeyType), sizeof(ValueType), \ + num_entries, usr, grp, md, selinux, pindir, share, \ + KVER_NONE, KVER_INF); \ BPF_MAP_ASSERT_OK(BPF_MAP_TYPE_##TYPE, (num_entries), (md)); \ BPF_ANNOTATE_KV_PAIR(the_map, KeyType, ValueType); \ \ From b2a6964fc21d3c18eff087153014961b9b430619 Mon Sep 17 00:00:00 2001 From: chiachangwang Date: Thu, 1 Dec 2022 01:11:26 +0000 Subject: [PATCH 595/777] Add withCleanCallingIdentity with Supplier to module utils Binder#withCleanCallingIdentity with Supplier is a very useful utility but it's not public. Thus, make one in the connectivity module utils. Bug: 255231779 Test: m ; adb shell dumpsys connectivity Change-Id: I029a34a96b1107111a605b91a54c8fdb071e9fc0 --- .../android/net/module/util/BinderUtils.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/BinderUtils.java b/staticlibs/framework/com/android/net/module/util/BinderUtils.java index eb695d1f9d..e4d14ea8d6 100644 --- a/staticlibs/framework/com/android/net/module/util/BinderUtils.java +++ b/staticlibs/framework/com/android/net/module/util/BinderUtils.java @@ -19,6 +19,8 @@ package com.android.net.module.util; import android.annotation.NonNull; import android.os.Binder; +import java.util.function.Supplier; + /** * Collection of utilities for {@link Binder} and related classes. * @hide @@ -56,4 +58,39 @@ public class BinderUtils { /** @see java.lang.Runnable */ void run() throws T; } + + /** + * Convenience method for running the provided action enclosed in + * {@link Binder#clearCallingIdentity}/{@link Binder#restoreCallingIdentity} returning the + * result. + * + *

Any exception thrown by the given action will be caught and rethrown after + * the call to {@link Binder#restoreCallingIdentity}. + * + * Note that this is copied from Binder#withCleanCallingIdentity with minor changes + * since it is not public. + * + * @hide + */ + public static final T withCleanCallingIdentity( + @NonNull ThrowingSupplier action) throws E { + final long callingIdentity = Binder.clearCallingIdentity(); + try { + return action.get(); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + } + + /** + * An equivalent of {@link Supplier} + * + * @param The class which is declared to be returned. + * @param The exception class which is declared to be thrown. + */ + @FunctionalInterface + public interface ThrowingSupplier { + /** @see java.util.function.Supplier */ + T get() throws E; + } } From 0937911c419dc786d34aa94f0975a952ece30b8c Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 2 Dec 2022 12:43:24 +0900 Subject: [PATCH 596/777] Add a method helper to create RTM_NEWADDR message in user space. Bug: 260934173 Test: atest NetworkStaticLibTests Change-Id: I39a53a3d8b0cd10437aeed502657dd34d8b7775d --- .../util/netlink/RtNetlinkAddressMessage.java | 47 ++++++++++++++++++ .../netlink/RtNetlinkAddressMessageTest.java | 48 ++++++++++++++++++- 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java index f7b0d02fb7..3748e46271 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java @@ -16,6 +16,10 @@ package com.android.net.module.util.netlink; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REPLACE; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; + import android.system.OsConstants; import androidx.annotation.NonNull; @@ -24,8 +28,10 @@ import androidx.annotation.VisibleForTesting; import com.android.net.module.util.HexDump; +import java.net.Inet6Address; import java.net.InetAddress; import java.nio.ByteBuffer; +import java.nio.ByteOrder; /** * A NetlinkMessage subclass for rtnetlink address messages. @@ -145,6 +151,47 @@ public class RtNetlinkAddressMessage extends NetlinkMessage { flags.pack(byteBuffer); } + /** + * A convenience method to create an RTM_NEWADDR message. + */ + public static byte[] newRtmNewAddressMessage(int seqNo, final InetAddress ip, short prefixlen, + byte flags, byte scope, int ifIndex, long preferred, long valid) { + final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); + nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWADDR; + nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE; + nlmsghdr.nlmsg_seq = seqNo; + + final RtNetlinkAddressMessage msg = new RtNetlinkAddressMessage(nlmsghdr); + final byte family = + (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET); + msg.mIfaddrmsg = new StructIfaddrMsg(family, prefixlen, flags, scope, ifIndex); + msg.mIpAddress = ip; + msg.mIfacacheInfo = new StructIfacacheInfo(preferred, valid, 0 /* cstamp */, + 0 /* tstamp */); + msg.mFlags = (int) (flags & 0xFF); + + final byte[] bytes = new byte[msg.getRequiredSpace()]; + nlmsghdr.nlmsg_len = bytes.length; + final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); + byteBuffer.order(ByteOrder.nativeOrder()); + msg.pack(byteBuffer); + return bytes; + } + + private int getRequiredSpace() { + int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructIfaddrMsg.STRUCT_SIZE; + if (mIpAddress != null) { + spaceRequired += NetlinkConstants.alignedLengthOf( + StructNlAttr.NLA_HEADERLEN + mIpAddress.getAddress().length); + } + if (mIfacacheInfo != null) { + spaceRequired += NetlinkConstants.alignedLengthOf( + StructNlAttr.NLA_HEADERLEN + StructIfacacheInfo.STRUCT_SIZE); + } + spaceRequired += StructNlAttr.NLA_HEADERLEN + 4; // IFA_FLAGS "u32" attr + return spaceRequired; + } + @Override public String toString() { return "RtNetlinkAddressMessage{ " diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java index 7d8dbd2bbb..b21e06096d 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java @@ -16,8 +16,11 @@ package com.android.net.module.util.netlink; +import static android.system.OsConstants.IFA_F_PERMANENT; import static android.system.OsConstants.NETLINK_ROUTE; +import static android.system.OsConstants.RT_SCOPE_LINK; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -31,6 +34,8 @@ import androidx.test.runner.AndroidJUnit4; import com.android.net.module.util.HexDump; +import libcore.util.HexEncoding; + import org.junit.Test; import org.junit.runner.RunWith; @@ -42,7 +47,7 @@ import java.nio.ByteOrder; @SmallTest public class RtNetlinkAddressMessageTest { private static final Inet6Address TEST_LINK_LOCAL = - (Inet6Address) InetAddresses.parseNumericAddress("fe80::2C41:5CFF:FE09:6665"); + (Inet6Address) InetAddresses.parseNumericAddress("FE80::2C41:5CFF:FE09:6665"); // An example of the full RTM_NEWADDR message. private static final String RTM_NEWADDR_HEX = @@ -127,6 +132,47 @@ public class RtNetlinkAddressMessageTest { assertNull(msg); } + @Test + public void testCreateRtmNewAddressMessage() { + // Hexadecimal representation of our created packet. + final String expectedNewAddressHex = + // struct nlmsghdr + "48000000" + // length = 72 + "1400" + // type = 20 (RTM_NEWADDR) + "0501" + // flags = NLM_F_ACK | NLM_F_REQUEST | NLM_F_REPLACE + "01000000" + // seqno = 1 + "00000000" + // pid = 0 (send to kernel) + // struct IfaddrMsg + "0A" + // family = inet6 + "40" + // prefix len = 64 + "80" + // flags = IFA_F_PERMANENT + "FD" + // scope = RT_SCOPE_LINK + "17000000" + // ifindex = 23 + // struct nlattr: IFA_ADDRESS + "1400" + // len + "0100" + // type + "FE800000000000002C415CFFFE096665" + // IP address = fe80::2C41:5cff:fe09:6665 + // struct nlattr: IFA_CACHEINFO + "1400" + // len + "0600" + // type + "FFFFFFFF" + // preferred = infinite + "FFFFFFFF" + // valid = infinite + "00000000" + // cstamp + "00000000" + // tstamp + // struct nlattr: IFA_FLAGS + "0800" + // len + "0800" + // type + "80000000"; // flags = IFA_F_PERMANENT + final byte[] expectedNewAddress = + HexEncoding.decode(expectedNewAddressHex.toCharArray(), false); + + final byte[] bytes = RtNetlinkAddressMessage.newRtmNewAddressMessage(1 /* seqno */, + TEST_LINK_LOCAL, (short) 64 /* prefix len */, (byte) IFA_F_PERMANENT /* flags */, + (byte) RT_SCOPE_LINK /* scope */, 23 /* ifindex */, + (long) 0xFFFFFFFF /* preferred */, (long) 0xFFFFFFFF /* valid */); + assertArrayEquals(expectedNewAddress, bytes); + } + @Test public void testToString() { final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWADDR_HEX); From 741ae9ff5d67c118ea48c691644266c3752b477e Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 8 Dec 2022 08:41:23 +0900 Subject: [PATCH 597/777] Add IPV4_FLAG_{DF,MF} constants. Bug: 258093642 Test: see other CL in topic Change-Id: I04b954a7adb0a0e8bc4032a2cbfc899fe958b3b1 --- .../com/android/net/module/util/NetworkStackConstants.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index ebef1557bf..287473e60f 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -97,6 +97,8 @@ public final class NetworkStackConstants { public static final int IPV4_SRC_ADDR_OFFSET = 12; public static final int IPV4_DST_ADDR_OFFSET = 16; public static final int IPV4_ADDR_LEN = 4; + public static final int IPV4_FLAG_MF = 0x2000; + public static final int IPV4_FLAG_DF = 0x4000; public static final Inet4Address IPV4_ADDR_ALL = makeInet4Address( (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff); public static final Inet4Address IPV4_ADDR_ANY = makeInet4Address( From c7801476ea07a163740ea83ad09d74380f6ce8a5 Mon Sep 17 00:00:00 2001 From: chiachangwang Date: Thu, 8 Dec 2022 05:27:51 +0000 Subject: [PATCH 598/777] Add NetlinkUtils Add NetlinkUtils to support common netlink related utilities. Also add method to support usage for construct an inet_diag_req_v2 message for querying alive TCP sockets from kernel. Bug: 259000745 Test: atest NetworkStackTests Change-Id: I542a115128fe663dd1c478942091452fb9352111 --- .../net/module/util/netlink/NetlinkUtils.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java new file mode 100644 index 0000000000..34c468acfd --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java @@ -0,0 +1,47 @@ +/* + * 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 com.android.net.module.util.netlink; + +import static android.system.OsConstants.IPPROTO_TCP; + +/** + * Utilities for netlink related class. + * @hide + */ +public class NetlinkUtils { + /** Corresponds to enum from bionic/libc/include/netinet/tcp.h. */ + private static final int TCP_ESTABLISHED = 1; + private static final int TCP_SYN_SENT = 2; + private static final int TCP_SYN_RECV = 3; + + public static final int TCP_MONITOR_STATE_FILTER = + (1 << TCP_ESTABLISHED) | (1 << TCP_SYN_SENT) | (1 << TCP_SYN_RECV); + + /** + * Construct an inet_diag_req_v2 message for querying alive TCP sockets from kernel. + */ + public static byte[] buildInetDiagReqForAliveTcpSockets(int family) { + return InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, + null /* local addr */, + null /* remote addr */, + family, + (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_DUMP) /* flag */, + 0 /* pad */, + 1 << NetlinkConstants.INET_DIAG_MEMINFO /* idiagExt */, + TCP_MONITOR_STATE_FILTER); + } +} From 41abe75ba75d79042c5e46e378d3d731659c71dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 8 Dec 2022 16:39:56 +0000 Subject: [PATCH 599/777] updated TODO's for bpf_shared.h -> netd.h rename MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off: Maciej Żenczykowski Change-Id: I44bb430f176161cafd6dfbd5e26e61dbe2a0183a --- staticlibs/native/tcutils/tests/tcutils_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staticlibs/native/tcutils/tests/tcutils_test.cpp b/staticlibs/native/tcutils/tests/tcutils_test.cpp index 8129286f0a..3a89696c63 100644 --- a/staticlibs/native/tcutils/tests/tcutils_test.cpp +++ b/staticlibs/native/tcutils/tests/tcutils_test.cpp @@ -79,7 +79,7 @@ TEST(LibTcUtilsTest, AttachReplaceDetachClsactLo) { } TEST(LibTcUtilsTest, AddAndDeleteBpfFilter) { - // TODO: this should use bpf_shared.h rather than hardcoding the path + // TODO: this should likely be in the tethering module, where using netd.h would be ok static constexpr char bpfProgPath[] = "/sys/fs/bpf/tethering/prog_offload_schedcls_tether_downstream6_ether"; const int errNOENT = isAtLeastKernelVersion(4, 19, 0) ? ENOENT : EINVAL; @@ -111,7 +111,7 @@ TEST(LibTcUtilsTest, AddAndDeleteBpfFilter) { } TEST(LibTcUtilsTest, AddAndDeleteIngressPoliceFilter) { - // TODO: this should use bpf_shared.h rather than hardcoding the path + // TODO: this should likely be in the tethering module, where using netd.h would be ok static constexpr char bpfProgPath[] = "/sys/fs/bpf/netd_shared/prog_netd_schedact_ingress_account"; int fd = bpf::retrieveProgram(bpfProgPath); From fa647de162427427c586f912a2e043b776cde44f Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Thu, 7 Jul 2022 16:22:27 -0700 Subject: [PATCH 600/777] RaResponder: add support for NS/NA for tests Add support to respond to neighbor solicitations in addition to router solicitations. This is useful for tests that need to send IPv6 traffic through a tap interface. I have previously experimented with the target link-layer address option in the RA, but it did not seem to prevent a subsequent NS. As a TODO, this class should be renamed to NdResponder (and possibly rewritten in Kotlin). Test: test only change Bug: 235559605 Bug: 259849956 Change-Id: I33bac507082fa89d1a5ae02cbe671ce7f5f09b07 Merged-In: I33bac507082fa89d1a5ae02cbe671ce7f5f09b07 --- .../RouterAdvertisementResponder.java | 103 ++++++++++++++---- 1 file changed, 79 insertions(+), 24 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java b/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java index 4ad93d85ce..91c3f766d4 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java @@ -18,12 +18,14 @@ package com.android.testutils; import static android.system.OsConstants.IPPROTO_ICMPV6; -import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN; -import static com.android.net.module.util.NetworkStackConstants.ETHER_SRC_ADDR_OFFSET; import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA; +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION; import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_NODES_MULTICAST; -import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST; +import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE; +import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER; +import static com.android.net.module.util.NetworkStackConstants.NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED; import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_AUTONOMOUS; import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_ON_LINK; @@ -31,6 +33,7 @@ import android.net.InetAddresses; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.MacAddress; +import android.util.ArrayMap; import android.util.Pair; import com.android.net.module.util.Ipv6Utils; @@ -38,18 +41,19 @@ import com.android.net.module.util.Struct; import com.android.net.module.util.structs.EthernetHeader; import com.android.net.module.util.structs.Icmpv6Header; import com.android.net.module.util.structs.Ipv6Header; +import com.android.net.module.util.structs.LlaOption; +import com.android.net.module.util.structs.NsHeader; import com.android.net.module.util.structs.PrefixInformationOption; import com.android.net.module.util.structs.RdnssOption; import java.io.IOException; import java.net.Inet6Address; import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.Map; /** - * RA responder class useful for tests that require a provisioned interface. + * ND (RA & NA) responder class useful for tests that require a provisioned IPv6 interface. + * TODO: rename to NdResponder */ public class RouterAdvertisementResponder extends PacketResponder { private static final String TAG = "RouterAdvertisementResponder"; @@ -57,26 +61,28 @@ public class RouterAdvertisementResponder extends PacketResponder { private static final Inet6Address DNS_SERVER = (Inet6Address) InetAddresses.parseNumericAddress("2001:4860:4860::64"); private final TapPacketReader mPacketReader; - private final List> mRouterList = new ArrayList<>(); + // Maps IPv6 address to MacAddress and isRouter boolean. + private final Map> mNeighborMap = new ArrayMap<>(); public RouterAdvertisementResponder(TapPacketReader packetReader) { - super(packetReader, RouterAdvertisementResponder::isRouterSolicitation, TAG); + super(packetReader, RouterAdvertisementResponder::isRsOrNs, TAG); mPacketReader = packetReader; } - private static boolean isRouterSolicitation(byte[] packet) { + /** Returns true if the packet is a router solicitation or neighbor solicitation message. */ + private static boolean isRsOrNs(byte[] packet) { final ByteBuffer buffer = ByteBuffer.wrap(packet); final EthernetHeader ethHeader = Struct.parse(EthernetHeader.class, buffer); if (ethHeader.etherType != ETHER_TYPE_IPV6) { return false; } final Ipv6Header ipv6Header = Struct.parse(Ipv6Header.class, buffer); - if (ipv6Header.nextHeader != IPPROTO_ICMPV6 - || !ipv6Header.dstIp.equals(IPV6_ADDR_ALL_ROUTERS_MULTICAST)) { + if (ipv6Header.nextHeader != IPPROTO_ICMPV6) { return false; } final Icmpv6Header icmpv6Header = Struct.parse(Icmpv6Header.class, buffer); - return icmpv6Header.type == ICMPV6_ROUTER_SOLICITATION; + return icmpv6Header.type == ICMPV6_ROUTER_SOLICITATION + || icmpv6Header.type == ICMPV6_NEIGHBOR_SOLICITATION; } /** @@ -85,7 +91,16 @@ public class RouterAdvertisementResponder extends PacketResponder { * @param ip the link-local address of the router. */ public void addRouterEntry(MacAddress mac, Inet6Address ip) { - mRouterList.add(new Pair<>(mac, ip)); + mNeighborMap.put(ip, new Pair<>(mac, true)); + } + + /** + * Adds a new neighbor to be advertised. + * @param mac the mac address of the neighbor. + * @param ip the link-local address of the neighbor. + */ + public void addNeighborEntry(MacAddress mac, Inet6Address ip) { + mNeighborMap.put(ip, new Pair<>(mac, false)); } private ByteBuffer buildPrefixOption() { @@ -105,19 +120,59 @@ public class RouterAdvertisementResponder extends PacketResponder { 0/*retransTimer, unspecified*/, buildPrefixOption(), buildRdnssOption()); } + private static void sendResponse(TapPacketReader reader, ByteBuffer buffer) { + try { + reader.sendResponse(buffer); + } catch (IOException e) { + throw new RuntimeException("Failed to send buffer."); + } + } + + private void replyToRouterSolicitation(TapPacketReader reader, MacAddress dstMac) { + for (Map.Entry> it : mNeighborMap.entrySet()) { + final boolean isRouter = it.getValue().second; + if (!isRouter) { + continue; + } + final ByteBuffer raResponse = buildRaPacket(it.getValue().first, dstMac, it.getKey()); + sendResponse(reader, raResponse); + } + } + + private void replyToNeighborSolicitation(TapPacketReader reader, MacAddress dstMac, + Inet6Address dstIp, Inet6Address targetIp) { + final Pair neighbor = mNeighborMap.get(targetIp); + if (neighbor == null) { + return; + } + + final MacAddress srcMac = neighbor.first; + final boolean isRouter = neighbor.second; + int flags = NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED | NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE; + if (isRouter) { + flags |= NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER; + } + + final ByteBuffer tlla = LlaOption.build((byte) ICMPV6_ND_OPTION_TLLA, srcMac); + final ByteBuffer naResponse = Ipv6Utils.buildNaPacket(srcMac, dstMac, targetIp, dstIp, + flags, targetIp, tlla); + sendResponse(reader, naResponse); + } + @Override protected void replyToPacket(byte[] packet, TapPacketReader reader) { - final MacAddress srcMac = MacAddress.fromBytes( - Arrays.copyOfRange(packet, ETHER_SRC_ADDR_OFFSET, - ETHER_SRC_ADDR_OFFSET + ETHER_ADDR_LEN)); + final ByteBuffer buf = ByteBuffer.wrap(packet); + // Messages are filtered by parent class, so it is safe to assume that packet is either an + // RS or NS. + final EthernetHeader ethHdr = Struct.parse(EthernetHeader.class, buf); + final Ipv6Header ipv6Hdr = Struct.parse(Ipv6Header.class, buf); + final Icmpv6Header icmpv6Header = Struct.parse(Icmpv6Header.class, buf); - for (Pair it : mRouterList) { - final ByteBuffer raResponse = buildRaPacket(it.first, srcMac, it.second); - try { - reader.sendResponse(raResponse); - } catch (IOException e) { - throw new RuntimeException("Failed to send RA"); - } + if (icmpv6Header.type == ICMPV6_ROUTER_SOLICITATION) { + replyToRouterSolicitation(reader, ethHdr.srcMac); + } else if (icmpv6Header.type == ICMPV6_NEIGHBOR_SOLICITATION) { + final NsHeader nsHeader = Struct.parse(NsHeader.class, buf); + replyToNeighborSolicitation(reader, ethHdr.srcMac, ipv6Hdr.srcIp, nsHeader.target); } } } From 5a8738e7de92b06fc769a05b7b1069849fc5bb9d Mon Sep 17 00:00:00 2001 From: Ryan Zuklie Date: Thu, 8 Dec 2022 16:44:23 -0800 Subject: [PATCH 601/777] Rename DEFINE_BPF_RINGBUF to DEFINE_BPF_RINGBUF_EXT _EXT suffix is used for the all-args versions of these, such as the one here. Bug: 246985031 Test: build and flash on 4.19 and 5.10 Change-Id: Ibd76cbdc38f4d1f9df4f440147e5f18d9a2ea026 --- .../bpf_headers/include/bpf/bpf_helpers.h | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index ea5659354b..4d48720046 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -182,21 +182,21 @@ static void (*bpf_ringbuf_submit_unsafe)(const void* data, __u64 flags) = (void* // accessing the ring buffer should set a program level min_kver >= 5.8. // * The definition below sets a map min_kver of 5.8 which requires targeting // a BPFLOADER_MIN_VER >= BPFLOADER_S_VERSION. -#define DEFINE_BPF_RINGBUF(the_map, ValueType, size_bytes, usr, grp, md, \ - selinux, pindir, share) \ - DEFINE_BPF_MAP_BASE(the_map, RINGBUF, 0, 0, size_bytes, usr, grp, md, \ - selinux, pindir, share, KVER(5, 8, 0), KVER_INF); \ - static inline __always_inline __unused int bpf_##the_map##_output( \ - const ValueType* v) { \ - return bpf_ringbuf_output_unsafe(&the_map, v, sizeof(*v), 0); \ - } \ - static inline __always_inline __unused \ - ValueType* bpf_##the_map##_reserve() { \ - return bpf_ringbuf_reserve_unsafe(&the_map, sizeof(ValueType), 0); \ - } \ - static inline __always_inline __unused void bpf_##the_map##_submit( \ - const ValueType* v) { \ - bpf_ringbuf_submit_unsafe(v, 0); \ +#define DEFINE_BPF_RINGBUF_EXT(the_map, ValueType, size_bytes, usr, grp, md, \ + selinux, pindir, share) \ + DEFINE_BPF_MAP_BASE(the_map, RINGBUF, 0, 0, size_bytes, usr, grp, md, \ + selinux, pindir, share, KVER(5, 8, 0), KVER_INF); \ + static inline __always_inline __unused int bpf_##the_map##_output( \ + const ValueType* v) { \ + return bpf_ringbuf_output_unsafe(&the_map, v, sizeof(*v), 0); \ + } \ + static inline __always_inline __unused \ + ValueType* bpf_##the_map##_reserve() { \ + return bpf_ringbuf_reserve_unsafe(&the_map, sizeof(ValueType), 0); \ + } \ + static inline __always_inline __unused void bpf_##the_map##_submit( \ + const ValueType* v) { \ + bpf_ringbuf_submit_unsafe(v, 0); \ } /* There exist buggy kernels with pre-T OS, that due to From d03464df217fc0392cc054ae74768a9d0c390d20 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Mon, 12 Dec 2022 18:33:28 +0900 Subject: [PATCH 602/777] Address comments left from aosp/2324894. - address flags preferrence, support u32 flags - assert IP address should not be null - add unit tests for the update. Bug: 260934173 Test: atest NetworkStaticLibTests Change-Id: I18b3a717a9602748617cad279f65c0fefd5dec48 --- .../util/netlink/RtNetlinkAddressMessage.java | 34 +++++----- .../netlink/RtNetlinkAddressMessageTest.java | 63 ++++++++++++++++++- 2 files changed, 79 insertions(+), 18 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java index 3748e46271..c07cec08f7 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java @@ -17,7 +17,6 @@ package com.android.net.module.util.netlink; import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REPLACE; import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; import android.system.OsConstants; @@ -32,6 +31,7 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.Objects; /** * A NetlinkMessage subclass for rtnetlink address messages. @@ -154,21 +154,26 @@ public class RtNetlinkAddressMessage extends NetlinkMessage { /** * A convenience method to create an RTM_NEWADDR message. */ - public static byte[] newRtmNewAddressMessage(int seqNo, final InetAddress ip, short prefixlen, - byte flags, byte scope, int ifIndex, long preferred, long valid) { + public static byte[] newRtmNewAddressMessage(int seqNo, @NonNull final InetAddress ip, + short prefixlen, int flags, byte scope, int ifIndex, long preferred, long valid) { + Objects.requireNonNull(ip, "IP address to be set via netlink message cannot be null"); + final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWADDR; - nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE; + nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; nlmsghdr.nlmsg_seq = seqNo; final RtNetlinkAddressMessage msg = new RtNetlinkAddressMessage(nlmsghdr); final byte family = (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET); - msg.mIfaddrmsg = new StructIfaddrMsg(family, prefixlen, flags, scope, ifIndex); + // IFA_FLAGS attribute is always present within this method, just set flags from + // ifaddrmsg to 0. kernel will prefer the flags from IFA_FLAGS attribute. + msg.mIfaddrmsg = + new StructIfaddrMsg(family, prefixlen, (short) 0 /* flags */, scope, ifIndex); msg.mIpAddress = ip; msg.mIfacacheInfo = new StructIfacacheInfo(preferred, valid, 0 /* cstamp */, 0 /* tstamp */); - msg.mFlags = (int) (flags & 0xFF); + msg.mFlags = flags; final byte[] bytes = new byte[msg.getRequiredSpace()]; nlmsghdr.nlmsg_len = bytes.length; @@ -180,15 +185,14 @@ public class RtNetlinkAddressMessage extends NetlinkMessage { private int getRequiredSpace() { int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructIfaddrMsg.STRUCT_SIZE; - if (mIpAddress != null) { - spaceRequired += NetlinkConstants.alignedLengthOf( - StructNlAttr.NLA_HEADERLEN + mIpAddress.getAddress().length); - } - if (mIfacacheInfo != null) { - spaceRequired += NetlinkConstants.alignedLengthOf( - StructNlAttr.NLA_HEADERLEN + StructIfacacheInfo.STRUCT_SIZE); - } - spaceRequired += StructNlAttr.NLA_HEADERLEN + 4; // IFA_FLAGS "u32" attr + // IFA_ADDRESS attr + spaceRequired += NetlinkConstants.alignedLengthOf( + StructNlAttr.NLA_HEADERLEN + mIpAddress.getAddress().length); + // IFA_CACHEINFO attr + spaceRequired += NetlinkConstants.alignedLengthOf( + StructNlAttr.NLA_HEADERLEN + StructIfacacheInfo.STRUCT_SIZE); + // IFA_FLAGS "u32" attr + spaceRequired += StructNlAttr.NLA_HEADERLEN + 4; return spaceRequired; } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java index b21e06096d..f845eb426b 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java @@ -19,6 +19,9 @@ package com.android.net.module.util.netlink; import static android.system.OsConstants.IFA_F_PERMANENT; import static android.system.OsConstants.NETLINK_ROUTE; import static android.system.OsConstants.RT_SCOPE_LINK; +import static android.system.OsConstants.RT_SCOPE_UNIVERSE; + +import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -48,6 +51,8 @@ import java.nio.ByteOrder; public class RtNetlinkAddressMessageTest { private static final Inet6Address TEST_LINK_LOCAL = (Inet6Address) InetAddresses.parseNumericAddress("FE80::2C41:5CFF:FE09:6665"); + private static final Inet6Address TEST_GLOBAL_ADDRESS = + (Inet6Address) InetAddresses.parseNumericAddress("2001:DB8:1::100"); // An example of the full RTM_NEWADDR message. private static final String RTM_NEWADDR_HEX = @@ -139,13 +144,13 @@ public class RtNetlinkAddressMessageTest { // struct nlmsghdr "48000000" + // length = 72 "1400" + // type = 20 (RTM_NEWADDR) - "0501" + // flags = NLM_F_ACK | NLM_F_REQUEST | NLM_F_REPLACE + "0500" + // flags = NLM_F_ACK | NLM_F_REQUEST "01000000" + // seqno = 1 "00000000" + // pid = 0 (send to kernel) // struct IfaddrMsg "0A" + // family = inet6 "40" + // prefix len = 64 - "80" + // flags = IFA_F_PERMANENT + "00" + // flags = 0 "FD" + // scope = RT_SCOPE_LINK "17000000" + // ifindex = 23 // struct nlattr: IFA_ADDRESS @@ -167,12 +172,64 @@ public class RtNetlinkAddressMessageTest { HexEncoding.decode(expectedNewAddressHex.toCharArray(), false); final byte[] bytes = RtNetlinkAddressMessage.newRtmNewAddressMessage(1 /* seqno */, - TEST_LINK_LOCAL, (short) 64 /* prefix len */, (byte) IFA_F_PERMANENT /* flags */, + TEST_LINK_LOCAL, (short) 64 /* prefix len */, IFA_F_PERMANENT /* flags */, (byte) RT_SCOPE_LINK /* scope */, 23 /* ifindex */, (long) 0xFFFFFFFF /* preferred */, (long) 0xFFFFFFFF /* valid */); assertArrayEquals(expectedNewAddress, bytes); } + @Test + public void testCreateRtmNewAddressMessage_nullIpAddress() { + assertThrows(NullPointerException.class, + () -> RtNetlinkAddressMessage.newRtmNewAddressMessage(1 /* seqno */, + null /* IP address */, (short) 0 /* prefix len */, + IFA_F_PERMANENT /* flags */, (byte) RT_SCOPE_LINK /* scope */, + 23 /* ifindex */, (long) 0xFFFFFFFF /* preferred */, + (long) 0xFFFFFFFF /* valid */)); + } + + @Test + public void testCreateRtmNewAddressMessage_u32Flags() { + // Hexadecimal representation of our created packet. + final String expectedNewAddressHex = + // struct nlmsghdr + "48000000" + // length = 72 + "1400" + // type = 20 (RTM_NEWADDR) + "0500" + // flags = NLM_F_ACK | NLM_F_REQUEST + "01000000" + // seqno = 1 + "00000000" + // pid = 0 (send to kernel) + // struct IfaddrMsg + "0A" + // family = inet6 + "80" + // prefix len = 128 + "00" + // flags = 0 + "00" + // scope = RT_SCOPE_UNIVERSE + "17000000" + // ifindex = 23 + // struct nlattr: IFA_ADDRESS + "1400" + // len + "0100" + // type + "20010DB8000100000000000000000100" + // IP address = 2001:db8:1::100 + // struct nlattr: IFA_CACHEINFO + "1400" + // len + "0600" + // type + "FFFFFFFF" + // preferred = infinite + "FFFFFFFF" + // valid = infinite + "00000000" + // cstamp + "00000000" + // tstamp + // struct nlattr: IFA_FLAGS + "0800" + // len + "0800" + // type + "00030000"; // flags = IFA_F_MANAGETEMPADDR | IFA_F_NOPREFIXROUTE + final byte[] expectedNewAddress = + HexEncoding.decode(expectedNewAddressHex.toCharArray(), false); + + final byte[] bytes = RtNetlinkAddressMessage.newRtmNewAddressMessage(1 /* seqno */, + TEST_GLOBAL_ADDRESS, (short) 128 /* prefix len */, + (int) 0x300 /* flags: IFA_F_MANAGETEMPADDR | IFA_F_NOPREFIXROUTE */, + (byte) RT_SCOPE_UNIVERSE /* scope */, 23 /* ifindex */, + (long) 0xFFFFFFFF /* preferred */, (long) 0xFFFFFFFF /* valid */); + assertArrayEquals(expectedNewAddress, bytes); + } + @Test public void testToString() { final ByteBuffer byteBuffer = toByteBuffer(RTM_NEWADDR_HEX); From ccd5eb9359653037b86e9afa3f003265a03271b6 Mon Sep 17 00:00:00 2001 From: Ryan Zuklie Date: Wed, 30 Nov 2022 10:21:47 -0800 Subject: [PATCH 603/777] Add skeleton BPF ring buffer integration test This adds a BPF program with a ring buffer and an associated test that ensures the program and ring buffer can be loaded by the bpf loader. In the following changes, this foundation will be used to test the user space ring buffer wrapper class. Unlike BpfMap, userspace can't (easily) write to the ring buffer so the most accurate way to test a userspace ring buffer implementation is to write to it from a BPF program. Note: the BPF program in this change is never actually attached to a cgroup, it is only loaded. The program will be executed manually using BPF_PROG_RUN which is "side-effect free" (it can have side effects on BPF maps, but not on Kernel state, e.g. dropping packets). Bug: 246985031 Test: atest libbpf_android_test Change-Id: Ib9c591218188f5f358a755c8854bc6f87d26af12 --- staticlibs/native/bpf_headers/Android.bp | 2 +- .../native/bpf_headers/BpfRingbufTest.cpp | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 staticlibs/native/bpf_headers/BpfRingbufTest.cpp diff --git a/staticlibs/native/bpf_headers/Android.bp b/staticlibs/native/bpf_headers/Android.bp index 98694b2b80..31adef9f3c 100644 --- a/staticlibs/native/bpf_headers/Android.bp +++ b/staticlibs/native/bpf_headers/Android.bp @@ -38,12 +38,12 @@ cc_library_headers { ], } - cc_test { // TODO: Rename to bpf_map_test and modify .gcls as well. name: "libbpf_android_test", srcs: [ "BpfMapTest.cpp", + "BpfRingbufTest.cpp", ], defaults: ["bpf_defaults"], cflags: [ diff --git a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp new file mode 100644 index 0000000000..0785d62488 --- /dev/null +++ b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp @@ -0,0 +1,61 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "bpf/BpfUtils.h" + +namespace android { +namespace bpf { +using ::android::base::testing::HasError; +using ::android::base::testing::HasValue; +using ::android::base::testing::WithMessage; +using ::testing::HasSubstr; + +class BpfRingbufTest : public ::testing::Test { + protected: + BpfRingbufTest() + : mProgPath("/sys/fs/bpf/prog_bpfRingbufProg_skfilter_ringbuf_test"), + mRingbufPath("/sys/fs/bpf/map_bpfRingbufProg_test_ringbuf") {} + + void SetUp() { + if (!android::bpf::isAtLeastKernelVersion(5, 8, 0)) { + GTEST_SKIP() << "BPF ring buffers not supported"; + return; + } + + errno = 0; + mProgram.reset(retrieveProgram(mProgPath.c_str())); + EXPECT_EQ(errno, 0); + ASSERT_GE(mProgram.get(), 0) + << mProgPath << " was either not found or inaccessible."; + } + + std::string mProgPath; + std::string mRingbufPath; + android::base::unique_fd mProgram; +}; + +TEST_F(BpfRingbufTest, CheckSetUp) {} + +} // namespace bpf +} // namespace android From 449c01f6f6e552c011a3e34427eb92da78487de9 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 12 Dec 2022 05:55:12 +0000 Subject: [PATCH 604/777] Use TargetSetupError for ConnectivityCheck If the preparer throws AssertionError, tests will still be retried without re-running the preparer. It needs to throw TargetSetupError to indicate that setup failed. Change-Id: Id01845536a216e1a3ca1c671c97f7bcd992c354e Fixes: 254542801 Test: atest --- .../testutils/ConnectivityCheckTargetPreparer.kt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/staticlibs/testutils/host/com/android/testutils/ConnectivityCheckTargetPreparer.kt b/staticlibs/testutils/host/com/android/testutils/ConnectivityCheckTargetPreparer.kt index 85589ad9e6..ccc40641a2 100644 --- a/staticlibs/testutils/host/com/android/testutils/ConnectivityCheckTargetPreparer.kt +++ b/staticlibs/testutils/host/com/android/testutils/ConnectivityCheckTargetPreparer.kt @@ -21,6 +21,7 @@ import com.android.tradefed.invoker.TestInformation import com.android.tradefed.result.CollectingTestListener import com.android.tradefed.result.ddmlib.DefaultRemoteAndroidTestRunner import com.android.tradefed.targetprep.BaseTargetPreparer +import com.android.tradefed.targetprep.TargetSetupError import com.android.tradefed.targetprep.suite.SuiteApkInstaller private const val CONNECTIVITY_CHECKER_APK = "ConnectivityChecker.apk" @@ -52,13 +53,14 @@ class ConnectivityCheckTargetPreparer : BaseTargetPreparer() { val receiver = CollectingTestListener() if (!testInformation.device.runInstrumentationTests(runner, receiver)) { - throw AssertionError("Device state check failed to complete") + throw TargetSetupError("Device state check failed to complete", + testInformation.device.deviceDescriptor) } val runResult = receiver.currentRunResults if (runResult.isRunFailure) { - throw AssertionError("Failed to check device state before the test: " + - runResult.runFailureMessage) + throw TargetSetupError("Failed to check device state before the test: " + + runResult.runFailureMessage, testInformation.device.deviceDescriptor) } if (!runResult.hasFailedTests()) return @@ -67,7 +69,8 @@ class ConnectivityCheckTargetPreparer : BaseTargetPreparer() { else "$testDescription: ${testResult.stackTrace}" }.joinToString("\n") - throw AssertionError("Device setup checks failed. Check the test bench: \n$errorMsg") + throw TargetSetupError("Device setup checks failed. Check the test bench: \n$errorMsg", + testInformation.device.deviceDescriptor) } override fun tearDown(testInformation: TestInformation?, e: Throwable?) { From 3d4eb94be5c3e3f65d625e6135c18cf118d112ce Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 9 Aug 2022 14:36:59 +0800 Subject: [PATCH 605/777] [ST03] Add test dns server for integration tests This is re-upload of aosp/1390056, CL that fixes test is separated in a follow-up CL that submit at the same time. Bug: 139774492 Test: atest DnsAnswerProviderTest TestDnsServerTest Change-Id: Ia72975f3044f009ebb0f4564a527830268a4a157 --- .../android/testutils/TestDnsServerTest.kt | 122 +++++++++++++ .../android/testutils/DnsAnswerProvider.kt | 65 +++++++ .../com/android/testutils/TestDnsServer.kt | 169 ++++++++++++++++++ 3 files changed, 356 insertions(+) create mode 100644 staticlibs/tests/unit/src/com/android/testutils/TestDnsServerTest.kt create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/DnsAnswerProvider.kt create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/TestDnsServer.kt diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestDnsServerTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestDnsServerTest.kt new file mode 100644 index 0000000000..6f4587b140 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/testutils/TestDnsServerTest.kt @@ -0,0 +1,122 @@ +/* + * 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 com.android.testutils + +import android.net.DnsResolver.CLASS_IN +import android.net.DnsResolver.TYPE_AAAA +import android.net.Network +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.net.module.util.DnsPacket +import com.android.net.module.util.DnsPacket.DnsRecord +import libcore.net.InetAddressUtils +import org.junit.After +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito +import java.net.DatagramPacket +import java.net.DatagramSocket +import java.net.InetAddress +import java.net.InetSocketAddress +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +val TEST_V6_ADDR = InetAddressUtils.parseNumericAddress("2001:db8::3") +const val TEST_DOMAIN = "hello.example.com" + +@RunWith(AndroidJUnit4::class) +@SmallTest +class TestDnsServerTest { + private val network = Mockito.mock(Network::class.java) + private val localAddr = InetSocketAddress(InetAddress.getLocalHost(), 0 /* port */) + private val testServer: TestDnsServer = TestDnsServer(network, localAddr) + + @After + fun tearDown() { + if (testServer.isAlive) testServer.stop() + } + + @Test + fun testStartStop() { + repeat(100) { + val server = TestDnsServer(network, localAddr) + server.start() + assertTrue(server.isAlive) + server.stop() + assertFalse(server.isAlive) + } + + // Test illegal start/stop. + assertFailsWith { testServer.stop() } + testServer.start() + assertTrue(testServer.isAlive) + assertFailsWith { testServer.start() } + testServer.stop() + assertFalse(testServer.isAlive) + assertFailsWith { testServer.stop() } + // TestDnsServer rejects start after stop. + assertFailsWith { testServer.start() } + } + + @Test + fun testHandleDnsQuery() { + testServer.setAnswer(TEST_DOMAIN, listOf(TEST_V6_ADDR)) + testServer.start() + + // Mock query and send it to the test server. + val queryHeader = DnsPacket.DnsHeader(0xbeef /* id */, + 0x0 /* flag */, 1 /* qcount */, 0 /* ancount */) + val qlist = listOf(DnsRecord.makeQuestion(TEST_DOMAIN, TYPE_AAAA, CLASS_IN)) + val queryPacket = TestDnsServer.DnsQueryPacket(queryHeader, qlist, emptyList()) + val response = resolve(queryPacket, testServer.port) + + // Verify expected answer packet. Set QR bit of flag to 1 for response packet + // according to RFC 1035 section 4.1.1. + val answerHeader = DnsPacket.DnsHeader(0xbeef, + 1 shl 15 /* flag */, 1 /* qcount */, 1 /* ancount */) + val alist = listOf(DnsRecord.makeAOrAAAARecord(DnsPacket.ANSECTION, TEST_DOMAIN, + CLASS_IN, DEFAULT_TTL_S, TEST_V6_ADDR)) + val expectedAnswerPacket = TestDnsServer.DnsAnswerPacket(answerHeader, qlist, alist) + assertEquals(expectedAnswerPacket, response) + + // Clean up the server in tearDown. + } + + private fun resolve(queryDnsPacket: DnsPacket, serverPort: Int): TestDnsServer.DnsAnswerPacket { + val bytes = queryDnsPacket.bytes + // Create a new client socket, the socket will be bound to a + // random port other than the server port. + val socket = DatagramSocket(localAddr).also { it.soTimeout = 100 } + val queryPacket = DatagramPacket(bytes, bytes.size, localAddr.address, serverPort) + + // Send query and wait for the reply. + socket.send(queryPacket) + val buffer = ByteArray(MAX_BUF_SIZE) + val reply = DatagramPacket(buffer, buffer.size) + socket.receive(reply) + return TestDnsServer.DnsAnswerPacket(reply.data) + } + + // TODO: Add more tests, which includes: + // * Empty question RR packet (or more unexpected states) + // * No answer found (setAnswer empty list at L.78) + // * Test one or multi A record(s) + // * Test multi AAAA records + // * Test CNAME records +} diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DnsAnswerProvider.kt b/staticlibs/testutils/devicetests/com/android/testutils/DnsAnswerProvider.kt new file mode 100644 index 0000000000..6a804bf937 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/DnsAnswerProvider.kt @@ -0,0 +1,65 @@ +/* + * 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 com.android.testutils + +import android.net.DnsResolver.CLASS_IN +import com.android.net.module.util.DnsPacket +import com.android.net.module.util.DnsPacket.ANSECTION +import java.net.InetAddress +import java.util.concurrent.ConcurrentHashMap + +const val DEFAULT_TTL_S = 5L + +/** + * Helper class to store the mapping of DNS queries. + * + * DnsAnswerProvider is built atop a ConcurrentHashMap and as such it provides the same + * guarantees as ConcurrentHashMap between writing and reading elements. Specifically : + * - Setting an answer happens-before reading the same answer. + * - Callers can read and write concurrently from DnsAnswerProvider and expect no + * ConcurrentModificationException. + * Freshness of the answers depends on ordering of the threads ; if callers need a + * freshness guarantee, they need to provide the happens-before relationship from a + * write that they want to observe to the read that they need to be observed. + */ +class DnsAnswerProvider { + private val mDnsKeyToRecords = ConcurrentHashMap>() + + /** + * Get answer for the specified hostname. + * + * @param query the target hostname. + * @param type type of record, could be A or AAAA. + * + * @return list of [DnsPacket.DnsRecord] associated to the query. Empty if no record matches. + */ + fun getAnswer(query: String, type: Int) = mDnsKeyToRecords[query] + .orEmpty().filter { it.nsType == type } + + /** Set answer for the specified {@code query}. + * + * @param query the target hostname + * @param addresses [List] which could be used to generate multiple A or AAAA + * RRs with the corresponding addresses. + */ + fun setAnswer(query: String, hosts: List) = mDnsKeyToRecords.put(query, hosts.map { + DnsPacket.DnsRecord.makeAOrAAAARecord(ANSECTION, query, CLASS_IN, DEFAULT_TTL_S, it) + }) + + fun clearAnswer(query: String) = mDnsKeyToRecords.remove(query) + fun clearAll() = mDnsKeyToRecords.clear() +} \ No newline at end of file diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestDnsServer.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestDnsServer.kt new file mode 100644 index 0000000000..c63b38f929 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestDnsServer.kt @@ -0,0 +1,169 @@ +/* + * 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 com.android.testutils + +import android.net.Network +import android.util.Log +import com.android.internal.annotations.GuardedBy +import com.android.internal.annotations.VisibleForTesting +import com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE +import com.android.net.module.util.DnsPacket +import java.net.DatagramPacket +import java.net.DatagramSocket +import java.net.InetAddress +import java.net.InetSocketAddress +import java.net.SocketAddress +import java.net.SocketException +import java.util.ArrayList + +private const val TAG = "TestDnsServer" +private const val VDBG = true +@VisibleForTesting(visibility = PRIVATE) +const val MAX_BUF_SIZE = 8192 + +/** + * A simple implementation of Dns Server that can be bound on specific address and Network. + * + * The caller should use start() to make the server start a new thread to receive DNS queries + * on the bound address, [isAlive] to check status, and stop() for stopping. + * The server allows user to manipulate the records to be answered through + * [setAnswer] at runtime. + * + * This server runs on its own thread. Please make sure writing the query to the socket + * happens-after using [setAnswer] to guarantee the correct answer is returned. If possible, + * use [setAnswer] before calling [start] for simplicity. + */ +class TestDnsServer(network: Network, addr: InetSocketAddress) { + enum class Status { + NOT_STARTED, STARTED, STOPPED + } + @GuardedBy("thread") + private var status: Status = Status.NOT_STARTED + private val thread = ReceivingThread() + private val socket = DatagramSocket(addr).also { network.bindSocket(it) } + private val ansProvider = DnsAnswerProvider() + + // The buffer to store the received packet. They are being reused for + // efficiency and it's fine because they are only ever accessed + // on the server thread in a sequential manner. + private val buffer = ByteArray(MAX_BUF_SIZE) + private val packet = DatagramPacket(buffer, buffer.size) + + fun setAnswer(hostname: String, answer: List) = + ansProvider.setAnswer(hostname, answer) + + private fun processPacket() { + // Blocking read and try construct a DnsQueryPacket object. + socket.receive(packet) + val q = DnsQueryPacket(packet.data) + handleDnsQuery(q, packet.socketAddress) + } + + // TODO: Add support to reply some error with a DNS reply packet with failure RCODE. + private fun handleDnsQuery(q: DnsQueryPacket, src: SocketAddress) { + val queryRecords = q.queryRecords + if (queryRecords.size != 1) { + throw IllegalArgumentException( + "Expected one dns query record but got ${queryRecords.size}" + ) + } + val answerRecords = queryRecords[0].let { ansProvider.getAnswer(it.dName, it.nsType) } + + if (VDBG) { + Log.v(TAG, "handleDnsPacket: " + + queryRecords.map { "${it.dName},${it.nsType}" }.joinToString() + + " ansCount=${answerRecords.size} socketAddress=$src") + } + + val bytes = q.getAnswerPacket(answerRecords).bytes + val reply = DatagramPacket(bytes, bytes.size, src) + socket.send(reply) + } + + fun start() { + synchronized(thread) { + if (status != Status.NOT_STARTED) { + throw IllegalStateException("unexpected status: $status") + } + thread.start() + status = Status.STARTED + } + } + fun stop() { + synchronized(thread) { + if (status != Status.STARTED) { + throw IllegalStateException("unexpected status: $status") + } + socket.close() + thread.interrupt() + thread.join() + status = Status.STOPPED + } + } + val isAlive get() = thread.isAlive + val port get() = socket.localPort + + inner class ReceivingThread : Thread() { + override fun run() { + Log.i(TAG, "starting addr={${socket.localSocketAddress}}") + while (!interrupted() && !socket.isClosed) { + try { + processPacket() + } catch (e: InterruptedException) { + // The caller terminated the server, exit. + break + } catch (e: SocketException) { + // The caller terminated the server, exit. + break + } + } + Log.i(TAG, "exiting socket={$socket}") + } + } + + @VisibleForTesting(visibility = PRIVATE) + class DnsQueryPacket : DnsPacket { + constructor(data: ByteArray) : super(data) + constructor(header: DnsHeader, qd: List, an: List) : + super(header, qd, an) + + init { + if (mHeader.isResponse) { + throw ParseException("Not a query packet") + } + } + + val queryRecords: List + get() = mRecords[QDSECTION] + + fun getAnswerPacket(ar: List): DnsAnswerPacket { + // Set QR bit of flag to 1 for response packet according to RFC 1035 section 4.1.1. + val flags = 1 shl 15 + val qr = ArrayList(mRecords[QDSECTION]) + // Copy the query packet header id to the answer packet as RFC 1035 section 4.1.1. + val header = DnsHeader(mHeader.id, flags, qr.size, ar.size) + return DnsAnswerPacket(header, qr, ar) + } + } + + class DnsAnswerPacket : DnsPacket { + constructor(header: DnsHeader, qr: List, ar: List) : + super(header, qr, ar) + @VisibleForTesting(visibility = PRIVATE) + constructor(bytes: ByteArray) : super(bytes) + } +} From 041620a6fb2d4a364122e1a7a50e5262dc47e03b Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 3 Aug 2022 15:54:23 +0900 Subject: [PATCH 606/777] Randomize the prefix used by RouterAdvertisementResponder. Currently RouterAdvertisementResponder always uses a prefix of 2001:db8::/64, even if there are multiple instances on different interfaces. Randomize the prefix instead. Test: TH Bug: 240323229 Bug: 235559605 Bug: 259849956 Change-Id: I585ca804845f4278187602a6c9816470dcea04f8 Merged-In: I585ca804845f4278187602a6c9816470dcea04f8 (cherry picked from commit 6ab502437e77fde3346f45376fc6212d2825b27b) --- .../RouterAdvertisementResponder.java | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java b/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java index 91c3f766d4..51df935179 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java @@ -31,7 +31,6 @@ import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_ON_LINK import android.net.InetAddresses; import android.net.IpPrefix; -import android.net.LinkAddress; import android.net.MacAddress; import android.util.ArrayMap; import android.util.Pair; @@ -50,6 +49,8 @@ import java.io.IOException; import java.net.Inet6Address; import java.nio.ByteBuffer; import java.util.Map; +import java.util.Objects; +import java.util.Random; /** * ND (RA & NA) responder class useful for tests that require a provisioned IPv6 interface. @@ -57,16 +58,30 @@ import java.util.Map; */ public class RouterAdvertisementResponder extends PacketResponder { private static final String TAG = "RouterAdvertisementResponder"; - private static final LinkAddress SLAAC_PREFIX = new LinkAddress("2001:db8::/64"); private static final Inet6Address DNS_SERVER = (Inet6Address) InetAddresses.parseNumericAddress("2001:4860:4860::64"); private final TapPacketReader mPacketReader; // Maps IPv6 address to MacAddress and isRouter boolean. private final Map> mNeighborMap = new ArrayMap<>(); + private final IpPrefix mPrefix; - public RouterAdvertisementResponder(TapPacketReader packetReader) { + public RouterAdvertisementResponder(TapPacketReader packetReader, IpPrefix prefix) { super(packetReader, RouterAdvertisementResponder::isRsOrNs, TAG); mPacketReader = packetReader; + mPrefix = Objects.requireNonNull(prefix); + } + + public RouterAdvertisementResponder(TapPacketReader packetReader) { + this(packetReader, makeRandomPrefix()); + } + + private static IpPrefix makeRandomPrefix() { + final byte[] prefixBytes = new IpPrefix("2001:db8::/64").getAddress().getAddress(); + final Random r = new Random(); + for (int i = 4; i < 8; i++) { + prefixBytes[i] = (byte) r.nextInt(); + } + return new IpPrefix(prefixBytes, 64); } /** Returns true if the packet is a router solicitation or neighbor solicitation message. */ @@ -103,11 +118,17 @@ public class RouterAdvertisementResponder extends PacketResponder { mNeighborMap.put(ip, new Pair<>(mac, false)); } + /** + * @return the prefix that is announced in the Router Advertisements sent by this object. + */ + public IpPrefix getPrefix() { + return mPrefix; + } + private ByteBuffer buildPrefixOption() { return PrefixInformationOption.build( - new IpPrefix(SLAAC_PREFIX.getAddress(), SLAAC_PREFIX.getPrefixLength()), - (byte) (PIO_FLAG_ON_LINK | PIO_FLAG_AUTONOMOUS), 3600/*valid lifetime*/, - 3600/*preferred lifetime*/); + mPrefix, (byte) (PIO_FLAG_ON_LINK | PIO_FLAG_AUTONOMOUS), + 3600 /* valid lifetime */, 3600 /* preferred lifetime */); } private ByteBuffer buildRdnssOption() { From 70b03f92998e7988bce5ccc9470d7bb5a9eab4c8 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 17 Nov 2022 15:18:27 +0800 Subject: [PATCH 607/777] Interrupt thread before closing socket Test failed when socket.close() ran, and in the other thread we are trying to initialize an InetSocketAddress. If the socket was closed, the port got from the socket object becomes -1 hence the InetSocketAddress cannot be constructed and the IllegalArgumentException would be thrown. Interrupt thread before closing socket to prevent from the race. Test: atest TestDnsServerTest --rerun-until-failure 1000 Fix: 259160848 Change-Id: I219ee1e32144ba9983a28765e7a84621c27c1c09 --- .../devicetests/com/android/testutils/TestDnsServer.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestDnsServer.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestDnsServer.kt index c63b38f929..e1b771b2f2 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestDnsServer.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestDnsServer.kt @@ -108,8 +108,13 @@ class TestDnsServer(network: Network, addr: InetSocketAddress) { if (status != Status.STARTED) { throw IllegalStateException("unexpected status: $status") } - socket.close() + // The thread needs to be interrupted before closing the socket to prevent a data + // race where the thread tries to read from the socket while it's being closed. + // DatagramSocket is not thread-safe and running both concurrently can end up in + // getPort() returning -1 after it's been checked not to, resulting in a crash by + // IllegalArgumentException inside the DatagramSocket implementation. thread.interrupt() + socket.close() thread.join() status = Status.STOPPED } @@ -119,7 +124,6 @@ class TestDnsServer(network: Network, addr: InetSocketAddress) { inner class ReceivingThread : Thread() { override fun run() { - Log.i(TAG, "starting addr={${socket.localSocketAddress}}") while (!interrupted() && !socket.isClosed) { try { processPacket() From 8a00b8cf7cbc995786e0ba207dc3caa1a5b4f84b Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 12 Dec 2022 19:26:13 +0900 Subject: [PATCH 608/777] Add a physical local native network type. There are no local networks yet, but they will come in followup patches. Test: netd_integration_test Bug: 64955351 Change-Id: Ic82cf2390f52024e44e03b264b55c9843b932b71 --- staticlibs/netd/Android.bp | 12 +- .../aidl_api/netd_aidl_interface/11/.hash | 1 + .../11/android/net/INetd.aidl | 222 ++++++++++++++++++ .../net/INetdUnsolicitedEventListener.aidl | 48 ++++ .../net/InterfaceConfigurationParcel.aidl | 42 ++++ .../11/android/net/MarkMaskParcel.aidl | 39 +++ .../11/android/net/NativeNetworkConfig.aidl | 44 ++++ .../11/android/net/NativeNetworkType.aidl | 40 ++++ .../11/android/net/NativeVpnType.aidl | 41 ++++ .../11/android/net/RouteInfoParcel.aidl | 40 ++++ .../11/android/net/TetherConfigParcel.aidl | 39 +++ .../android/net/TetherOffloadRuleParcel.aidl | 44 ++++ .../11/android/net/TetherStatsParcel.aidl | 43 ++++ .../11/android/net/UidRangeParcel.aidl | 40 ++++ .../net/netd/aidl/NativeUidRangeConfig.aidl | 41 ++++ .../android/net/NativeNetworkType.aidl | 1 + .../android/net/NativeNetworkConfig.aidl | 6 +- .../binder/android/net/NativeNetworkType.aidl | 7 +- 18 files changed, 742 insertions(+), 8 deletions(-) create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/11/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/NativeNetworkConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/NativeNetworkType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/NativeVpnType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/netd/aidl/NativeUidRangeConfig.aidl diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index 79bde9b56c..6cc445b8d4 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -21,7 +21,7 @@ java_library { sdk_version: "system_current", min_sdk_version: "29", static_libs: [ - "netd_aidl_interface-V10-java", + "netd_aidl_interface-V11-java", ], apex_available: [ "//apex_available:platform", // used from services.net @@ -44,7 +44,7 @@ cc_library_static { cc_library_static { name: "netd_aidl_interface-lateststable-ndk", whole_static_libs: [ - "netd_aidl_interface-V10-ndk", + "netd_aidl_interface-V11-ndk", ], apex_available: [ "com.android.resolv", @@ -55,12 +55,12 @@ cc_library_static { cc_defaults { name: "netd_aidl_interface_lateststable_cpp_static", - static_libs: ["netd_aidl_interface-V10-cpp"], + static_libs: ["netd_aidl_interface-V11-cpp"], } cc_defaults { name: "netd_aidl_interface_lateststable_cpp_shared", - shared_libs: ["netd_aidl_interface-V10-cpp"], + shared_libs: ["netd_aidl_interface-V11-cpp"], } aidl_interface { @@ -149,6 +149,10 @@ aidl_interface { version: "10", imports: [], }, + { + version: "11", + imports: [], + }, ], diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/11/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/11/.hash new file mode 100644 index 0000000000..d22cb04b48 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/11/.hash @@ -0,0 +1 @@ +d384a1d9f2f6dc0301a43d2b9d6d3a49e3898ae7 diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/INetd.aidl new file mode 100644 index 0000000000..e671fdb781 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/INetd.aidl @@ -0,0 +1,222 @@ +/** + * Copyright (c) 2016, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreatePhysical(int netId, int permission); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + void networkCreate(in android.net.NativeNetworkConfig config); + void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int CLAT_MARK = -559038041; + const int LOCAL_NET_ID = 99; + const int DUMMY_NET_ID = 51; + const int UNREACHABLE_NET_ID = 52; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + /** + * @deprecated use FIREWALL_ALLOWLIST. + */ + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_ALLOWLIST = 0; + /** + * @deprecated use FIREWALL_DENYLIST. + */ + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_DENYLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const int FIREWALL_CHAIN_RESTRICTED = 4; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..31775dfd11 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2018, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..1869d8d49e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..8ea20d118f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/MarkMaskParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/NativeNetworkConfig.aidl new file mode 100644 index 0000000000..77d814b825 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/NativeNetworkConfig.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeNetworkConfig { + int netId; + android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL; + int permission; + boolean secure; + android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM; + boolean excludeLocalRoutes = false; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/NativeNetworkType.aidl new file mode 100644 index 0000000000..e77a1432e8 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/NativeNetworkType.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeNetworkType { + PHYSICAL = 0, + VIRTUAL = 1, + PHYSICAL_LOCAL = 2, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/NativeVpnType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/NativeVpnType.aidl new file mode 100644 index 0000000000..8a8be83958 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/NativeVpnType.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeVpnType { + SERVICE = 1, + PLATFORM = 2, + LEGACY = 3, + OEM = 4, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5ef95e67ca --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/RouteInfoParcel.aidl @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2020, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..7b39c22e4e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/TetherConfigParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..983e9860ea --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..5f1b722690 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/TetherStatsParcel.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..72e987a2af --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/UidRangeParcel.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/netd/aidl/NativeUidRangeConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/netd/aidl/NativeUidRangeConfig.aidl new file mode 100644 index 0000000000..9bb679f1c1 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/11/android/net/netd/aidl/NativeUidRangeConfig.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.netd.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeUidRangeConfig { + int netId; + android.net.UidRangeParcel[] uidRanges; + int subPriority; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl index 06c8979d51..e77a1432e8 100644 --- a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl @@ -36,4 +36,5 @@ package android.net; enum NativeNetworkType { PHYSICAL = 0, VIRTUAL = 1, + PHYSICAL_LOCAL = 2, } diff --git a/staticlibs/netd/binder/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/binder/android/net/NativeNetworkConfig.aidl index e654a1f4cf..96eccc7acf 100644 --- a/staticlibs/netd/binder/android/net/NativeNetworkConfig.aidl +++ b/staticlibs/netd/binder/android/net/NativeNetworkConfig.aidl @@ -31,13 +31,13 @@ parcelable NativeNetworkConfig { int netId; /** - * The type of network, e.g. physical network or virtual network. + * The type of network : virtual, physical or physical local network. */ NativeNetworkType networkType = NativeNetworkType.PHYSICAL; /** - * For physical networks. The permission necessary to use the network. Must be one of - * PERMISSION_NONE/PERMISSION_NETWORK/PERMISSION_SYSTEM. Ignored for all other network types. + * The permission necessary to use the network. Must be PERMISSION_NONE, PERMISSION_NETWORK + * or PERMISSION_SYSTEM. Ignored for virtual network types. */ int permission; diff --git a/staticlibs/netd/binder/android/net/NativeNetworkType.aidl b/staticlibs/netd/binder/android/net/NativeNetworkType.aidl index d667029470..7005535791 100644 --- a/staticlibs/netd/binder/android/net/NativeNetworkType.aidl +++ b/staticlibs/netd/binder/android/net/NativeNetworkType.aidl @@ -27,4 +27,9 @@ enum NativeNetworkType { * Virtual private network type. */ VIRTUAL = 1, -} \ No newline at end of file + + /** + * Physical local network, such as a tethering downstream. + */ + PHYSICAL_LOCAL = 2, +} From f3e13a3fddd8a9168f8e31a33507cdb850081365 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 15 Dec 2022 11:29:46 +0900 Subject: [PATCH 609/777] Add DHCPv6 relevant constants such as port and multicast group address. Bug: 260934173 Test: m Change-Id: Ice5e9c7fa3f2250654a6a9822d05786831bd66c4 --- .../net/module/util/NetworkStackConstants.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 287473e60f..7b3943cea7 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -209,6 +209,17 @@ public final class NetworkStackConstants { public static final int INFINITE_LEASE = 0xffffffff; public static final int DHCP4_CLIENT_PORT = 68; + /** + * DHCPv6 constants. + * + * See also: + * - https://datatracker.ietf.org/doc/html/rfc8415 + */ + public static final int DHCP6_CLIENT_PORT = 546; + public static final int DHCP6_SERVER_PORT = 547; + public static final Inet6Address ALL_DHCP_RELAY_AGENTS_AND_SERVERS = + (Inet6Address) InetAddresses.parseNumericAddress("ff02::1:2"); + /** * IEEE802.11 standard constants. * From f618ab0769ae0f7564f483d729555b273ac39f54 Mon Sep 17 00:00:00 2001 From: chiachangwang Date: Fri, 16 Dec 2022 07:26:33 +0000 Subject: [PATCH 610/777] Add SocketUtils in the shared libs SocketUtils in the framework should be better to move to shared lib since it's commonly used by modules. But it is exposed in API surface, so it cannnot simply move from framework to shared lib. Create a SocketUtils in libs to deprecate the usage of the original SocketUtils so that adding extra socket utils will not be restricted by API release. Test: m Change-Id: Idf57071a4bd89a6114dda9a9c9c19fd0e5db54c5 --- staticlibs/Android.bp | 1 + .../android/net/module/util/SocketUtils.java | 58 +++++++++++++++++++ .../net/module/util/ip/NetlinkMonitor.java | 13 +---- 3 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 staticlibs/device/com/android/net/module/util/SocketUtils.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 63c8b4e99d..d8a397d0a4 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -40,6 +40,7 @@ java_library { "device/com/android/net/module/util/NetworkMonitorUtils.java", "device/com/android/net/module/util/PacketReader.java", "device/com/android/net/module/util/SharedLog.java", + "device/com/android/net/module/util/SocketUtils.java", // This library is used by system modules, for which the system health impact of Kotlin // has not yet been evaluated. Annotations may need jarjar'ing. // "src_devicecommon/**/*.kt", diff --git a/staticlibs/device/com/android/net/module/util/SocketUtils.java b/staticlibs/device/com/android/net/module/util/SocketUtils.java new file mode 100644 index 0000000000..9878ea5c95 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/SocketUtils.java @@ -0,0 +1,58 @@ +/* + * 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 com.android.net.module.util; + +import static android.net.util.SocketUtils.closeSocket; + +import android.annotation.NonNull; +import android.system.NetlinkSocketAddress; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.SocketAddress; + +/** + * Collection of utilities to interact with raw sockets. + * + * This class also provides utilities to interact with {@link android.net.util.SocketUtils} + * because it is in the API surface could not be simply move the frameworks/libs/net/ + * to share with module. + * + * TODO: deprecate android.net.util.SocketUtils and replace with this class. + */ +public class SocketUtils { + + /** + * Make a socket address to communicate with netlink. + */ + @NonNull + public static SocketAddress makeNetlinkSocketAddress(int portId, int groupsMask) { + return new NetlinkSocketAddress(portId, groupsMask); + } + + /** + * Close a socket, ignoring any exception while closing. + */ + public static void closeSocketQuietly(FileDescriptor fd) { + try { + closeSocket(fd); + } catch (IOException ignored) { + } + } + + private SocketUtils() {} +} diff --git a/staticlibs/device/com/android/net/module/util/ip/NetlinkMonitor.java b/staticlibs/device/com/android/net/module/util/ip/NetlinkMonitor.java index 942aaf1267..9b23671918 100644 --- a/staticlibs/device/com/android/net/module/util/ip/NetlinkMonitor.java +++ b/staticlibs/device/com/android/net/module/util/ip/NetlinkMonitor.java @@ -16,7 +16,6 @@ package com.android.net.module.util.ip; -import static android.net.util.SocketUtils.makeNetlinkSocketAddress; import static android.system.OsConstants.AF_NETLINK; import static android.system.OsConstants.ENOBUFS; import static android.system.OsConstants.SOCK_DGRAM; @@ -24,10 +23,11 @@ import static android.system.OsConstants.SOCK_NONBLOCK; import static android.system.OsConstants.SOL_SOCKET; import static android.system.OsConstants.SO_RCVBUF; +import static com.android.net.module.util.SocketUtils.closeSocketQuietly; +import static com.android.net.module.util.SocketUtils.makeNetlinkSocketAddress; import static com.android.net.module.util.netlink.NetlinkConstants.hexify; import android.annotation.NonNull; -import android.net.util.SocketUtils; import android.os.Handler; import android.os.SystemClock; import android.system.ErrnoException; @@ -41,7 +41,6 @@ import com.android.net.module.util.netlink.NetlinkMessage; import com.android.net.module.util.netlink.NetlinkSocket; import java.io.FileDescriptor; -import java.io.IOException; import java.net.SocketAddress; import java.net.SocketException; import java.nio.ByteBuffer; @@ -179,14 +178,6 @@ public class NetlinkMonitor extends PacketReader { return true; } - // TODO: move NetworkStackUtils to frameworks/libs/net for NetworkStackUtils#closeSocketQuietly. - private void closeSocketQuietly(FileDescriptor fd) { - try { - SocketUtils.closeSocket(fd); - } catch (IOException ignored) { - } - } - /** * Processes one netlink message. Must be overridden by subclasses. * @param nlMsg the message to process. From d8c03fec3aa1a491052ee48ba9b0fd1240fa01d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 16 Dec 2022 20:59:00 +0000 Subject: [PATCH 611/777] BpfSyscallWrapper - use 'enum bpf_cmd' instead of int for bpf() arg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I73d8d33e1677088fbbed02c554c88269912d2f76 --- .../native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h index d5b7670158..f7d6a380c7 100644 --- a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h +++ b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h @@ -38,7 +38,7 @@ namespace bpf { * all unused portions are zero. It will fail with E2BIG if we don't fully zero bpf_attr. */ -inline int bpf(int cmd, const bpf_attr& attr) { +inline int bpf(enum bpf_cmd cmd, const bpf_attr& attr) { return syscall(__NR_bpf, cmd, &attr, sizeof(attr)); } From 8da25a73a503d59387510247fd57822ed671d6c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sun, 18 Dec 2022 11:11:03 +0000 Subject: [PATCH 612/777] remove unused SKIP_IF_XDP_NOT_SUPPORTED macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I2480cbe958d2827440e5dd827b43a89f4b7a556c --- staticlibs/native/bpf_headers/include/bpf/BpfUtils.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index 157f210c83..65c542f587 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -126,11 +126,5 @@ static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsign // so we can just trivialize this #define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED -#define SKIP_IF_XDP_NOT_SUPPORTED \ - do { \ - if (!android::bpf::isAtLeastKernelVersion(5, 9, 0)) \ - GTEST_SKIP() << "Skip: xdp not supported."; \ - } while (0) - } // namespace bpf } // namespace android From d6ba77ab89daacd138a0669818de3a3dcde51a15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sun, 18 Dec 2022 11:04:12 +0000 Subject: [PATCH 613/777] remove no longer needed SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can merge this now that: https://googleplex-android-review.git.corp.google.com/c/platform/system/netd/+/20284735 'bpf_base_test - unconditionally run TestSocketFilterSetUp' has been pulled into tm-mainline-prod. Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I1b65cd41ce7b4eaab7f1fead2742c72e48294244 --- staticlibs/native/bpf_headers/include/bpf/BpfUtils.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index 65c542f587..a6e4783d59 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -121,10 +121,5 @@ static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsign GTEST_SKIP() << "Skip: bpf is not supported."; \ } while (0) -// Only used by tm-mainline-prod's system/netd/tests/bpf_base_test.cpp -// but platform and platform tests aren't expected to build/work in tm-mainline-prod -// so we can just trivialize this -#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED - } // namespace bpf } // namespace android From ec6505edd62380f2a3060a12e0857c8d91c61359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sun, 18 Dec 2022 19:48:07 +0000 Subject: [PATCH 614/777] remove SKIP_IF_BPF_NOT_SUPPORTED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is only user left, let us simply move the macro definition into the resolv_integration_test.cpp file. Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I6eb66abaa7f6392ab43300e5087e4277491e44c9 --- staticlibs/native/bpf_headers/include/bpf/BpfUtils.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index a6e4783d59..dc4fb17970 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -115,11 +115,5 @@ static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsign return kernelVersion() >= KVER(major, minor, sub); } -#define SKIP_IF_BPF_NOT_SUPPORTED \ - do { \ - if (!android::bpf::isAtLeastKernelVersion(4, 9, 0)) \ - GTEST_SKIP() << "Skip: bpf is not supported."; \ - } while (0) - } // namespace bpf } // namespace android From 29bbf2dace42b370cffcb97cec0423c876ee2255 Mon Sep 17 00:00:00 2001 From: chiachangwang Date: Fri, 16 Dec 2022 10:54:04 +0000 Subject: [PATCH 615/777] Add common netlink operation and definition for TCP socket polling Move code to common lib to support coming TCP socket polling design in connectivity module to prevent code duplication. Bug: 259000745 Test: atest FrameworksNetTests Change-Id: I89ca1c19122c3b4306b93a6a253e0ea67259eb77 --- .../net/module/util/ip/IpNeighborMonitor.java | 4 +- .../net/module/util/ip/NetlinkMonitor.java | 6 +- .../module/util/netlink/InetDiagMessage.java | 25 ++- .../module/util/netlink/NetlinkSocket.java | 174 ---------------- .../net/module/util/netlink/NetlinkUtils.java | 189 ++++++++++++++++-- .../module/util/ip/ConntrackMonitorTest.java | 4 +- ...kSocketTest.java => NetlinkUtilsTest.java} | 26 ++- 7 files changed, 216 insertions(+), 212 deletions(-) delete mode 100644 staticlibs/device/com/android/net/module/util/netlink/NetlinkSocket.java rename staticlibs/tests/unit/src/com/android/net/module/util/netlink/{NetlinkSocketTest.java => NetlinkUtilsTest.java} (89%) diff --git a/staticlibs/device/com/android/net/module/util/ip/IpNeighborMonitor.java b/staticlibs/device/com/android/net/module/util/ip/IpNeighborMonitor.java index 4a61794188..e88e7f0c92 100644 --- a/staticlibs/device/com/android/net/module/util/ip/IpNeighborMonitor.java +++ b/staticlibs/device/com/android/net/module/util/ip/IpNeighborMonitor.java @@ -31,7 +31,7 @@ import android.util.Log; import com.android.net.module.util.SharedLog; import com.android.net.module.util.netlink.NetlinkMessage; -import com.android.net.module.util.netlink.NetlinkSocket; +import com.android.net.module.util.netlink.NetlinkUtils; import com.android.net.module.util.netlink.RtNetlinkNeighborMessage; import com.android.net.module.util.netlink.StructNdMsg; @@ -68,7 +68,7 @@ public class IpNeighborMonitor extends NetlinkMonitor { 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null); try { - NetlinkSocket.sendOneShotKernelMessage(NETLINK_ROUTE, msg); + NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, msg); } catch (ErrnoException e) { Log.e(TAG, "Error " + msgSnippet + ": " + e); return -e.errno; diff --git a/staticlibs/device/com/android/net/module/util/ip/NetlinkMonitor.java b/staticlibs/device/com/android/net/module/util/ip/NetlinkMonitor.java index 9b23671918..f882483da8 100644 --- a/staticlibs/device/com/android/net/module/util/ip/NetlinkMonitor.java +++ b/staticlibs/device/com/android/net/module/util/ip/NetlinkMonitor.java @@ -38,7 +38,7 @@ import com.android.net.module.util.PacketReader; import com.android.net.module.util.SharedLog; import com.android.net.module.util.netlink.NetlinkErrorMessage; import com.android.net.module.util.netlink.NetlinkMessage; -import com.android.net.module.util.netlink.NetlinkSocket; +import com.android.net.module.util.netlink.NetlinkUtils; import java.io.FileDescriptor; import java.net.SocketAddress; @@ -82,7 +82,7 @@ public class NetlinkMonitor extends PacketReader { */ public NetlinkMonitor(@NonNull Handler h, @NonNull SharedLog log, @NonNull String tag, int family, int bindGroups, int sockRcvbufSize) { - super(h, NetlinkSocket.DEFAULT_RECV_BUFSIZE); + super(h, NetlinkUtils.DEFAULT_RECV_BUFSIZE); mLog = log.forSubComponent(tag); mTag = tag; mFamily = family; @@ -109,7 +109,7 @@ public class NetlinkMonitor extends PacketReader { } } Os.bind(fd, makeNetlinkSocketAddress(0, mBindGroups)); - NetlinkSocket.connectToKernel(fd); + NetlinkUtils.connectSocketToNetlink(fd); if (DBG) { final SocketAddress nlAddr = Os.getsockname(fd); diff --git a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java index eff1f25dbe..5a180e7b5c 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java @@ -19,11 +19,12 @@ package com.android.net.module.util.netlink; import static android.os.Process.INVALID_UID; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.NETLINK_INET_DIAG; import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY; -import static com.android.net.module.util.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE; +import static com.android.net.module.util.netlink.NetlinkUtils.DEFAULT_RECV_BUFSIZE; import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; @@ -132,8 +133,8 @@ public class InetDiagMessage extends NetlinkMessage { FileDescriptor fd) throws ErrnoException, InterruptedIOException { byte[] msg = inetDiagReqV2(protocol, local, remote, family, flags); - NetlinkSocket.sendMessage(fd, msg, 0, msg.length, TIMEOUT_MS); - ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT_MS); + NetlinkUtils.sendMessage(fd, msg, 0, msg.length, TIMEOUT_MS); + ByteBuffer response = NetlinkUtils.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT_MS); final NetlinkMessage nlMsg = NetlinkMessage.parse(response, NETLINK_INET_DIAG); if (nlMsg == null) { @@ -210,8 +211,8 @@ public class InetDiagMessage extends NetlinkMessage { int uid = INVALID_UID; FileDescriptor fd = null; try { - fd = NetlinkSocket.forProto(NETLINK_INET_DIAG); - NetlinkSocket.connectToKernel(fd); + fd = NetlinkUtils.netlinkSocketForProto(NETLINK_INET_DIAG); + NetlinkUtils.connectSocketToNetlink(fd); uid = lookupUid(protocol, local, remote, fd); } catch (ErrnoException | SocketException | IllegalArgumentException | InterruptedIOException e) { @@ -228,6 +229,20 @@ public class InetDiagMessage extends NetlinkMessage { return uid; } + /** + * Construct an inet_diag_req_v2 message for querying alive TCP sockets from kernel. + */ + public static byte[] buildInetDiagReqForAliveTcpSockets(int family) { + return inetDiagReqV2(IPPROTO_TCP, + null /* local addr */, + null /* remote addr */, + family, + (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_DUMP) /* flag */, + 0 /* pad */, + 1 << NetlinkConstants.INET_DIAG_MEMINFO /* idiagExt */, + NetlinkUtils.TCP_MONITOR_STATE_FILTER); + } + @Override public String toString() { return "InetDiagMessage{ " diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkSocket.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkSocket.java deleted file mode 100644 index ec326dd7c2..0000000000 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkSocket.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2015 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 com.android.net.module.util.netlink; - -import static android.net.util.SocketUtils.makeNetlinkSocketAddress; -import static android.system.OsConstants.AF_NETLINK; -import static android.system.OsConstants.EIO; -import static android.system.OsConstants.EPROTO; -import static android.system.OsConstants.ETIMEDOUT; -import static android.system.OsConstants.SOCK_DGRAM; -import static android.system.OsConstants.SOL_SOCKET; -import static android.system.OsConstants.SO_RCVBUF; -import static android.system.OsConstants.SO_RCVTIMEO; -import static android.system.OsConstants.SO_SNDTIMEO; - -import android.net.util.SocketUtils; -import android.system.ErrnoException; -import android.system.Os; -import android.system.StructTimeval; -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.SocketException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - - -/** - * NetlinkSocket - * - * A small static class to assist with AF_NETLINK socket operations. - * - * @hide - */ -public class NetlinkSocket { - private static final String TAG = "NetlinkSocket"; - private static final long IO_TIMEOUT_MS = 300L; - - public static final int DEFAULT_RECV_BUFSIZE = 8 * 1024; - public static final int SOCKET_RECV_BUFSIZE = 64 * 1024; - - /** - * Send one netlink message to kernel via netlink socket. - * - * @param nlProto netlink protocol type. - * @param msg the raw bytes of netlink message to be sent. - */ - public static void sendOneShotKernelMessage(int nlProto, byte[] msg) throws ErrnoException { - final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage"; - final FileDescriptor fd = forProto(nlProto); - - try { - connectToKernel(fd); - sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT_MS); - final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT_MS); - // recvMessage() guaranteed to not return null if it did not throw. - final NetlinkMessage response = NetlinkMessage.parse(bytes, nlProto); - if (response != null && response instanceof NetlinkErrorMessage - && (((NetlinkErrorMessage) response).getNlMsgError() != null)) { - final int errno = ((NetlinkErrorMessage) response).getNlMsgError().error; - if (errno != 0) { - // TODO: consider ignoring EINVAL (-22), which appears to be - // normal when probing a neighbor for which the kernel does - // not already have / no longer has a link layer address. - Log.e(TAG, errPrefix + ", errmsg=" + response.toString()); - // Note: convert kernel errnos (negative) into userspace errnos (positive). - throw new ErrnoException(response.toString(), Math.abs(errno)); - } - } else { - final String errmsg; - if (response == null) { - bytes.position(0); - errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes); - } else { - errmsg = response.toString(); - } - Log.e(TAG, errPrefix + ", errmsg=" + errmsg); - throw new ErrnoException(errmsg, EPROTO); - } - } catch (InterruptedIOException e) { - Log.e(TAG, errPrefix, e); - throw new ErrnoException(errPrefix, ETIMEDOUT, e); - } catch (SocketException e) { - Log.e(TAG, errPrefix, e); - throw new ErrnoException(errPrefix, EIO, e); - } finally { - try { - SocketUtils.closeSocket(fd); - } catch (IOException e) { - // Nothing we can do here - } - } - } - - /** - * Create netlink socket with the given netlink protocol type. - * - * @return fd the fileDescriptor of the socket. - * Throw ErrnoException if the exception is thrown. - */ - public static FileDescriptor forProto(int nlProto) throws ErrnoException { - final FileDescriptor fd = Os.socket(AF_NETLINK, SOCK_DGRAM, nlProto); - Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, SOCKET_RECV_BUFSIZE); - return fd; - } - - /** - * Connect to kernel via netlink socket. - * - * Throw ErrnoException, SocketException if the exception is thrown. - */ - public static void connectToKernel(FileDescriptor fd) throws ErrnoException, SocketException { - Os.connect(fd, makeNetlinkSocketAddress(0, 0)); - } - - private static void checkTimeout(long timeoutMs) { - if (timeoutMs < 0) { - throw new IllegalArgumentException("Negative timeouts not permitted"); - } - } - - /** - * Wait up to |timeoutMs| (or until underlying socket error) for a - * netlink message of at most |bufsize| size. - * - * Multi-threaded calls with different timeouts will cause unexpected results. - */ - public static ByteBuffer recvMessage(FileDescriptor fd, int bufsize, long timeoutMs) - throws ErrnoException, IllegalArgumentException, InterruptedIOException { - checkTimeout(timeoutMs); - - Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs)); - - ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize); - int length = Os.read(fd, byteBuffer); - if (length == bufsize) { - Log.w(TAG, "maximum read"); - } - byteBuffer.position(0); - byteBuffer.limit(length); - byteBuffer.order(ByteOrder.nativeOrder()); - return byteBuffer; - } - - /** - * Send a message to a peer to which this socket has previously connected, - * waiting at most |timeoutMs| milliseconds for the send to complete. - * - * Multi-threaded calls with different timeouts will cause unexpected results. - */ - public static int sendMessage( - FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs) - throws ErrnoException, IllegalArgumentException, InterruptedIOException { - checkTimeout(timeoutMs); - Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs)); - return Os.write(fd, bytes, offset, count); - } -} diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java index 34c468acfd..ae16cf8d19 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java @@ -16,13 +16,40 @@ package com.android.net.module.util.netlink; -import static android.system.OsConstants.IPPROTO_TCP; +import static android.net.util.SocketUtils.makeNetlinkSocketAddress; +import static android.system.OsConstants.AF_NETLINK; +import static android.system.OsConstants.EIO; +import static android.system.OsConstants.EPROTO; +import static android.system.OsConstants.ETIMEDOUT; +import static android.system.OsConstants.NETLINK_INET_DIAG; +import static android.system.OsConstants.SOCK_CLOEXEC; +import static android.system.OsConstants.SOCK_DGRAM; +import static android.system.OsConstants.SOL_SOCKET; +import static android.system.OsConstants.SO_RCVBUF; +import static android.system.OsConstants.SO_RCVTIMEO; +import static android.system.OsConstants.SO_SNDTIMEO; + +import android.net.util.SocketUtils; +import android.system.ErrnoException; +import android.system.Os; +import android.system.StructTimeval; +import android.util.Log; + +import androidx.annotation.NonNull; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.SocketException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; /** - * Utilities for netlink related class. + * Utilities for netlink related class that may not be able to fit into a specific class. * @hide */ public class NetlinkUtils { + private static final String TAG = "NetlinkUtils"; /** Corresponds to enum from bionic/libc/include/netinet/tcp.h. */ private static final int TCP_ESTABLISHED = 1; private static final int TCP_SYN_SENT = 2; @@ -31,17 +58,155 @@ public class NetlinkUtils { public static final int TCP_MONITOR_STATE_FILTER = (1 << TCP_ESTABLISHED) | (1 << TCP_SYN_SENT) | (1 << TCP_SYN_RECV); + public static final int UNKNOWN_MARK = 0xffffffff; + public static final int NULL_MASK = 0; + + // Initial mark value corresponds to the initValue in system/netd/include/Fwmark.h. + public static final int INIT_MARK_VALUE = 0; + // Corresponds to enum definition in bionic/libc/kernel/uapi/linux/inet_diag.h + public static final int INET_DIAG_INFO = 2; + public static final int INET_DIAG_MARK = 15; + + public static final long IO_TIMEOUT_MS = 300L; + + public static final int DEFAULT_RECV_BUFSIZE = 8 * 1024; + public static final int SOCKET_RECV_BUFSIZE = 64 * 1024; + /** - * Construct an inet_diag_req_v2 message for querying alive TCP sockets from kernel. + * Return whether the input ByteBuffer contains enough remaining bytes for + * {@code StructNlMsgHdr}. */ - public static byte[] buildInetDiagReqForAliveTcpSockets(int family) { - return InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, - null /* local addr */, - null /* remote addr */, - family, - (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_DUMP) /* flag */, - 0 /* pad */, - 1 << NetlinkConstants.INET_DIAG_MEMINFO /* idiagExt */, - TCP_MONITOR_STATE_FILTER); + public static boolean enoughBytesRemainForValidNlMsg(@NonNull final ByteBuffer bytes) { + return bytes.remaining() >= StructNlMsgHdr.STRUCT_SIZE; } + + /** + * Send one netlink message to kernel via netlink socket. + * + * @param nlProto netlink protocol type. + * @param msg the raw bytes of netlink message to be sent. + */ + public static void sendOneShotKernelMessage(int nlProto, byte[] msg) throws ErrnoException { + final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage"; + final FileDescriptor fd = netlinkSocketForProto(nlProto); + + try { + connectSocketToNetlink(fd); + sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT_MS); + final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT_MS); + // recvMessage() guaranteed to not return null if it did not throw. + final NetlinkMessage response = NetlinkMessage.parse(bytes, nlProto); + if (response != null && response instanceof NetlinkErrorMessage + && (((NetlinkErrorMessage) response).getNlMsgError() != null)) { + final int errno = ((NetlinkErrorMessage) response).getNlMsgError().error; + if (errno != 0) { + // TODO: consider ignoring EINVAL (-22), which appears to be + // normal when probing a neighbor for which the kernel does + // not already have / no longer has a link layer address. + Log.e(TAG, errPrefix + ", errmsg=" + response.toString()); + // Note: convert kernel errnos (negative) into userspace errnos (positive). + throw new ErrnoException(response.toString(), Math.abs(errno)); + } + } else { + final String errmsg; + if (response == null) { + bytes.position(0); + errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes); + } else { + errmsg = response.toString(); + } + Log.e(TAG, errPrefix + ", errmsg=" + errmsg); + throw new ErrnoException(errmsg, EPROTO); + } + } catch (InterruptedIOException e) { + Log.e(TAG, errPrefix, e); + throw new ErrnoException(errPrefix, ETIMEDOUT, e); + } catch (SocketException e) { + Log.e(TAG, errPrefix, e); + throw new ErrnoException(errPrefix, EIO, e); + } finally { + try { + SocketUtils.closeSocket(fd); + } catch (IOException e) { + // Nothing we can do here + } + } + } + + /** + * Create netlink socket with the given netlink protocol type. + * + * @return fd the fileDescriptor of the socket. + * @throws ErrnoException if the FileDescriptor not connect to be created successfully + */ + public static FileDescriptor netlinkSocketForProto(int nlProto) throws ErrnoException { + final FileDescriptor fd = Os.socket(AF_NETLINK, SOCK_DGRAM, nlProto); + Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, SOCKET_RECV_BUFSIZE); + return fd; + } + + /** + * Construct a netlink inet_diag socket. + */ + public static FileDescriptor createNetLinkInetDiagSocket() throws ErrnoException { + return Os.socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_INET_DIAG); + } + + /** + * Connect the given file descriptor to the Netlink interface to the kernel. + * + * The fd must be a SOCK_DGRAM socket : create it with {@link #netlinkSocketForProto} + * + * @throws ErrnoException if the {@code fd} could not connect to kernel successfully + * @throws SocketException if there is an error accessing a socket. + */ + public static void connectSocketToNetlink(FileDescriptor fd) + throws ErrnoException, SocketException { + Os.connect(fd, makeNetlinkSocketAddress(0, 0)); + } + + private static void checkTimeout(long timeoutMs) { + if (timeoutMs < 0) { + throw new IllegalArgumentException("Negative timeouts not permitted"); + } + } + + /** + * Wait up to |timeoutMs| (or until underlying socket error) for a + * netlink message of at most |bufsize| size. + * + * Multi-threaded calls with different timeouts will cause unexpected results. + */ + public static ByteBuffer recvMessage(FileDescriptor fd, int bufsize, long timeoutMs) + throws ErrnoException, IllegalArgumentException, InterruptedIOException { + checkTimeout(timeoutMs); + + Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs)); + + final ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize); + final int length = Os.read(fd, byteBuffer); + if (length == bufsize) { + Log.w(TAG, "maximum read"); + } + byteBuffer.position(0); + byteBuffer.limit(length); + byteBuffer.order(ByteOrder.nativeOrder()); + return byteBuffer; + } + + /** + * Send a message to a peer to which this socket has previously connected. + * + * This waits at most |timeoutMs| milliseconds for the send to complete, will get the exception + * if it times out. + */ + public static int sendMessage( + FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs) + throws ErrnoException, IllegalArgumentException, InterruptedIOException { + checkTimeout(timeoutMs); + Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs)); + return Os.write(fd, bytes, offset, count); + } + + private NetlinkUtils() {} } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/ip/ConntrackMonitorTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/ip/ConntrackMonitorTest.java index 99d8f0739d..7ee376c98d 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/ip/ConntrackMonitorTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/ip/ConntrackMonitorTest.java @@ -47,7 +47,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.net.module.util.SharedLog; import com.android.net.module.util.ip.ConntrackMonitor.ConntrackEvent; import com.android.net.module.util.netlink.NetlinkConstants; -import com.android.net.module.util.netlink.NetlinkSocket; +import com.android.net.module.util.netlink.NetlinkUtils; import libcore.util.HexEncoding; @@ -104,7 +104,7 @@ public class ConntrackMonitorTest { private void sendMessage(byte[] msg) { mHandler.post(() -> { try { - NetlinkSocket.sendMessage(mWriteFd, msg, 0 /* offset */, msg.length, + NetlinkUtils.sendMessage(mWriteFd, msg, 0 /* offset */, msg.length, TIMEOUT_MS); } catch (ErrnoException | InterruptedIOException e) { fail("Unable to send netfilter message: " + e); diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkSocketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java similarity index 89% rename from staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkSocketTest.java rename to staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java index f4073b6dc0..7a1639aeb5 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkSocketTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java @@ -22,7 +22,7 @@ import static android.system.OsConstants.AF_UNSPEC; import static android.system.OsConstants.EACCES; import static android.system.OsConstants.NETLINK_ROUTE; -import static com.android.net.module.util.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE; +import static com.android.net.module.util.netlink.NetlinkUtils.DEFAULT_RECV_BUFSIZE; import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; @@ -42,8 +42,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.modules.utils.build.SdkLevel; import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; import libcore.io.IoUtils; @@ -56,17 +54,17 @@ import java.nio.ByteOrder; @RunWith(AndroidJUnit4.class) @SmallTest -public class NetlinkSocketTest { - private static final String TAG = "NetlinkSocketTest"; +public class NetlinkUtilsTest { + private static final String TAG = "NetlinkUitlsTest"; private static final int TEST_SEQNO = 5; private static final int TEST_TIMEOUT_MS = 500; @Test public void testGetNeighborsQuery() throws Exception { - final FileDescriptor fd = NetlinkSocket.forProto(NETLINK_ROUTE); + final FileDescriptor fd = NetlinkUtils.netlinkSocketForProto(NETLINK_ROUTE); assertNotNull(fd); - NetlinkSocket.connectToKernel(fd); + NetlinkUtils.connectSocketToNetlink(fd); final NetlinkSocketAddress localAddr = (NetlinkSocketAddress) Os.getsockname(fd); assertNotNull(localAddr); @@ -85,7 +83,7 @@ public class NetlinkSocketTest { // Apps targeting an SDK version > S are not allowed to send RTM_GETNEIGH{TBL} messages if (SdkLevel.isAtLeastT() && targetSdk > 31) { try { - NetlinkSocket.sendMessage(fd, req, 0, req.length, TEST_TIMEOUT_MS); + NetlinkUtils.sendMessage(fd, req, 0, req.length, TEST_TIMEOUT_MS); fail("RTM_GETNEIGH is not allowed for apps targeting SDK > 31 on T+ platforms," + " target SDK version: " + targetSdk); } catch (ErrnoException e) { @@ -97,14 +95,14 @@ public class NetlinkSocketTest { // Check that apps targeting lower API levels / running on older platforms succeed assertEquals(req.length, - NetlinkSocket.sendMessage(fd, req, 0, req.length, TEST_TIMEOUT_MS)); + NetlinkUtils.sendMessage(fd, req, 0, req.length, TEST_TIMEOUT_MS)); int neighMessageCount = 0; int doneMessageCount = 0; while (doneMessageCount == 0) { ByteBuffer response = - NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TEST_TIMEOUT_MS); + NetlinkUtils.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TEST_TIMEOUT_MS); assertNotNull(response); assertTrue(StructNlMsgHdr.STRUCT_SIZE <= response.limit()); assertEquals(0, response.position()); @@ -141,10 +139,10 @@ public class NetlinkSocketTest { @Test public void testBasicWorkingGetAddrQuery() throws Exception { - final FileDescriptor fd = NetlinkSocket.forProto(NETLINK_ROUTE); + final FileDescriptor fd = NetlinkUtils.netlinkSocketForProto(NETLINK_ROUTE); assertNotNull(fd); - NetlinkSocket.connectToKernel(fd); + NetlinkUtils.connectSocketToNetlink(fd); final NetlinkSocketAddress localAddr = (NetlinkSocketAddress) Os.getsockname(fd); assertNotNull(localAddr); @@ -156,12 +154,12 @@ public class NetlinkSocketTest { assertNotNull(req); final long timeout = 500; - assertEquals(req.length, NetlinkSocket.sendMessage(fd, req, 0, req.length, timeout)); + assertEquals(req.length, NetlinkUtils.sendMessage(fd, req, 0, req.length, timeout)); int addrMessageCount = 0; while (true) { - ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, timeout); + ByteBuffer response = NetlinkUtils.recvMessage(fd, DEFAULT_RECV_BUFSIZE, timeout); assertNotNull(response); assertTrue(StructNlMsgHdr.STRUCT_SIZE <= response.limit()); assertEquals(0, response.position()); From 6776e3b02b0799e0b7afdf914162193fefea1e50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 10 Dec 2022 12:18:23 +0000 Subject: [PATCH 616/777] remove spurious #include and OVERFLOW_COUNTERSET MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I8ad1b19905509862bdfa4e710da778ed0effb058 --- staticlibs/native/bpf_headers/BpfRingbufTest.cpp | 1 + staticlibs/native/bpf_headers/include/bpf/BpfMap.h | 2 ++ staticlibs/native/bpf_headers/include/bpf/BpfUtils.h | 9 --------- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp index 0785d62488..4a45a93b3e 100644 --- a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp +++ b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp @@ -22,6 +22,7 @@ #include #include +#include "BpfSyscallWrappers.h" #include "bpf/BpfUtils.h" namespace android { diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h index 47256fa098..51e6d162bd 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h @@ -22,6 +22,8 @@ #include #include #include + +#include "BpfSyscallWrappers.h" #include "bpf/BpfUtils.h" namespace android { diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index 157f210c83..89068166d2 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -25,21 +25,12 @@ #include #include -#include - #include #include -#include "BpfSyscallWrappers.h" - -// The buffer size for the buffer that records program loading logs, needs to be large enough for -// the largest kernel program. - namespace android { namespace bpf { -constexpr const int OVERFLOW_COUNTERSET = 2; - constexpr const uint64_t NONEXISTENT_COOKIE = 0; static inline uint64_t getSocketCookie(int sockFd) { From 8531cfe5dda13fcb56ffbebbb4e39d9b6940fcef Mon Sep 17 00:00:00 2001 From: Ryan Zuklie Date: Thu, 15 Dec 2022 16:11:37 -0800 Subject: [PATCH 617/777] Add option to skip map/prog based on build type This feature allows skipping a program or map based on the type of the build. This allows things like userdebug-only programs. Bug: 246985031 Test: added test program and watched it skipped on userdebug Change-Id: I5cd9725ad8f133c98c86e6ba620a266313055157 --- .../bpf_headers/include/bpf/bpf_map_def.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h index 02caf07e93..f17cf3ac1a 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h @@ -174,7 +174,14 @@ struct bpf_map_def { char pin_subdir[BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE]; bool shared; // use empty string as 'file' component of pin path - allows cross .o map sharing - char pad0[3]; // manually pad up to 4 byte alignment, may be used for extensions in the future + + // The following 3 ignore_on_* fields were added in version 0.32 (U). These are ignored in + // older bpfloader versions, and zero in programs compiled before 0.32. + bool ignore_on_eng:1; + bool ignore_on_user:1; + bool ignore_on_userdebug:1; + + char pad0[2]; // manually pad up to 4 byte alignment, may be used for extensions in the future unsigned int uid; // uid_t }; @@ -196,7 +203,14 @@ struct bpf_prog_def { unsigned int max_kver; bool optional; // program section (ie. function) may fail to load, continue onto next func. - char pad0[3]; + + // The following 3 ignore_on_* fields were added in version 0.32 (U). These are ignored in + // older bpfloader versions, and zero in programs compiled before 0.32. + bool ignore_on_eng:1; + bool ignore_on_user:1; + bool ignore_on_userdebug:1; + + char pad0[2]; // manually pad up to 4 byte alignment, may be used for extensions in the future // The following fields were added in version 0.1 unsigned int bpfloader_min_ver; // if missing, defaults to 0, ie. v0.0 From 111118096a3f9dd54c9a781401c268089c205881 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 16 Dec 2022 02:17:07 +0000 Subject: [PATCH 618/777] Add XFRM_MIGRATE support and freeze INetd v12. This commit updates netd_aidl_interface to support migrating IPsec tunnel mode SA to different source and destination addresses. server/aidl_api/netd_aidl_interface/12/ are generated by "m netd_aidl_interface-freeze-api" Bug: 169170985 Test: atest netd_integration_test (new tests) Change-Id: I89b54272c1528f12e6351819e0efe666af7a2946 --- staticlibs/netd/Android.bp | 13 +- .../aidl_api/netd_aidl_interface/12/.hash | 1 + .../12/android/net/INetd.aidl | 225 ++++++++++++++++++ .../net/INetdUnsolicitedEventListener.aidl | 48 ++++ .../net/InterfaceConfigurationParcel.aidl | 42 ++++ .../android/net/IpSecMigrateInfoParcel.aidl | 45 ++++ .../12/android/net/MarkMaskParcel.aidl | 39 +++ .../12/android/net/NativeNetworkConfig.aidl | 44 ++++ .../12/android/net/NativeNetworkType.aidl | 40 ++++ .../12/android/net/NativeVpnType.aidl | 41 ++++ .../12/android/net/RouteInfoParcel.aidl | 40 ++++ .../12/android/net/TetherConfigParcel.aidl | 39 +++ .../android/net/TetherOffloadRuleParcel.aidl | 44 ++++ .../12/android/net/TetherStatsParcel.aidl | 43 ++++ .../12/android/net/UidRangeParcel.aidl | 40 ++++ .../net/netd/aidl/NativeUidRangeConfig.aidl | 41 ++++ .../current/android/net/INetd.aidl | 3 + .../android/net/IpSecMigrateInfoParcel.aidl | 45 ++++ staticlibs/netd/binder/android/net/INetd.aidl | 26 +- .../android/net/IpSecMigrateInfoParcel.aidl | 50 ++++ 20 files changed, 904 insertions(+), 5 deletions(-) create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/12/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/IpSecMigrateInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/NativeNetworkConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/NativeNetworkType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/NativeVpnType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/netd/aidl/NativeUidRangeConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/IpSecMigrateInfoParcel.aidl create mode 100644 staticlibs/netd/binder/android/net/IpSecMigrateInfoParcel.aidl diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index 6cc445b8d4..057ea2aae8 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -21,7 +21,7 @@ java_library { sdk_version: "system_current", min_sdk_version: "29", static_libs: [ - "netd_aidl_interface-V11-java", + "netd_aidl_interface-V12-java", ], apex_available: [ "//apex_available:platform", // used from services.net @@ -44,7 +44,7 @@ cc_library_static { cc_library_static { name: "netd_aidl_interface-lateststable-ndk", whole_static_libs: [ - "netd_aidl_interface-V11-ndk", + "netd_aidl_interface-V12-ndk", ], apex_available: [ "com.android.resolv", @@ -55,12 +55,12 @@ cc_library_static { cc_defaults { name: "netd_aidl_interface_lateststable_cpp_static", - static_libs: ["netd_aidl_interface-V11-cpp"], + static_libs: ["netd_aidl_interface-V12-cpp"], } cc_defaults { name: "netd_aidl_interface_lateststable_cpp_shared", - shared_libs: ["netd_aidl_interface-V11-cpp"], + shared_libs: ["netd_aidl_interface-V12-cpp"], } aidl_interface { @@ -71,6 +71,7 @@ aidl_interface { // AIDL interface that callers can implement to receive networking events from netd. "binder/android/net/INetdUnsolicitedEventListener.aidl", "binder/android/net/InterfaceConfigurationParcel.aidl", + "binder/android/net/IpSecMigrateInfoParcel.aidl", "binder/android/net/MarkMaskParcel.aidl", "binder/android/net/NativeNetworkConfig.aidl", "binder/android/net/NativeNetworkType.aidl", @@ -153,6 +154,10 @@ aidl_interface { version: "11", imports: [], }, + { + version: "12", + imports: [], + }, ], diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/12/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/12/.hash new file mode 100644 index 0000000000..7a4d53c20a --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/12/.hash @@ -0,0 +1 @@ +5a3a5f46fe31c118889d7a92be4faafb3df651ff diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/INetd.aidl new file mode 100644 index 0000000000..763b92ac60 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/INetd.aidl @@ -0,0 +1,225 @@ +/** + * Copyright (c) 2016, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreatePhysical(int netId, int permission); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + void networkCreate(in android.net.NativeNetworkConfig config); + void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + void ipSecMigrate(in android.net.IpSecMigrateInfoParcel migrateInfo); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int CLAT_MARK = -559038041; + const int LOCAL_NET_ID = 99; + const int DUMMY_NET_ID = 51; + const int UNREACHABLE_NET_ID = 52; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = -1; + /** + * @deprecated use FIREWALL_ALLOWLIST. + */ + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_ALLOWLIST = 0; + /** + * @deprecated use FIREWALL_DENYLIST. + */ + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_DENYLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const int FIREWALL_CHAIN_RESTRICTED = 4; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; + const int IPSEC_DIRECTION_IN = 0; + const int IPSEC_DIRECTION_OUT = 1; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..31775dfd11 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2018, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..1869d8d49e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/IpSecMigrateInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/IpSecMigrateInfoParcel.aidl new file mode 100644 index 0000000000..975a26199d --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/IpSecMigrateInfoParcel.aidl @@ -0,0 +1,45 @@ +/** + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@JavaOnlyImmutable +parcelable IpSecMigrateInfoParcel { + int requestId; + int selAddrFamily; + int direction; + @utf8InCpp String oldSourceAddress; + @utf8InCpp String oldDestinationAddress; + @utf8InCpp String newSourceAddress; + @utf8InCpp String newDestinationAddress; + int interfaceId; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..8ea20d118f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/MarkMaskParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/NativeNetworkConfig.aidl new file mode 100644 index 0000000000..77d814b825 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/NativeNetworkConfig.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeNetworkConfig { + int netId; + android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL; + int permission; + boolean secure; + android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM; + boolean excludeLocalRoutes = false; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/NativeNetworkType.aidl new file mode 100644 index 0000000000..e77a1432e8 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/NativeNetworkType.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeNetworkType { + PHYSICAL = 0, + VIRTUAL = 1, + PHYSICAL_LOCAL = 2, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/NativeVpnType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/NativeVpnType.aidl new file mode 100644 index 0000000000..8a8be83958 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/NativeVpnType.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeVpnType { + SERVICE = 1, + PLATFORM = 2, + LEGACY = 3, + OEM = 4, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5ef95e67ca --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/RouteInfoParcel.aidl @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2020, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..7b39c22e4e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/TetherConfigParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..983e9860ea --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..5f1b722690 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/TetherStatsParcel.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..72e987a2af --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/UidRangeParcel.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/netd/aidl/NativeUidRangeConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/netd/aidl/NativeUidRangeConfig.aidl new file mode 100644 index 0000000000..9bb679f1c1 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/12/android/net/netd/aidl/NativeUidRangeConfig.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.netd.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeUidRangeConfig { + int netId; + android.net.UidRangeParcel[] uidRanges; + int subPriority; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl index e671fdb781..763b92ac60 100644 --- a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl @@ -168,6 +168,7 @@ interface INetd { void networkCreate(in android.net.NativeNetworkConfig config); void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + void ipSecMigrate(in android.net.IpSecMigrateInfoParcel migrateInfo); const int IPV4 = 4; const int IPV6 = 6; const int CONF = 1; @@ -219,4 +220,6 @@ interface INetd { const String IF_FLAG_POINTOPOINT = "point-to-point"; const String IF_FLAG_RUNNING = "running"; const String IF_FLAG_MULTICAST = "multicast"; + const int IPSEC_DIRECTION_IN = 0; + const int IPSEC_DIRECTION_OUT = 1; } diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/IpSecMigrateInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/IpSecMigrateInfoParcel.aidl new file mode 100644 index 0000000000..975a26199d --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/IpSecMigrateInfoParcel.aidl @@ -0,0 +1,45 @@ +/** + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@JavaOnlyImmutable +parcelable IpSecMigrateInfoParcel { + int requestId; + int selAddrFamily; + int direction; + @utf8InCpp String oldSourceAddress; + @utf8InCpp String oldDestinationAddress; + @utf8InCpp String newSourceAddress; + @utf8InCpp String newDestinationAddress; + int interfaceId; +} diff --git a/staticlibs/netd/binder/android/net/INetd.aidl b/staticlibs/netd/binder/android/net/INetd.aidl index 8bf8e5b9d6..dff07c6e3e 100644 --- a/staticlibs/netd/binder/android/net/INetd.aidl +++ b/staticlibs/netd/binder/android/net/INetd.aidl @@ -18,6 +18,7 @@ package android.net; import android.net.INetdUnsolicitedEventListener; import android.net.InterfaceConfigurationParcel; +import android.net.IpSecMigrateInfoParcel; import android.net.MarkMaskParcel; import android.net.NativeNetworkConfig; import android.net.RouteInfoParcel; @@ -265,7 +266,7 @@ interface INetd { int spi); /** - * Create an IpSec Security Association describing how ip(v6) traffic will be encrypted + * Update an IPsec SA (xfrm_state) describing how ip(v6) traffic will be encrypted * or decrypted. * * @param transformId a unique identifier for allocated resources @@ -1396,4 +1397,27 @@ interface INetd { * unix errno. */ void networkRemoveUidRangesParcel(in NativeUidRangeConfig uidRangesConfig); + + /** + * Migrate an existing IPsec tunnel mode SA to different addresses. + * + * If the underlying network also changes, caller must update it by + * calling ipSecAddSecurityAssociation. + * + * @param migrateInfo parcelable with migration info. + * + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the failure. + */ + void ipSecMigrate(in android.net.IpSecMigrateInfoParcel migrateInfo); + + /** + * IPSEC_DIRECTION_IN is used for IPsec SAs or policies that direct traffic towards the host. + */ + const int IPSEC_DIRECTION_IN = 0; + + /** + * IPSEC_DIRECTION_OUT is used for IPsec SAs or policies that direct traffic away from the host. + */ + const int IPSEC_DIRECTION_OUT = 1; } diff --git a/staticlibs/netd/binder/android/net/IpSecMigrateInfoParcel.aidl b/staticlibs/netd/binder/android/net/IpSecMigrateInfoParcel.aidl new file mode 100644 index 0000000000..e192d66308 --- /dev/null +++ b/staticlibs/netd/binder/android/net/IpSecMigrateInfoParcel.aidl @@ -0,0 +1,50 @@ +/** + * 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; + +@JavaOnlyImmutable +parcelable IpSecMigrateInfoParcel { + /** The unique identifier for allocated resources. */ + int requestId; + /** + * The address family identifier for the new selector. Can be AF_INET + * or AF_INET6. + */ + int selAddrFamily; + /** IPSEC_DIRECTION_IN or IPSEC_DIRECTION_OUT. */ + int direction; + /** + * The IP address for the current sending endpoint. + * + * The local address for an outbound SA and the remote address for an + * inbound SA. + */ + @utf8InCpp String oldSourceAddress; + /** + * The IP address for the current receiving endpoint. + * + * The remote address for an outbound SA and the local address for an + * inbound SA. + */ + @utf8InCpp String oldDestinationAddress; + /** The IP address for the new sending endpoint. */ + @utf8InCpp String newSourceAddress; + /** The IP address for the new receiving endpoint. */ + @utf8InCpp String newDestinationAddress; + /** The identifier for the XFRM interface. */ + int interfaceId; +} From 4045840fd453c533856b36b79983ae9d74d1a09b Mon Sep 17 00:00:00 2001 From: lucaslin Date: Tue, 20 Dec 2022 02:59:41 +0000 Subject: [PATCH 619/777] Add @JvmOverloads for eventuallyExpect and expectAvailableCallbacks It's useful for the java code to have the overload methods for eventuallyExpect and expectAvailableCallbacks. Bug: 231749077 Test: atest CtsHostsideNetworkTests:HostsideVpnTests Change-Id: I6bb1385ee84d1ff1e9f0472e6de3f452ab142958 --- .../com/android/testutils/TestableNetworkCallback.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index 92c83b7ff6..124d13402f 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -46,7 +46,7 @@ open class RecorderCallback private constructor( private val backingRecord: ArrayTrackRecord ) : NetworkCallback() { public constructor() : this(ArrayTrackRecord()) - protected constructor(src: RecorderCallback?): this(src?.backingRecord ?: ArrayTrackRecord()) + protected constructor(src: RecorderCallback?) : this(src?.backingRecord ?: ArrayTrackRecord()) private val TAG = this::class.simpleName @@ -177,7 +177,7 @@ open class TestableNetworkCallback private constructor( constructor( timeoutMs: Long = DEFAULT_TIMEOUT, noCallbackTimeoutMs: Long = DEFAULT_NO_CALLBACK_TIMEOUT - ): this(null, timeoutMs, noCallbackTimeoutMs) + ) : this(null, timeoutMs, noCallbackTimeoutMs) fun createLinkedCopy() = TestableNetworkCallback( this, defaultTimeoutMs, defaultNoCallbackTimeoutMs) @@ -373,6 +373,7 @@ open class TestableNetworkCallback private constructor( assertNotNull(it, "Callback ${T::class} not received within ${timeoutMs}ms") } as T + @JvmOverloads fun eventuallyExpect( type: KClass, timeoutMs: Long = defaultTimeoutMs, @@ -422,6 +423,7 @@ open class TestableNetworkCallback private constructor( // @param validated the expected value of the VALIDATED capability in the // onCapabilitiesChanged callback. // @param tmt how long to wait for the callbacks. + @JvmOverloads fun expectAvailableCallbacks( net: Network, suspended: Boolean = false, From 32be06f45f8c6dd2a7fe32fa53c209bc0a733c76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 10 Dec 2022 11:40:13 +0000 Subject: [PATCH 620/777] verify java map key/value struct size matches file descriptor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (this should avoid kernel reading/writing from out of bounds) Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I71fe71eee4e4e6a917477eef5fd2266439e803f3 --- .../com/android/net/module/util/BpfMap.java | 10 ++-- .../native/bpf_headers/include/bpf/BpfUtils.h | 26 ++-------- .../bpf_headers/include/bpf/KernelVersion.h | 49 +++++++++++++++++++ staticlibs/native/bpfmapjni/Android.bp | 2 +- .../com_android_net_module_util_BpfMap.cpp | 25 ++++++++-- 5 files changed, 81 insertions(+), 31 deletions(-) create mode 100644 staticlibs/native/bpf_headers/include/bpf/KernelVersion.h diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java index 2267f318df..9042085952 100644 --- a/staticlibs/device/com/android/net/module/util/BpfMap.java +++ b/staticlibs/device/com/android/net/module/util/BpfMap.java @@ -67,8 +67,10 @@ public class BpfMap implements IBpfMap private static ConcurrentHashMap, ParcelFileDescriptor> sFdCache = new ConcurrentHashMap<>(); - private static ParcelFileDescriptor cachedBpfFdGet(String path, int mode) + private static ParcelFileDescriptor cachedBpfFdGet(String path, int mode, + int keySize, int valueSize) throws ErrnoException, NullPointerException { + // TODO: key should include keySize & valueSize, but really we should match specific types Pair key = Pair.create(path, mode); // unlocked fetch is safe: map is concurrent read capable, and only inserted into ParcelFileDescriptor fd = sFdCache.get(key); @@ -79,7 +81,7 @@ public class BpfMap implements IBpfMap fd = sFdCache.get(key); if (fd != null) return fd; // okay, we really haven't opened this before... - fd = ParcelFileDescriptor.adoptFd(nativeBpfFdGet(path, mode)); + fd = ParcelFileDescriptor.adoptFd(nativeBpfFdGet(path, mode, keySize, valueSize)); sFdCache.put(key, fd); return fd; } @@ -94,11 +96,11 @@ public class BpfMap implements IBpfMap */ public BpfMap(@NonNull final String path, final int flag, final Class key, final Class value) throws ErrnoException, NullPointerException { - mMapFd = cachedBpfFdGet(path, flag); mKeyClass = key; mValueClass = value; mKeySize = Struct.getSize(key); mValueSize = Struct.getSize(value); + mMapFd = cachedBpfFdGet(path, flag, mKeySize, mValueSize); } /** @@ -295,7 +297,7 @@ public class BpfMap implements IBpfMap } } - private static native int nativeBpfFdGet(String path, int mode) + private static native int nativeBpfFdGet(String path, int mode, int keySize, int valueSize) throws ErrnoException, NullPointerException; // Note: the following methods appear to not require the object by virtue of taking the diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index 28d4b8bba5..e2cb67681c 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include #include @@ -25,9 +26,10 @@ #include #include -#include #include +#include "KernelVersion.h" + namespace android { namespace bpf { @@ -84,27 +86,5 @@ static inline int setrlimitForTest() { return res; } -#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c)) - -static inline unsigned uncachedKernelVersion() { - struct utsname buf; - if (uname(&buf)) return 0; - - unsigned kver_major = 0; - unsigned kver_minor = 0; - unsigned kver_sub = 0; - (void)sscanf(buf.release, "%u.%u.%u", &kver_major, &kver_minor, &kver_sub); - return KVER(kver_major, kver_minor, kver_sub); -} - -static inline unsigned kernelVersion() { - static unsigned kver = uncachedKernelVersion(); - return kver; -} - -static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) { - return kernelVersion() >= KVER(major, minor, sub); -} - } // namespace bpf } // namespace android diff --git a/staticlibs/native/bpf_headers/include/bpf/KernelVersion.h b/staticlibs/native/bpf_headers/include/bpf/KernelVersion.h new file mode 100644 index 0000000000..e0e53a932e --- /dev/null +++ b/staticlibs/native/bpf_headers/include/bpf/KernelVersion.h @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include + +namespace android { +namespace bpf { + +#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c)) + +static inline unsigned uncachedKernelVersion() { + struct utsname buf; + if (uname(&buf)) return 0; + + unsigned kver_major = 0; + unsigned kver_minor = 0; + unsigned kver_sub = 0; + (void)sscanf(buf.release, "%u.%u.%u", &kver_major, &kver_minor, &kver_sub); + return KVER(kver_major, kver_minor, kver_sub); +} + +static inline unsigned kernelVersion() { + static unsigned kver = uncachedKernelVersion(); + return kver; +} + +static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) { + return kernelVersion() >= KVER(major, minor, sub); +} + +} // namespace bpf +} // namespace android diff --git a/staticlibs/native/bpfmapjni/Android.bp b/staticlibs/native/bpfmapjni/Android.bp index cd254d4c73..8babcce3f7 100644 --- a/staticlibs/native/bpfmapjni/Android.bp +++ b/staticlibs/native/bpfmapjni/Android.bp @@ -23,7 +23,7 @@ cc_library_static { "com_android_net_module_util_TcUtils.cpp", ], header_libs: [ - "bpf_syscall_wrappers", + "bpf_headers", "jni_headers", ], shared_libs: [ diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp index 2e88fc83dc..2146d17c7f 100644 --- a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp +++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp @@ -25,15 +25,34 @@ #define BPF_FD_JUST_USE_INT #include "BpfSyscallWrappers.h" +#include "bpf/KernelVersion.h" + namespace android { static jint com_android_net_module_util_BpfMap_nativeBpfFdGet(JNIEnv *env, jclass clazz, - jstring path, jint mode) { + jstring path, jint mode, jint keySize, jint valueSize) { ScopedUtfChars pathname(env, path); jint fd = bpf::bpfFdGet(pathname.c_str(), static_cast(mode)); - if (fd < 0) jniThrowErrnoException(env, "nativeBpfFdGet", errno); + if (fd < 0) { + jniThrowErrnoException(env, "nativeBpfFdGet", errno); + return -1; + } + + if (bpf::isAtLeastKernelVersion(4, 14, 0)) { + // These likely fail with -1 and set errno to EINVAL on <4.14 + if (bpf::bpfGetFdKeySize(fd) != keySize) { + close(fd); + jniThrowErrnoException(env, "nativeBpfFdGet KeySize", EBADFD); + return -1; + } + if (bpf::bpfGetFdValueSize(fd) != valueSize) { + close(fd); + jniThrowErrnoException(env, "nativeBpfFdGet ValueSize", EBADFD); + return -1; + } + } return fd; } @@ -103,7 +122,7 @@ static jboolean com_android_net_module_util_BpfMap_nativeFindMapEntry(JNIEnv *en */ static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ - { "nativeBpfFdGet", "(Ljava/lang/String;I)I", + { "nativeBpfFdGet", "(Ljava/lang/String;III)I", (void*) com_android_net_module_util_BpfMap_nativeBpfFdGet }, { "nativeWriteToMapEntry", "(I[B[BI)V", (void*) com_android_net_module_util_BpfMap_nativeWriteToMapEntry }, From 89e363d9079fcb84ab9724234bac8d11f36355d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 21 Dec 2022 23:09:50 +0000 Subject: [PATCH 621/777] switch BpfBitmap key from U32 to S32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since this is an array from 32 bit int to 64 bit int, the S32/U32 distinction doesn't matter before we hit a bitmap with 2 billion entries, ie. 128 billion bits, taking up 16GiB of RAM... But S32 is a native java int, while U32 requires long. Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I5b06e80e801e007bafb18693647d968cba905c36 --- .../com/android/net/module/util/BpfBitmap.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/BpfBitmap.java b/staticlibs/device/com/android/net/module/util/BpfBitmap.java index 0c8bb37ee1..d2a5b65450 100644 --- a/staticlibs/device/com/android/net/module/util/BpfBitmap.java +++ b/staticlibs/device/com/android/net/module/util/BpfBitmap.java @@ -27,7 +27,7 @@ import androidx.annotation.NonNull; * */ public class BpfBitmap { - private BpfMap mBpfMap; + private BpfMap mBpfMap; /** * Create a BpfBitmap map wrapper with "path" of filesystem. @@ -35,8 +35,8 @@ public class BpfBitmap { * @param path The path of the BPF map. */ public BpfBitmap(@NonNull String path) throws ErrnoException { - mBpfMap = new BpfMap(path, BpfMap.BPF_F_RDWR, - Struct.U32.class, Struct.S64.class); + mBpfMap = new BpfMap(path, BpfMap.BPF_F_RDWR, + Struct.S32.class, Struct.S64.class); } /** @@ -44,7 +44,7 @@ public class BpfBitmap { * * @param key The key in the map corresponding to the value to return. */ - private long getBpfMapValue(Struct.U32 key) throws ErrnoException { + private long getBpfMapValue(Struct.S32 key) throws ErrnoException { Struct.S64 curVal = mBpfMap.getValue(key); if (curVal != null) { return curVal.val; @@ -61,7 +61,7 @@ public class BpfBitmap { public boolean get(int index) throws ErrnoException { if (index < 0) return false; - Struct.U32 key = new Struct.U32(index >> 6); + Struct.S32 key = new Struct.S32(index >> 6); return ((getBpfMapValue(key) >>> (index & 63)) & 1L) != 0; } @@ -92,7 +92,7 @@ public class BpfBitmap { public void set(int index, boolean set) throws ErrnoException { if (index < 0) throw new IllegalArgumentException("Index out of bounds."); - Struct.U32 key = new Struct.U32(index >> 6); + Struct.S32 key = new Struct.S32(index >> 6); long mask = (1L << (index & 63)); long val = getBpfMapValue(key); if (set) val |= mask; else val &= ~mask; @@ -114,7 +114,7 @@ public class BpfBitmap { * Checks if all bitmap values are 0. */ public boolean isEmpty() throws ErrnoException { - Struct.U32 key = mBpfMap.getFirstKey(); + Struct.S32 key = mBpfMap.getFirstKey(); while (key != null) { if (getBpfMapValue(key) != 0) { return false; From 9f7d45203f34a33d1e5268af9a828ebe11b5fe6e Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 20 Dec 2022 20:39:33 +0900 Subject: [PATCH 622/777] Introduce visibleOnHandlerThread This is a helper function that lets a caller make sure the side effects of a piece of code are visible both on a handler thread and in the caller thread before continuing. Also move HandlerUtilsTests to the tests directory of frameworks/libs/net from the NetworkStack where it used to be Test: NetworkStaticLibTests Change-Id: Icf1bd8bbe1216777c52b73cfbd0a46b647b72260 --- .../com/android/testutils/HandlerUtilsTest.kt | 76 +++++++++++++++++++ .../com/android/testutils/HandlerUtils.kt | 30 ++++++++ 2 files changed, 106 insertions(+) create mode 100644 staticlibs/tests/unit/src/com/android/testutils/HandlerUtilsTest.kt diff --git a/staticlibs/tests/unit/src/com/android/testutils/HandlerUtilsTest.kt b/staticlibs/tests/unit/src/com/android/testutils/HandlerUtilsTest.kt new file mode 100644 index 0000000000..46a3588f9b --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/testutils/HandlerUtilsTest.kt @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2019 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 com.android.testutils + +import android.os.Handler +import android.os.HandlerThread +import kotlin.test.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +private const val ATTEMPTS = 50 // Causes testWaitForIdle to take about 150ms on aosp_crosshatch-eng +private const val TIMEOUT_MS = 200 + +@RunWith(JUnit4::class) +class HandlerUtilsTest { + @Test + fun testWaitForIdle() { + val handlerThread = HandlerThread("testHandler").apply { start() } + + // Tests that waitForIdle can be called many times without ill impact if the service is + // already idle. + repeat(ATTEMPTS) { + handlerThread.waitForIdle(TIMEOUT_MS) + } + + // Tests that calling waitForIdle waits for messages to be processed. Use both an + // inline runnable that's instantiated at each loop run and a runnable that's instantiated + // once for all. + val tempRunnable = object : Runnable { + // Use StringBuilder preferentially to StringBuffer because StringBuilder is NOT + // thread-safe. It's part of the point that both runnables run on the same thread + // so if anything is wrong in that space it's better to opportunistically use a class + // where things might go wrong, even if there is no guarantee of failure. + var memory = StringBuilder() + override fun run() { + memory.append("b") + } + } + repeat(ATTEMPTS) { i -> + handlerThread.threadHandler.post { tempRunnable.memory.append("a"); } + handlerThread.threadHandler.post(tempRunnable) + handlerThread.waitForIdle(TIMEOUT_MS) + assertEquals(tempRunnable.memory.toString(), "ab".repeat(i + 1)) + } + } + + // Statistical test : even if visibleOnHandlerThread doesn't work this is likely to succeed, + // but it will be at least flaky. + @Test + fun testVisibleOnHandlerThread() { + val handlerThread = HandlerThread("testHandler").apply { start() } + val handler = Handler(handlerThread.looper) + + repeat(ATTEMPTS) { attempt -> + var x = -10 + visibleOnHandlerThread(handler) { x = attempt } + assertEquals(attempt, x) + handler.post { assertEquals(attempt, x) } + } + } +} diff --git a/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt b/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt index 861f45ee3c..68713490d2 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt @@ -21,9 +21,14 @@ package com.android.testutils import android.os.ConditionVariable import android.os.Handler import android.os.HandlerThread +import android.util.Log +import com.android.testutils.FunctionalUtils.ThrowingRunnable +import java.lang.Exception import java.util.concurrent.Executor import kotlin.test.fail +private const val TAG = "HandlerUtils" + /** * Block until the specified Handler or HandlerThread becomes idle, or until timeoutMs has passed. */ @@ -48,3 +53,28 @@ fun waitForIdleSerialExecutor(executor: Executor, timeoutMs: Long) { fail("Executor did not become idle after ${timeoutMs}ms") } } + +/** + * Executes a block of code, making its side effects visible on the caller and the handler thread + * + * After this function returns, the side effects of the passed block of code are guaranteed to be + * observed both on the thread running the handler and on the thread running this method. + * To achieve this, this method runs the passed block on the handler and blocks this thread + * until it's executed, so keep in mind this method will block, (including, if the handler isn't + * running, blocking forever). + */ +fun visibleOnHandlerThread(handler: Handler, r: ThrowingRunnable) { + val cv = ConditionVariable() + handler.post { + try { + r.run() + } catch (exception: Exception) { + Log.e(TAG, "visibleOnHandlerThread caught exception", exception) + } + cv.open() + } + // After block() returns, the handler thread has seen the change (since it ran it) + // and this thread also has seen the change (since cv.open() happens-before cv.block() + // returns). + cv.block() +} From 463f211a76596822daff0bbf80fa2ca9c59383b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 22 Dec 2022 12:06:15 +0000 Subject: [PATCH 623/777] convert BpfDumpTest from U32 to S32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit no need to use U32, of which uses I'd like to eliminate wherever possible Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I8c0a2df73c4153b21d33ee7a8f5d434f0fc80103 --- .../android/net/module/util/BpfDumpTest.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java index 4e483322d1..a66dacd9d2 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/BpfDumpTest.java @@ -57,8 +57,8 @@ public class BpfDumpTest { @Test public void testToBase64EncodedString() { - final Struct.U32 key = new Struct.U32(TEST_KEY); - final Struct.U32 value = new Struct.U32(TEST_VAL); + final Struct.S32 key = new Struct.S32(TEST_KEY); + final Struct.S32 value = new Struct.S32(TEST_VAL); // Verified in python: // import base64 @@ -71,15 +71,15 @@ public class BpfDumpTest { @Test public void testFromBase64EncodedString() { - Pair decodedKeyValue = BpfDump.fromBase64EncodedString( - Struct.U32.class, Struct.U32.class, TEST_KEY_VAL_BASE64); + Pair decodedKeyValue = BpfDump.fromBase64EncodedString( + Struct.S32.class, Struct.S32.class, TEST_KEY_VAL_BASE64); assertEquals(TEST_KEY, decodedKeyValue.first.val); assertEquals(TEST_VAL, decodedKeyValue.second.val); } private void assertThrowsIllegalArgumentException(final String testStr) { assertThrows(IllegalArgumentException.class, - () -> BpfDump.fromBase64EncodedString(Struct.U32.class, Struct.U32.class, testStr)); + () -> BpfDump.fromBase64EncodedString(Struct.S32.class, Struct.S32.class, testStr)); } @Test @@ -96,7 +96,7 @@ public class BpfDumpTest { TEST_KEY_VAL_BASE64 + BASE64_DELIMITER + TEST_KEY_BASE64); } - private String getDumpMap(final IBpfMap map) { + private String getDumpMap(final IBpfMap map) { final StringWriter sw = new StringWriter(); BpfDump.dumpMap(map, new PrintWriter(sw), "mapName", "header", (key, val) -> "key=" + key.val + ", val=" + val.val); @@ -105,9 +105,9 @@ public class BpfDumpTest { @Test public void testDumpMap() throws Exception { - final IBpfMap map = - new TestBpfMap<>(Struct.U32.class, Struct.U32.class); - map.updateEntry(new Struct.U32(123), new Struct.U32(456)); + final IBpfMap map = + new TestBpfMap<>(Struct.S32.class, Struct.S32.class); + map.updateEntry(new Struct.S32(123), new Struct.S32(456)); final String dump = getDumpMap(map); assertEquals(dump, "mapName:\n" @@ -117,10 +117,10 @@ public class BpfDumpTest { @Test public void testDumpMapMultipleEntries() throws Exception { - final IBpfMap map = - new TestBpfMap<>(Struct.U32.class, Struct.U32.class); - map.updateEntry(new Struct.U32(123), new Struct.U32(456)); - map.updateEntry(new Struct.U32(789), new Struct.U32(123)); + final IBpfMap map = + new TestBpfMap<>(Struct.S32.class, Struct.S32.class); + map.updateEntry(new Struct.S32(123), new Struct.S32(456)); + map.updateEntry(new Struct.S32(789), new Struct.S32(123)); final String dump = getDumpMap(map); assertTrue(dump.contains("mapName:")); @@ -129,7 +129,7 @@ public class BpfDumpTest { assertTrue(dump.contains("key=789, val=123")); } - private String getDumpMapStatus(final IBpfMap map) { + private String getDumpMapStatus(final IBpfMap map) { final StringWriter sw = new StringWriter(); BpfDump.dumpMapStatus(map, new PrintWriter(sw), "mapName", "mapPath"); return sw.toString(); @@ -137,8 +137,8 @@ public class BpfDumpTest { @Test public void testGetMapStatus() { - final IBpfMap map = - new TestBpfMap<>(Struct.U32.class, Struct.U32.class); + final IBpfMap map = + new TestBpfMap<>(Struct.S32.class, Struct.S32.class); assertEquals("mapName: OK\n", getDumpMapStatus(map)); } From da7a00d1476953884379c788704e91f259704947 Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Fri, 23 Dec 2022 17:26:13 +0800 Subject: [PATCH 624/777] Adds setNetworkAllowlist and freeze AIDL to v13 Add this interface so that CS can tell netd the network is allowed for the given UID ranges. Freeze AIDL to v13. Test: netd_integration_test Change-Id: I00c45a663dc917fc0ba4da5a99828edad1562d8c --- staticlibs/netd/Android.bp | 12 +- .../aidl_api/netd_aidl_interface/13/.hash | 1 + .../13/android/net/INetd.aidl | 226 ++++++++++++++++++ .../net/INetdUnsolicitedEventListener.aidl | 48 ++++ .../net/InterfaceConfigurationParcel.aidl | 42 ++++ .../android/net/IpSecMigrateInfoParcel.aidl | 45 ++++ .../13/android/net/MarkMaskParcel.aidl | 39 +++ .../13/android/net/NativeNetworkConfig.aidl | 44 ++++ .../13/android/net/NativeNetworkType.aidl | 40 ++++ .../13/android/net/NativeVpnType.aidl | 41 ++++ .../13/android/net/RouteInfoParcel.aidl | 40 ++++ .../13/android/net/TetherConfigParcel.aidl | 39 +++ .../android/net/TetherOffloadRuleParcel.aidl | 44 ++++ .../13/android/net/TetherStatsParcel.aidl | 43 ++++ .../13/android/net/UidRangeParcel.aidl | 40 ++++ .../net/netd/aidl/NativeUidRangeConfig.aidl | 41 ++++ .../current/android/net/INetd.aidl | 5 +- staticlibs/netd/binder/android/net/INetd.aidl | 15 ++ 18 files changed, 799 insertions(+), 6 deletions(-) create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/13/.hash create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/INetd.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/INetdUnsolicitedEventListener.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/InterfaceConfigurationParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/IpSecMigrateInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/MarkMaskParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/NativeNetworkConfig.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/NativeNetworkType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/NativeVpnType.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/RouteInfoParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/TetherConfigParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/TetherOffloadRuleParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/TetherStatsParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/UidRangeParcel.aidl create mode 100644 staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/netd/aidl/NativeUidRangeConfig.aidl diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index 057ea2aae8..525160dd60 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -21,7 +21,7 @@ java_library { sdk_version: "system_current", min_sdk_version: "29", static_libs: [ - "netd_aidl_interface-V12-java", + "netd_aidl_interface-V13-java", ], apex_available: [ "//apex_available:platform", // used from services.net @@ -44,7 +44,7 @@ cc_library_static { cc_library_static { name: "netd_aidl_interface-lateststable-ndk", whole_static_libs: [ - "netd_aidl_interface-V12-ndk", + "netd_aidl_interface-V13-ndk", ], apex_available: [ "com.android.resolv", @@ -55,12 +55,12 @@ cc_library_static { cc_defaults { name: "netd_aidl_interface_lateststable_cpp_static", - static_libs: ["netd_aidl_interface-V12-cpp"], + static_libs: ["netd_aidl_interface-V13-cpp"], } cc_defaults { name: "netd_aidl_interface_lateststable_cpp_shared", - shared_libs: ["netd_aidl_interface-V12-cpp"], + shared_libs: ["netd_aidl_interface-V13-cpp"], } aidl_interface { @@ -158,6 +158,10 @@ aidl_interface { version: "12", imports: [], }, + { + version: "13", + imports: [], + }, ], diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/13/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/13/.hash new file mode 100644 index 0000000000..d3c72cfb1e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/13/.hash @@ -0,0 +1 @@ +38614f80a23b92603d4851177e57c460aec1b606 diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/INetd.aidl new file mode 100644 index 0000000000..3507784723 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/INetd.aidl @@ -0,0 +1,226 @@ +/** + * Copyright (c) 2016, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetd { + boolean isAlive(); + boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids); + boolean bandwidthEnableDataSaver(boolean enable); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreatePhysical(int netId, int permission); + /** + * @deprecated use networkCreate() instead. + */ + void networkCreateVpn(int netId, boolean secure); + void networkDestroy(int netId); + void networkAddInterface(int netId, in @utf8InCpp String iface); + void networkRemoveInterface(int netId, in @utf8InCpp String iface); + void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges); + void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges); + void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids); + boolean tetherApplyDnsInterfaces(); + android.net.TetherStatsParcel[] tetherGetStats(); + void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength); + @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter); + void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value); + void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid); + int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId); + void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi); + void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket); + void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId); + void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId); + void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId); + void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName); + void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask); + void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode); + void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel); + void strictUidCleartextPenalty(int uid, int policyPenalty); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ + @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator. + */ + void clatdStop(in @utf8InCpp String ifName); + boolean ipfwdEnabled(); + @utf8InCpp String[] ipfwdGetRequesterList(); + void ipfwdEnableForwarding(in @utf8InCpp String requester); + void ipfwdDisableForwarding(in @utf8InCpp String requester); + void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface); + void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName); + void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes); + void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName); + void bandwidthSetGlobalAlert(long bytes); + void bandwidthAddNaughtyApp(int uid); + void bandwidthRemoveNaughtyApp(int uid); + void bandwidthAddNiceApp(int uid); + void bandwidthRemoveNiceApp(int uid); + void tetherStart(in @utf8InCpp String[] dhcpRanges); + void tetherStop(); + boolean tetherIsEnabled(); + void tetherInterfaceAdd(in @utf8InCpp String ifName); + void tetherInterfaceRemove(in @utf8InCpp String ifName); + @utf8InCpp String[] tetherInterfaceList(); + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + @utf8InCpp String[] tetherDnsList(); + void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop); + void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid); + int networkGetDefault(); + void networkSetDefault(int netId); + void networkClearDefault(); + void networkSetPermissionForNetwork(int netId, int permission); + void networkSetPermissionForUser(int permission, in int[] uids); + void networkClearPermissionForUser(in int[] uids); + void trafficSetNetPermForUids(int permission, in int[] uids); + void networkSetProtectAllow(int uid); + void networkSetProtectDeny(int uid); + boolean networkCanProtect(int uid); + void firewallSetFirewallType(int firewalltype); + void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule); + void firewallSetUidRule(int childChain, int uid, int firewallRule); + void firewallEnableChildChain(int childChain, boolean enable); + @utf8InCpp String[] interfaceGetList(); + android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName); + void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg); + void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable); + void interfaceClearAddrs(in @utf8InCpp String ifName); + void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable); + void interfaceSetMtu(in @utf8InCpp String ifName, int mtu); + void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface); + void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues); + void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener); + void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids); + void firewallRemoveUidInterfaceRules(in int[] uids); + void trafficSwapActiveStatsMap(); + IBinder getOemNetd(); + void tetherStartWithConfiguration(in android.net.TetherConfigParcel config); + android.net.MarkMaskParcel getFwmarkForNetwork(int netId); + void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + android.net.TetherStatsParcel[] tetherOffloadGetStats(); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes); + /** + * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator. + */ + android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex); + void networkCreate(in android.net.NativeNetworkConfig config); + void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); + void ipSecMigrate(in android.net.IpSecMigrateInfoParcel migrateInfo); + void setNetworkAllowlist(in android.net.netd.aidl.NativeUidRangeConfig[] allowedNetworks); + const int IPV4 = 4; + const int IPV6 = 6; + const int CONF = 1; + const int NEIGH = 2; + const String IPSEC_INTERFACE_PREFIX = "ipsec"; + const int IPV6_ADDR_GEN_MODE_EUI64 = 0; + const int IPV6_ADDR_GEN_MODE_NONE = 1; + const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2; + const int IPV6_ADDR_GEN_MODE_RANDOM = 3; + const int IPV6_ADDR_GEN_MODE_DEFAULT = 0; + const int PENALTY_POLICY_ACCEPT = 1; + const int PENALTY_POLICY_LOG = 2; + const int PENALTY_POLICY_REJECT = 3; + const int CLAT_MARK = 0xdeadc1a7; + const int LOCAL_NET_ID = 99; + const int DUMMY_NET_ID = 51; + const int UNREACHABLE_NET_ID = 52; + const String NEXTHOP_NONE = ""; + const String NEXTHOP_UNREACHABLE = "unreachable"; + const String NEXTHOP_THROW = "throw"; + const int PERMISSION_NONE = 0; + const int PERMISSION_NETWORK = 1; + const int PERMISSION_SYSTEM = 2; + const int NO_PERMISSIONS = 0; + const int PERMISSION_INTERNET = 4; + const int PERMISSION_UPDATE_DEVICE_STATS = 8; + const int PERMISSION_UNINSTALLED = (-1); + /** + * @deprecated use FIREWALL_ALLOWLIST. + */ + const int FIREWALL_WHITELIST = 0; + const int FIREWALL_ALLOWLIST = 0; + /** + * @deprecated use FIREWALL_DENYLIST. + */ + const int FIREWALL_BLACKLIST = 1; + const int FIREWALL_DENYLIST = 1; + const int FIREWALL_RULE_ALLOW = 1; + const int FIREWALL_RULE_DENY = 2; + const int FIREWALL_CHAIN_NONE = 0; + const int FIREWALL_CHAIN_DOZABLE = 1; + const int FIREWALL_CHAIN_STANDBY = 2; + const int FIREWALL_CHAIN_POWERSAVE = 3; + const int FIREWALL_CHAIN_RESTRICTED = 4; + const String IF_STATE_UP = "up"; + const String IF_STATE_DOWN = "down"; + const String IF_FLAG_BROADCAST = "broadcast"; + const String IF_FLAG_LOOPBACK = "loopback"; + const String IF_FLAG_POINTOPOINT = "point-to-point"; + const String IF_FLAG_RUNNING = "running"; + const String IF_FLAG_MULTICAST = "multicast"; + const int IPSEC_DIRECTION_IN = 0; + const int IPSEC_DIRECTION_OUT = 1; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/INetdUnsolicitedEventListener.aidl new file mode 100644 index 0000000000..31775dfd11 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/INetdUnsolicitedEventListener.aidl @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2018, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetdUnsolicitedEventListener { + oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid); + oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName); + oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers); + oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope); + oneway void onInterfaceAdded(@utf8InCpp String ifName); + oneway void onInterfaceRemoved(@utf8InCpp String ifName); + oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up); + oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up); + oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName); + oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex); +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/InterfaceConfigurationParcel.aidl new file mode 100644 index 0000000000..1869d8d49e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/InterfaceConfigurationParcel.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable InterfaceConfigurationParcel { + @utf8InCpp String ifName; + @utf8InCpp String hwAddr; + @utf8InCpp String ipv4Addr; + int prefixLength; + @utf8InCpp String[] flags; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/IpSecMigrateInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/IpSecMigrateInfoParcel.aidl new file mode 100644 index 0000000000..975a26199d --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/IpSecMigrateInfoParcel.aidl @@ -0,0 +1,45 @@ +/** + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@JavaOnlyImmutable +parcelable IpSecMigrateInfoParcel { + int requestId; + int selAddrFamily; + int direction; + @utf8InCpp String oldSourceAddress; + @utf8InCpp String oldDestinationAddress; + @utf8InCpp String newSourceAddress; + @utf8InCpp String newDestinationAddress; + int interfaceId; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/MarkMaskParcel.aidl new file mode 100644 index 0000000000..8ea20d118f --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/MarkMaskParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable MarkMaskParcel { + int mark; + int mask; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/NativeNetworkConfig.aidl new file mode 100644 index 0000000000..77d814b825 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/NativeNetworkConfig.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeNetworkConfig { + int netId; + android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL; + int permission; + boolean secure; + android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM; + boolean excludeLocalRoutes = false; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/NativeNetworkType.aidl new file mode 100644 index 0000000000..e77a1432e8 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/NativeNetworkType.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeNetworkType { + PHYSICAL = 0, + VIRTUAL = 1, + PHYSICAL_LOCAL = 2, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/NativeVpnType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/NativeVpnType.aidl new file mode 100644 index 0000000000..8a8be83958 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/NativeVpnType.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@Backing(type="int") +enum NativeVpnType { + SERVICE = 1, + PLATFORM = 2, + LEGACY = 3, + OEM = 4, +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/RouteInfoParcel.aidl new file mode 100644 index 0000000000..5ef95e67ca --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/RouteInfoParcel.aidl @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2020, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +parcelable RouteInfoParcel { + @utf8InCpp String destination; + @utf8InCpp String ifName; + @utf8InCpp String nextHop; + int mtu; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/TetherConfigParcel.aidl new file mode 100644 index 0000000000..7b39c22e4e --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/TetherConfigParcel.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherConfigParcel { + boolean usingLegacyDnsProxy; + @utf8InCpp String[] dhcpRanges; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/TetherOffloadRuleParcel.aidl new file mode 100644 index 0000000000..983e9860ea --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/TetherOffloadRuleParcel.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherOffloadRuleParcel { + int inputInterfaceIndex; + int outputInterfaceIndex; + byte[] destination; + int prefixLength; + byte[] srcL2Address; + byte[] dstL2Address; + int pmtu = 1500; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/TetherStatsParcel.aidl new file mode 100644 index 0000000000..5f1b722690 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/TetherStatsParcel.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +parcelable TetherStatsParcel { + @utf8InCpp String iface; + long rxBytes; + long rxPackets; + long txBytes; + long txPackets; + int ifIndex = 0; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/UidRangeParcel.aidl new file mode 100644 index 0000000000..72e987a2af --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/UidRangeParcel.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable UidRangeParcel { + int start; + int stop; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/netd/aidl/NativeUidRangeConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/netd/aidl/NativeUidRangeConfig.aidl new file mode 100644 index 0000000000..9bb679f1c1 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/13/android/net/netd/aidl/NativeUidRangeConfig.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.netd.aidl; +/* @hide */ +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable NativeUidRangeConfig { + int netId; + android.net.UidRangeParcel[] uidRanges; + int subPriority; +} diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl index 763b92ac60..3507784723 100644 --- a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl +++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl @@ -169,6 +169,7 @@ interface INetd { void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig); void ipSecMigrate(in android.net.IpSecMigrateInfoParcel migrateInfo); + void setNetworkAllowlist(in android.net.netd.aidl.NativeUidRangeConfig[] allowedNetworks); const int IPV4 = 4; const int IPV6 = 6; const int CONF = 1; @@ -182,7 +183,7 @@ interface INetd { const int PENALTY_POLICY_ACCEPT = 1; const int PENALTY_POLICY_LOG = 2; const int PENALTY_POLICY_REJECT = 3; - const int CLAT_MARK = -559038041; + const int CLAT_MARK = 0xdeadc1a7; const int LOCAL_NET_ID = 99; const int DUMMY_NET_ID = 51; const int UNREACHABLE_NET_ID = 52; @@ -195,7 +196,7 @@ interface INetd { const int NO_PERMISSIONS = 0; const int PERMISSION_INTERNET = 4; const int PERMISSION_UPDATE_DEVICE_STATS = 8; - const int PERMISSION_UNINSTALLED = -1; + const int PERMISSION_UNINSTALLED = (-1); /** * @deprecated use FIREWALL_ALLOWLIST. */ diff --git a/staticlibs/netd/binder/android/net/INetd.aidl b/staticlibs/netd/binder/android/net/INetd.aidl index dff07c6e3e..27d9a035ff 100644 --- a/staticlibs/netd/binder/android/net/INetd.aidl +++ b/staticlibs/netd/binder/android/net/INetd.aidl @@ -1420,4 +1420,19 @@ interface INetd { * IPSEC_DIRECTION_OUT is used for IPsec SAs or policies that direct traffic away from the host. */ const int IPSEC_DIRECTION_OUT = 1; + + /** + * Set the list of allowed UIDs for all networks with restrictions. + * + * This list is the entire list of restrictions for all networks known by + * netd. Calling this function always defines the entire list of restrictions, + * and networks not in the passed list are always reset to having no + * restrictions. + * + * @param NativeUidRangeConfig[] An array of allowlists, one per network. For each allowlist: + * - netId: the netId on which to set the allowlist + * - uidRanges: the UIDs allowed to use this network + * - subPriority: unused + */ + void setNetworkAllowlist(in NativeUidRangeConfig[] allowedNetworks); } From d7d3b03e13ee3f8d0e3d4d101eb3a6b73e0acc1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 22 Dec 2022 17:03:18 +0000 Subject: [PATCH 625/777] dedup kernelversion.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ie7a4dd46122e86bf808d0a3ac566075e1c3a2cd4 --- .../bpf_headers/include/bpf/KernelVersion.h | 3 +- staticlibs/native/tcutils/Android.bp | 4 +- staticlibs/native/tcutils/kernelversion.h | 56 ------------------- staticlibs/native/tcutils/tcutils.cpp | 4 +- .../native/tcutils/tests/tcutils_test.cpp | 6 +- 5 files changed, 8 insertions(+), 65 deletions(-) delete mode 100644 staticlibs/native/tcutils/kernelversion.h diff --git a/staticlibs/native/bpf_headers/include/bpf/KernelVersion.h b/staticlibs/native/bpf_headers/include/bpf/KernelVersion.h index e0e53a932e..29a36e6377 100644 --- a/staticlibs/native/bpf_headers/include/bpf/KernelVersion.h +++ b/staticlibs/native/bpf_headers/include/bpf/KernelVersion.h @@ -16,8 +16,7 @@ #pragma once -#include -#include +#include #include namespace android { diff --git a/staticlibs/native/tcutils/Android.bp b/staticlibs/native/tcutils/Android.bp index 88a26832b4..84a32eddf4 100644 --- a/staticlibs/native/tcutils/Android.bp +++ b/staticlibs/native/tcutils/Android.bp @@ -20,7 +20,7 @@ cc_library_static { name: "libtcutils", srcs: ["tcutils.cpp"], export_include_dirs: ["include"], - header_libs: ["bpf_syscall_wrappers"], + header_libs: ["bpf_headers"], shared_libs: [ "liblog", ], @@ -53,7 +53,7 @@ cc_test { "-Werror", "-Wno-error=unused-variable", ], - header_libs: ["bpf_syscall_wrappers"], + header_libs: ["bpf_headers"], static_libs: [ "libgmock", "libtcutils", diff --git a/staticlibs/native/tcutils/kernelversion.h b/staticlibs/native/tcutils/kernelversion.h deleted file mode 100644 index 9aab31d4a1..0000000000 --- a/staticlibs/native/tcutils/kernelversion.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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. - */ - -// ----------------------------------------------------------------------------- -// TODO - This should be replaced with BpfUtils in bpf_headers. -// Currently, bpf_headers contains a bunch requirements it doesn't actually provide, such as a -// non-ndk liblog version, and some version of libbase. libtcutils does not have access to either of -// these, so I think this will have to wait until we figure out a way around this. -// -// In the mean time copying verbatim from: -// frameworks/libs/net/common/native/bpf_headers - -#pragma once - -#include -#include - -#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c)) - -namespace android { - -static inline unsigned uncachedKernelVersion() { - struct utsname buf; - if (uname(&buf)) return 0; - - unsigned kver_major = 0; - unsigned kver_minor = 0; - unsigned kver_sub = 0; - (void)sscanf(buf.release, "%u.%u.%u", &kver_major, &kver_minor, &kver_sub); - return KVER(kver_major, kver_minor, kver_sub); -} - -static unsigned kernelVersion() { - static unsigned kver = uncachedKernelVersion(); - return kver; -} - -static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, - unsigned sub) { - return kernelVersion() >= KVER(major, minor, sub); -} - -} // namespace android diff --git a/staticlibs/native/tcutils/tcutils.cpp b/staticlibs/native/tcutils/tcutils.cpp index 4101885f6d..37a7ec85b4 100644 --- a/staticlibs/native/tcutils/tcutils.cpp +++ b/staticlibs/native/tcutils/tcutils.cpp @@ -19,7 +19,7 @@ #include "tcutils/tcutils.h" #include "logging.h" -#include "kernelversion.h" +#include "bpf/KernelVersion.h" #include "scopeguard.h" #include @@ -504,7 +504,7 @@ int isEthernet(const char *iface, bool &isEthernet) { // shipped with Android S, so (for safety) let's limit ourselves to // >5.10, ie. 5.11+ as a guarantee we're on Android T+ and thus no // longer need this non-upstream compatibility logic - static bool is_pre_5_11_kernel = !isAtLeastKernelVersion(5, 11, 0); + static bool is_pre_5_11_kernel = !bpf::isAtLeastKernelVersion(5, 11, 0); if (is_pre_5_11_kernel) return false; } diff --git a/staticlibs/native/tcutils/tests/tcutils_test.cpp b/staticlibs/native/tcutils/tests/tcutils_test.cpp index 3a89696c63..53835d7d88 100644 --- a/staticlibs/native/tcutils/tests/tcutils_test.cpp +++ b/staticlibs/native/tcutils/tests/tcutils_test.cpp @@ -18,7 +18,7 @@ #include -#include "kernelversion.h" +#include "bpf/KernelVersion.h" #include #include @@ -82,7 +82,7 @@ TEST(LibTcUtilsTest, AddAndDeleteBpfFilter) { // TODO: this should likely be in the tethering module, where using netd.h would be ok static constexpr char bpfProgPath[] = "/sys/fs/bpf/tethering/prog_offload_schedcls_tether_downstream6_ether"; - const int errNOENT = isAtLeastKernelVersion(4, 19, 0) ? ENOENT : EINVAL; + const int errNOENT = bpf::isAtLeastKernelVersion(4, 19, 0) ? ENOENT : EINVAL; // static test values static constexpr bool ingress = true; @@ -118,7 +118,7 @@ TEST(LibTcUtilsTest, AddAndDeleteIngressPoliceFilter) { ASSERT_LE(3, fd); close(fd); - const int errNOENT = isAtLeastKernelVersion(4, 19, 0) ? ENOENT : EINVAL; + const int errNOENT = bpf::isAtLeastKernelVersion(4, 19, 0) ? ENOENT : EINVAL; // static test values static constexpr unsigned rateInBytesPerSec = From ff998720b64f219e97ce95d8575713c871ff0853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 27 Dec 2022 12:06:12 +0000 Subject: [PATCH 626/777] Use the .o-wide bpfloader min/max ver for maps & programs too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is basically a no-op, but will make future compatibility checks easier. The programs/maps already won't load on a bpfloader outside of this range, as the entire .o will be skipped. Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I0669c7ff9e04e24a8da68aa821c9ad705a8f5a93 --- staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 4d48720046..5b17a8ef92 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -167,8 +167,8 @@ static void (*bpf_ringbuf_submit_unsafe)(const void* data, __u64 flags) = (void* .uid = (usr), \ .gid = (grp), \ .mode = (md), \ - .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER, \ - .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER, \ + .bpfloader_min_ver = BPFLOADER_MIN_VER, \ + .bpfloader_max_ver = BPFLOADER_MAX_VER, \ .min_kver = (minkver), \ .max_kver = (maxkver), \ .selinux_context = (selinux), \ @@ -296,8 +296,8 @@ static long (*bpf_get_current_comm)(void* buf, uint32_t buf_size) = (void*) BPF_ .min_kver = (min_kv), \ .max_kver = (max_kv), \ .optional = (opt), \ - .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER, \ - .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER, \ + .bpfloader_min_ver = BPFLOADER_MIN_VER, \ + .bpfloader_max_ver = BPFLOADER_MAX_VER, \ .selinux_context = selinux, \ .pin_subdir = pindir, \ }; \ From 3114700eba3acc7fb889cea3a5b67eedf42f392a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 27 Dec 2022 12:25:40 +0000 Subject: [PATCH 627/777] bpf_helpers.h: add load_byte/half/word() llvm/clang asm magic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit see kernel's samples/bpf/bpf_helpers.h or tools/testing/selftests/bpf/bpf_legacy.h Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Id331fb9abcd87df8bf87c5a86749acf0144ffbde --- staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 4d48720046..8c66b916e6 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -277,6 +277,11 @@ static void (*bpf_ringbuf_submit_unsafe)(const void* data, __u64 flags) = (void* DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \ DEFAULT_BPF_MAP_UID, gid, 0660) +// LLVM eBPF builtins: they directly generate BPF_LD_ABS/BPF_LD_IND (skb may be ignored?) +unsigned long long load_byte(void* skb, unsigned long long off) asm("llvm.bpf.load.byte"); +unsigned long long load_half(void* skb, unsigned long long off) asm("llvm.bpf.load.half"); +unsigned long long load_word(void* skb, unsigned long long off) asm("llvm.bpf.load.word"); + static int (*bpf_probe_read)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read; static int (*bpf_probe_read_str)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read_str; static unsigned long long (*bpf_ktime_get_ns)(void) = (void*) BPF_FUNC_ktime_get_ns; From a25f1091c5f386c1c9210a38d83b3adb07e3167e Mon Sep 17 00:00:00 2001 From: Igor Chernyshev Date: Tue, 20 Dec 2022 00:07:38 -0800 Subject: [PATCH 628/777] Add wear tethering util classes Bug: 245971639 Change-Id: I97655ece334ca93743896e89e12f8501f4e24776 --- staticlibs/Android.bp | 24 ++ .../net/module/util/async/Assertions.java | 41 +++ .../module/util/async/CircularByteBuffer.java | 210 ++++++++++++++ .../module/util/async/ReadableByteBuffer.java | 60 ++++ staticlibs/tests/unit/Android.bp | 11 +- .../util/async/CircularByteBufferTest.java | 267 ++++++++++++++++++ 6 files changed, 608 insertions(+), 5 deletions(-) create mode 100644 staticlibs/device/com/android/net/module/util/async/Assertions.java create mode 100644 staticlibs/device/com/android/net/module/util/async/CircularByteBuffer.java create mode 100644 staticlibs/device/com/android/net/module/util/async/ReadableByteBuffer.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/async/CircularByteBufferTest.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index d8a397d0a4..1fe6c2cc2b 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -304,6 +304,30 @@ java_library { lint: { strict_updatability_linting: true }, } +java_library { + name: "net-utils-device-common-async", + srcs: [ + "device/com/android/net/module/util/async/*.java", + ], + sdk_version: "module_current", + min_sdk_version: "29", + visibility: [ + "//frameworks/libs/net/common/tests:__subpackages__", + "//frameworks/libs/net/common/testutils:__subpackages__", + "//packages/modules/Connectivity:__subpackages__", + ], + libs: [ + "framework-annotations-lib", + ], + static_libs: [ + ], + apex_available: [ + "com.android.tethering", + "//apex_available:platform", + ], + lint: { strict_updatability_linting: true }, +} + // Use a filegroup and not a library for telephony sources, as framework-annotations cannot be // included either (some annotations would be duplicated on the bootclasspath). filegroup { diff --git a/staticlibs/device/com/android/net/module/util/async/Assertions.java b/staticlibs/device/com/android/net/module/util/async/Assertions.java new file mode 100644 index 0000000000..ce701d0591 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/async/Assertions.java @@ -0,0 +1,41 @@ +/* + * 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 com.android.net.module.util.async; + +import android.os.Build; + +/** + * Implements basic assert functions for runtime error-checking. + * + * @hide + */ +public final class Assertions { + public static final boolean IS_USER_BUILD = "user".equals(Build.TYPE); + + public static void throwsIfOutOfBounds(int totalLength, int pos, int len) { + if (!IS_USER_BUILD && ((totalLength | pos | len) < 0 || pos > totalLength - len)) { + throw new ArrayIndexOutOfBoundsException( + "length=" + totalLength + "; regionStart=" + pos + "; regionLength=" + len); + } + } + + public static void throwsIfOutOfBounds(byte[] buffer, int pos, int len) { + throwsIfOutOfBounds(buffer != null ? buffer.length : 0, pos, len); + } + + private Assertions() {} +} diff --git a/staticlibs/device/com/android/net/module/util/async/CircularByteBuffer.java b/staticlibs/device/com/android/net/module/util/async/CircularByteBuffer.java new file mode 100644 index 0000000000..92daa08f5f --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/async/CircularByteBuffer.java @@ -0,0 +1,210 @@ +/* + * 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 com.android.net.module.util.async; + +import java.util.Arrays; + +/** + * Implements a circular read-write byte buffer. + * + * @hide + */ +public final class CircularByteBuffer implements ReadableByteBuffer { + private final byte[] mBuffer; + private final int mCapacity; + private int mReadPos; + private int mWritePos; + private int mSize; + + public CircularByteBuffer(int capacity) { + mCapacity = capacity; + mBuffer = new byte[mCapacity]; + } + + @Override + public void clear() { + mReadPos = 0; + mWritePos = 0; + mSize = 0; + Arrays.fill(mBuffer, (byte) 0); + } + + @Override + public int capacity() { + return mCapacity; + } + + @Override + public int size() { + return mSize; + } + + /** Returns the amount of remaining writeable space in this buffer. */ + public int freeSize() { + return mCapacity - mSize; + } + + @Override + public byte peek(int offset) { + if (offset < 0 || offset >= size()) { + throw new IllegalArgumentException("Invalid offset=" + offset + ", size=" + size()); + } + + return mBuffer[(mReadPos + offset) % mCapacity]; + } + + @Override + public void readBytes(byte[] dst, int dstPos, int dstLen) { + if (dst != null) { + Assertions.throwsIfOutOfBounds(dst, dstPos, dstLen); + } + if (dstLen > size()) { + throw new IllegalArgumentException("Invalid len=" + dstLen + ", size=" + size()); + } + + while (dstLen > 0) { + final int copyLen = getCopyLen(mReadPos, mWritePos, dstLen); + if (dst != null) { + System.arraycopy(mBuffer, mReadPos, dst, dstPos, copyLen); + } + dstPos += copyLen; + dstLen -= copyLen; + mSize -= copyLen; + mReadPos = (mReadPos + copyLen) % mCapacity; + } + + if (mSize == 0) { + // Reset to the beginning for better contiguous access. + mReadPos = 0; + mWritePos = 0; + } + } + + @Override + public void peekBytes(int offset, byte[] dst, int dstPos, int dstLen) { + Assertions.throwsIfOutOfBounds(dst, dstPos, dstLen); + if (offset + dstLen > size()) { + throw new IllegalArgumentException("Invalid len=" + dstLen + + ", offset=" + offset + ", size=" + size()); + } + + int tmpReadPos = (mReadPos + offset) % mCapacity; + while (dstLen > 0) { + final int copyLen = getCopyLen(tmpReadPos, mWritePos, dstLen); + System.arraycopy(mBuffer, tmpReadPos, dst, dstPos, copyLen); + dstPos += copyLen; + dstLen -= copyLen; + tmpReadPos = (tmpReadPos + copyLen) % mCapacity; + } + } + + @Override + public int getDirectReadSize() { + if (size() == 0) { + return 0; + } + return (mReadPos < mWritePos ? (mWritePos - mReadPos) : (mCapacity - mReadPos)); + } + + @Override + public int getDirectReadPos() { + return mReadPos; + } + + @Override + public byte[] getDirectReadBuffer() { + return mBuffer; + } + + @Override + public void accountForDirectRead(int len) { + if (len < 0 || len > size()) { + throw new IllegalArgumentException("Invalid len=" + len + ", size=" + size()); + } + + mSize -= len; + mReadPos = (mReadPos + len) % mCapacity; + } + + /** Copies given data to the end of the buffer. */ + public void writeBytes(byte[] buffer, int pos, int len) { + Assertions.throwsIfOutOfBounds(buffer, pos, len); + if (len > freeSize()) { + throw new IllegalArgumentException("Invalid len=" + len + ", size=" + freeSize()); + } + + while (len > 0) { + final int copyLen = getCopyLen(mWritePos, mReadPos,len); + System.arraycopy(buffer, pos, mBuffer, mWritePos, copyLen); + pos += copyLen; + len -= copyLen; + mSize += copyLen; + mWritePos = (mWritePos + copyLen) % mCapacity; + } + } + + private int getCopyLen(int startPos, int endPos, int len) { + if (startPos < endPos) { + return Math.min(len, endPos - startPos); + } else { + return Math.min(len, mCapacity - startPos); + } + } + + /** Returns the amount of contiguous writeable space. */ + public int getDirectWriteSize() { + if (freeSize() == 0) { + return 0; // Return zero in case buffer is full. + } + return (mWritePos < mReadPos ? (mReadPos - mWritePos) : (mCapacity - mWritePos)); + } + + /** Returns the position of contiguous writeable space. */ + public int getDirectWritePos() { + return mWritePos; + } + + /** Returns the buffer reference for direct write operation. */ + public byte[] getDirectWriteBuffer() { + return mBuffer; + } + + /** Must be called after performing a direct write using getDirectWriteBuffer(). */ + public void accountForDirectWrite(int len) { + if (len < 0 || len > freeSize()) { + throw new IllegalArgumentException("Invalid len=" + len + ", size=" + freeSize()); + } + + mSize += len; + mWritePos = (mWritePos + len) % mCapacity; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("CircularByteBuffer{c="); + sb.append(mCapacity); + sb.append(",s="); + sb.append(mSize); + sb.append(",r="); + sb.append(mReadPos); + sb.append(",w="); + sb.append(mWritePos); + sb.append('}'); + return sb.toString(); + } +} diff --git a/staticlibs/device/com/android/net/module/util/async/ReadableByteBuffer.java b/staticlibs/device/com/android/net/module/util/async/ReadableByteBuffer.java new file mode 100644 index 0000000000..7f824049a2 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/async/ReadableByteBuffer.java @@ -0,0 +1,60 @@ +/* + * 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 com.android.net.module.util.async; + +/** + * Allows reading from a buffer of bytes. The data can be read and thus removed, + * or peeked at without disturbing the buffer state. + * + * @hide + */ +public interface ReadableByteBuffer { + /** Returns the size of the buffered data. */ + int size(); + + /** + * Returns the maximum amount of the buffered data. + * + * The caller may use this method in combination with peekBytes() + * to estimate when the buffer needs to be emptied using readData(). + */ + int capacity(); + + /** Clears all buffered data. */ + void clear(); + + /** Returns a single byte at the given offset. */ + byte peek(int offset); + + /** Copies an array of bytes from the given offset to "dst". */ + void peekBytes(int offset, byte[] dst, int dstPos, int dstLen); + + /** Reads and removes an array of bytes from the head of the buffer. */ + void readBytes(byte[] dst, int dstPos, int dstLen); + + /** Returns the amount of contiguous readable data. */ + int getDirectReadSize(); + + /** Returns the position of contiguous readable data. */ + int getDirectReadPos(); + + /** Returns the buffer reference for direct read operation. */ + byte[] getDirectReadBuffer(); + + /** Must be called after performing a direct read using getDirectReadBuffer(). */ + void accountForDirectRead(int len); +} diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index 21e8c641a3..6e223bd4e0 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -12,14 +12,15 @@ android_library { min_sdk_version: "29", defaults: ["framework-connectivity-test-defaults"], static_libs: [ - "net-utils-framework-common", - "net-utils-device-common-ip", "androidx.test.rules", "mockito-target-extended-minus-junit4", - "net-utils-device-common", - "net-utils-device-common-bpf", - "net-tests-utils", "netd-client", + "net-tests-utils", + "net-utils-framework-common", + "net-utils-device-common", + "net-utils-device-common-async", + "net-utils-device-common-bpf", + "net-utils-device-common-ip", ], libs: [ "android.test.runner", diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/async/CircularByteBufferTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/async/CircularByteBufferTest.java new file mode 100644 index 0000000000..01abee2b4a --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/async/CircularByteBufferTest.java @@ -0,0 +1,267 @@ +/* + * 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 com.android.net.module.util.async; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.fail; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class CircularByteBufferTest { + @Test + public void writeBytes() { + final int capacity = 23; + CircularByteBuffer buffer = new CircularByteBuffer(capacity); + assertEquals(0, buffer.size()); + assertEquals(0, buffer.getDirectReadSize()); + assertEquals(capacity, buffer.freeSize()); + assertEquals(capacity, buffer.getDirectWriteSize()); + + final byte[] writeBuffer = new byte[15]; + buffer.writeBytes(writeBuffer, 0, writeBuffer.length); + + assertEquals(writeBuffer.length, buffer.size()); + assertEquals(writeBuffer.length, buffer.getDirectReadSize()); + assertEquals(capacity - writeBuffer.length, buffer.freeSize()); + assertEquals(capacity - writeBuffer.length, buffer.getDirectWriteSize()); + + buffer.clear(); + assertEquals(0, buffer.size()); + assertEquals(0, buffer.getDirectReadSize()); + assertEquals(capacity, buffer.freeSize()); + assertEquals(capacity, buffer.getDirectWriteSize()); + } + + @Test + public void writeBytes_withRollover() { + doTestReadWriteWithRollover(new BufferAccessor(false, false)); + } + + @Test + public void writeBytes_withFullBuffer() { + doTestReadWriteWithFullBuffer(new BufferAccessor(false, false)); + } + + @Test + public void directWriteBytes_withRollover() { + doTestReadWriteWithRollover(new BufferAccessor(true, true)); + } + + @Test + public void directWriteBytes_withFullBuffer() { + doTestReadWriteWithFullBuffer(new BufferAccessor(true, true)); + } + + private void doTestReadWriteWithFullBuffer(BufferAccessor accessor) { + CircularByteBuffer buffer = doTestReadWrite(accessor, 20, 5, 4); + + assertEquals(0, buffer.size()); + assertEquals(20, buffer.freeSize()); + } + + private void doTestReadWriteWithRollover(BufferAccessor accessor) { + // All buffer sizes are prime numbers to ensure that some read or write + // operations will roll over the end of the internal buffer. + CircularByteBuffer buffer = doTestReadWrite(accessor, 31, 13, 7); + + assertNotEquals(0, buffer.size()); + } + + private CircularByteBuffer doTestReadWrite(BufferAccessor accessor, + final int capacity, final int writeLen, final int readLen) { + CircularByteBuffer buffer = new CircularByteBuffer(capacity); + + final byte[] writeBuffer = new byte[writeLen + 2]; + final byte[] peekBuffer = new byte[readLen + 2]; + final byte[] readBuffer = new byte[readLen + 2]; + + final int numIterations = 1011; + final int maxRemaining = readLen - 1; + + int currentWriteSymbol = 0; + int expectedReadSymbol = 0; + int expectedSize = 0; + int totalWritten = 0; + int totalRead = 0; + + for (int i = 0; i < numIterations; i++) { + // Fill in with write buffers as much as possible. + while (buffer.freeSize() >= writeLen) { + currentWriteSymbol = fillTestBytes(writeBuffer, 1, writeLen, currentWriteSymbol); + accessor.writeBytes(buffer, writeBuffer, 1, writeLen); + + expectedSize += writeLen; + totalWritten += writeLen; + assertEquals(expectedSize, buffer.size()); + assertEquals(capacity - expectedSize, buffer.freeSize()); + } + + // Keep reading into read buffers while there's still data. + while (buffer.size() >= readLen) { + peekBuffer[1] = 0; + peekBuffer[2] = 0; + buffer.peekBytes(2, peekBuffer, 3, readLen - 2); + assertEquals(0, peekBuffer[1]); + assertEquals(0, peekBuffer[2]); + + peekBuffer[2] = buffer.peek(1); + + accessor.readBytes(buffer, readBuffer, 1, readLen); + peekBuffer[1] = readBuffer[1]; + + expectedReadSymbol = checkTestBytes( + readBuffer, 1, readLen, expectedReadSymbol, totalRead); + + assertArrayEquals(peekBuffer, readBuffer); + + expectedSize -= readLen; + totalRead += readLen; + assertEquals(expectedSize, buffer.size()); + assertEquals(capacity - expectedSize, buffer.freeSize()); + } + + if (buffer.size() > maxRemaining) { + fail("Too much data remaining: " + buffer.size()); + } + } + + final int maxWritten = capacity * numIterations; + final int minWritten = maxWritten / 2; + if (totalWritten < minWritten || totalWritten > maxWritten + || (totalWritten - totalRead) > maxRemaining) { + fail("Unexpected counts: read=" + totalRead + ", written=" + totalWritten + + ", minWritten=" + minWritten + ", maxWritten=" + maxWritten); + } + + return buffer; + } + + @Test + public void readBytes_overflow() { + CircularByteBuffer buffer = new CircularByteBuffer(23); + + final byte[] dataBuffer = new byte[15]; + buffer.writeBytes(dataBuffer, 0, dataBuffer.length - 2); + + try { + buffer.readBytes(dataBuffer, 0, dataBuffer.length); + assertTrue(false); + } catch (IllegalArgumentException e) { + // expected + } + + assertEquals(13, buffer.size()); + assertEquals(10, buffer.freeSize()); + } + + @Test + public void writeBytes_overflow() { + CircularByteBuffer buffer = new CircularByteBuffer(23); + + final byte[] dataBuffer = new byte[15]; + buffer.writeBytes(dataBuffer, 0, dataBuffer.length); + + try { + buffer.writeBytes(dataBuffer, 0, dataBuffer.length); + assertTrue(false); + } catch (IllegalArgumentException e) { + // expected + } + + assertEquals(15, buffer.size()); + assertEquals(8, buffer.freeSize()); + } + + private static int fillTestBytes(byte[] buffer, int pos, int len, int startValue) { + for (int i = 0; i < len; i++) { + buffer[pos + i] = (byte) (startValue & 0xFF); + startValue = (startValue + 1) % 256; + } + return startValue; + } + + private static int checkTestBytes( + byte[] buffer, int pos, int len, int startValue, int totalRead) { + for (int i = 0; i < len; i++) { + byte expectedValue = (byte) (startValue & 0xFF); + if (expectedValue != buffer[pos + i]) { + fail("Unexpected byte=" + (((int) buffer[pos + i]) & 0xFF) + + ", expected=" + (((int) expectedValue) & 0xFF) + + ", pos=" + (totalRead + i)); + } + startValue = (startValue + 1) % 256; + } + return startValue; + } + + private static final class BufferAccessor { + private final boolean mDirectRead; + private final boolean mDirectWrite; + + BufferAccessor(boolean directRead, boolean directWrite) { + mDirectRead = directRead; + mDirectWrite = directWrite; + } + + void writeBytes(CircularByteBuffer buffer, byte[] src, int pos, int len) { + if (mDirectWrite) { + while (len > 0) { + if (buffer.getDirectWriteSize() == 0) { + fail("Direct write size is zero: free=" + buffer.freeSize() + + ", size=" + buffer.size()); + } + int copyLen = Math.min(len, buffer.getDirectWriteSize()); + System.arraycopy(src, pos, buffer.getDirectWriteBuffer(), + buffer.getDirectWritePos(), copyLen); + buffer.accountForDirectWrite(copyLen); + len -= copyLen; + pos += copyLen; + } + } else { + buffer.writeBytes(src, pos, len); + } + } + + void readBytes(CircularByteBuffer buffer, byte[] dst, int pos, int len) { + if (mDirectRead) { + while (len > 0) { + if (buffer.getDirectReadSize() == 0) { + fail("Direct read size is zero: free=" + buffer.freeSize() + + ", size=" + buffer.size()); + } + int copyLen = Math.min(len, buffer.getDirectReadSize()); + System.arraycopy( + buffer.getDirectReadBuffer(), buffer.getDirectReadPos(), dst, pos, copyLen); + buffer.accountForDirectRead(copyLen); + len -= copyLen; + pos += copyLen; + } + } else { + buffer.readBytes(dst, pos, len); + } + } + } +} From 508c60d87ac070d40371252f6469a3c50f733321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 27 Dec 2022 01:50:37 +0000 Subject: [PATCH 629/777] Treat unknown dns modes as empty string (ie. opportunistic) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 260211513 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I39282d887ec17bf4ed7aee2a7ae712d69b94bc31 --- .../net/module/util/ConnectivitySettingsUtils.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/ConnectivitySettingsUtils.java b/staticlibs/framework/com/android/net/module/util/ConnectivitySettingsUtils.java index b7eb70b08b..f4856b344f 100644 --- a/staticlibs/framework/com/android/net/module/util/ConnectivitySettingsUtils.java +++ b/staticlibs/framework/com/android/net/module/util/ConnectivitySettingsUtils.java @@ -60,6 +60,10 @@ public class ConnectivitySettingsUtils { } private static int getPrivateDnsModeAsInt(String mode) { + // If both PRIVATE_DNS_MODE and PRIVATE_DNS_DEFAULT_MODE are not set, choose + // PRIVATE_DNS_MODE_OPPORTUNISTIC as default mode. + if (TextUtils.isEmpty(mode)) + return PRIVATE_DNS_MODE_OPPORTUNISTIC; switch (mode) { case "off": return PRIVATE_DNS_MODE_OFF; @@ -68,7 +72,10 @@ public class ConnectivitySettingsUtils { case "opportunistic": return PRIVATE_DNS_MODE_OPPORTUNISTIC; default: - throw new IllegalArgumentException("Invalid private dns mode: " + mode); + // b/260211513: adb shell settings put global private_dns_mode foo + // can result in arbitrary strings - treat any unknown value as empty string. + // throw new IllegalArgumentException("Invalid private dns mode: " + mode); + return PRIVATE_DNS_MODE_OPPORTUNISTIC; } } @@ -82,9 +89,6 @@ public class ConnectivitySettingsUtils { final ContentResolver cr = context.getContentResolver(); String mode = Settings.Global.getString(cr, PRIVATE_DNS_MODE); if (TextUtils.isEmpty(mode)) mode = Settings.Global.getString(cr, PRIVATE_DNS_DEFAULT_MODE); - // If both PRIVATE_DNS_MODE and PRIVATE_DNS_DEFAULT_MODE are not set, choose - // PRIVATE_DNS_MODE_OPPORTUNISTIC as default mode. - if (TextUtils.isEmpty(mode)) return PRIVATE_DNS_MODE_OPPORTUNISTIC; return getPrivateDnsModeAsInt(mode); } From 17686b4c0527b6f7a3ce08de55c78e54882d7be7 Mon Sep 17 00:00:00 2001 From: Igor Chernyshev Date: Tue, 20 Dec 2022 11:08:50 -0800 Subject: [PATCH 630/777] Add base async io interfaces for wear tethering Bug: 245971639 Change-Id: I31ccd7193409c82a0902e4ae318cc096f93f32da --- .../net/module/util/async/AsyncFile.java | 78 +++++++++++++++++++ .../net/module/util/async/EventManager.java | 75 ++++++++++++++++++ .../net/module/util/async/FileHandle.java | 74 ++++++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/async/AsyncFile.java create mode 100644 staticlibs/device/com/android/net/module/util/async/EventManager.java create mode 100644 staticlibs/device/com/android/net/module/util/async/FileHandle.java diff --git a/staticlibs/device/com/android/net/module/util/async/AsyncFile.java b/staticlibs/device/com/android/net/module/util/async/AsyncFile.java new file mode 100644 index 0000000000..2a3231b718 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/async/AsyncFile.java @@ -0,0 +1,78 @@ +/* + * 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 com.android.net.module.util.async; + +import java.io.IOException; + +/** + * Represents an EventManager-managed file with Async IO semantics. + * + * Implements level-based Asyn IO semantics. This means that: + * - onReadReady() callback would keep happening as long as there's any remaining + * data to read, or the user calls enableReadEvents(false) + * - onWriteReady() callback would keep happening as long as there's remaining space + * to write to, or the user calls enableWriteEvents(false) + * + * All operations except close() must be called on the EventManager thread. + * + * @hide + */ +public interface AsyncFile { + /** + * Receives notifications when file readability or writeability changes. + * @hide + */ + public interface Listener { + /** Invoked after the underlying file has been closed. */ + void onClosed(AsyncFile file); + + /** Invoked while the file has readable data and read notifications are enabled. */ + void onReadReady(AsyncFile file); + + /** Invoked while the file has writeable space and write notifications are enabled. */ + void onWriteReady(AsyncFile file); + } + + /** Requests this file to be closed. */ + void close(); + + /** Enables or disables onReadReady() events. */ + void enableReadEvents(boolean enable); + + /** Enables or disables onWriteReady() events. */ + void enableWriteEvents(boolean enable); + + /** Returns true if the input stream has reached its end, or has been closed. */ + boolean reachedEndOfFile(); + + /** + * Reads available data from the given non-blocking file descriptor. + * + * Returns zero if there's no data to read at this moment. + * Returns -1 if the file has reached its end or the input stream has been closed. + * Otherwise returns the number of bytes read. + */ + int read(byte[] buffer, int pos, int len) throws IOException; + + /** + * Writes data into the given non-blocking file descriptor. + * + * Returns zero if there's no buffer space to write to at this moment. + * Otherwise returns the number of bytes written. + */ + int write(byte[] buffer, int pos, int len) throws IOException; +} diff --git a/staticlibs/device/com/android/net/module/util/async/EventManager.java b/staticlibs/device/com/android/net/module/util/async/EventManager.java new file mode 100644 index 0000000000..4ed4a70404 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/async/EventManager.java @@ -0,0 +1,75 @@ +/* + * 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 com.android.net.module.util.async; + +import java.io.IOException; +import java.util.concurrent.Executor; + +/** + * Manages Async IO files and scheduled alarms, and executes all related callbacks + * in its own thread. + * + * All callbacks of AsyncFile, Alarm and EventManager will execute on EventManager's thread. + * + * Methods of this interface can be called from any thread. + * + * @hide + */ +public interface EventManager extends Executor { + /** + * Represents a scheduled alarm, allowing caller to attempt to cancel that alarm + * before it executes. + * + * @hide + */ + public interface Alarm { + /** @hide */ + public interface Listener { + void onAlarm(Alarm alarm, long elapsedTimeMs); + void onAlarmCancelled(Alarm alarm); + } + + /** + * Attempts to cancel this alarm. Note that this request is inherently + * racy if executed close to the alarm's expiration time. + */ + void cancel(); + } + + /** + * Requests EventManager to manage the given file. + * + * The file descriptors are not cloned, and EventManager takes ownership of all files passed. + * + * No event callbacks are enabled by this method. + */ + AsyncFile registerFile(FileHandle fileHandle, AsyncFile.Listener listener) throws IOException; + + /** + * Schedules Alarm with the given timeout. + * + * Timeout of zero can be used for immediate execution. + */ + Alarm scheduleAlarm(long timeout, Alarm.Listener callback); + + /** Schedules Runnable for immediate execution. */ + @Override + void execute(Runnable callback); + + /** Throws a runtime exception if the caller is not executing on this EventManager's thread. */ + void assertInThread(); +} diff --git a/staticlibs/device/com/android/net/module/util/async/FileHandle.java b/staticlibs/device/com/android/net/module/util/async/FileHandle.java new file mode 100644 index 0000000000..9f7942d425 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/async/FileHandle.java @@ -0,0 +1,74 @@ +/* + * 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 com.android.net.module.util.async; + +import android.os.ParcelFileDescriptor; + +import java.io.Closeable; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Represents an file descriptor or another way to access a file. + * + * @hide + */ +public final class FileHandle { + private final ParcelFileDescriptor mFd; + private final Closeable mCloseable; + private final InputStream mInputStream; + private final OutputStream mOutputStream; + + public static FileHandle fromFileDescriptor(ParcelFileDescriptor fd) { + if (fd == null) { + throw new NullPointerException(); + } + return new FileHandle(fd, null, null, null); + } + + public static FileHandle fromBlockingStream( + Closeable closeable, InputStream is, OutputStream os) { + if (closeable == null || is == null || os == null) { + throw new NullPointerException(); + } + return new FileHandle(null, closeable, is, os); + } + + private FileHandle(ParcelFileDescriptor fd, Closeable closeable, + InputStream is, OutputStream os) { + mFd = fd; + mCloseable = closeable; + mInputStream = is; + mOutputStream = os; + } + + ParcelFileDescriptor getFileDescriptor() { + return mFd; + } + + Closeable getCloseable() { + return mCloseable; + } + + InputStream getInputStream() { + return mInputStream; + } + + OutputStream getOutputStream() { + return mOutputStream; + } +} From 888bd2de6764e16ca5b17aba9ed94e4f01b5b788 Mon Sep 17 00:00:00 2001 From: Ryan Zuklie Date: Wed, 4 Jan 2023 16:09:02 -0800 Subject: [PATCH 631/777] Update bpf helpers to support new ignore_on fields This updates the ringbuffer and program helpers to allow specifying which platform builds they are ignored on. In order to use this, you must specify a min loader version >= 0.32, so the helpers also add options for setting this at the program/ringbuf level. Bug: 246985031 Test: tethering build & install, full platform build & install Change-Id: I6bf9f7945c3fbac8fd4e02b5805016ac275b7884 --- .../bpf_headers/include/bpf/bpf_helpers.h | 128 +++++++++++------- .../bpf_headers/include/bpf/bpf_map_def.h | 4 +- 2 files changed, 78 insertions(+), 54 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 66dccf33fc..ed1ee51143 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -40,6 +40,9 @@ // BpfLoader v0.25+ support obj@ver.o files #define BPFLOADER_OBJ_AT_VER_VERSION 25u +// Bpfloader v0.33+ supports {map,prog}.ignore_on_{eng,user,userdebug} +#define BPFLOADER_IGNORED_ON_VERSION 33u + /* For mainline module use, you can #define BPFLOADER_{MIN/MAX}_VER * before #include "bpf_helpers.h" to change which bpfloaders will * process the resulting .o file. @@ -155,26 +158,37 @@ static void (*bpf_ringbuf_submit_unsafe)(const void* data, __u64 flags) = (void* __attribute__ ((section(".maps." #name), used)) \ ____btf_map_##name = { } +#define BPF_ASSERT_LOADER_VERSION(min_loader, ignore_eng, ignore_user, ignore_userdebug) \ + _Static_assert( \ + (min_loader) >= BPFLOADER_IGNORED_ON_VERSION || \ + !((ignore_eng) || (ignore_user) || (ignore_userdebug)), \ + "bpfloader min version must be >= 0.33 in order to use ignored_on"); + #define DEFINE_BPF_MAP_BASE(the_map, TYPE, keysize, valuesize, num_entries, \ usr, grp, md, selinux, pindir, share, minkver, \ - maxkver) \ - const struct bpf_map_def SECTION("maps") the_map = { \ - .type = BPF_MAP_TYPE_##TYPE, \ - .key_size = (keysize), \ - .value_size = (valuesize), \ - .max_entries = (num_entries), \ - .map_flags = 0, \ - .uid = (usr), \ - .gid = (grp), \ - .mode = (md), \ - .bpfloader_min_ver = BPFLOADER_MIN_VER, \ - .bpfloader_max_ver = BPFLOADER_MAX_VER, \ - .min_kver = (minkver), \ - .max_kver = (maxkver), \ - .selinux_context = (selinux), \ - .pin_subdir = (pindir), \ - .shared = (share), \ - }; + maxkver, minloader, maxloader, ignore_eng, \ + ignore_user, ignore_userdebug) \ + const struct bpf_map_def SECTION("maps") the_map = { \ + .type = BPF_MAP_TYPE_##TYPE, \ + .key_size = (keysize), \ + .value_size = (valuesize), \ + .max_entries = (num_entries), \ + .map_flags = 0, \ + .uid = (usr), \ + .gid = (grp), \ + .mode = (md), \ + .bpfloader_min_ver = (minloader), \ + .bpfloader_max_ver = (maxloader), \ + .min_kver = (minkver), \ + .max_kver = (maxkver), \ + .selinux_context = (selinux), \ + .pin_subdir = (pindir), \ + .shared = (share), \ + .ignore_on_eng = (ignore_eng), \ + .ignore_on_user = (ignore_user), \ + .ignore_on_userdebug = (ignore_userdebug), \ + }; \ + BPF_ASSERT_LOADER_VERSION(minloader, ignore_eng, ignore_user, ignore_userdebug); // Type safe macro to declare a ring buffer and related output functions. // Compatibility: @@ -182,22 +196,25 @@ static void (*bpf_ringbuf_submit_unsafe)(const void* data, __u64 flags) = (void* // accessing the ring buffer should set a program level min_kver >= 5.8. // * The definition below sets a map min_kver of 5.8 which requires targeting // a BPFLOADER_MIN_VER >= BPFLOADER_S_VERSION. -#define DEFINE_BPF_RINGBUF_EXT(the_map, ValueType, size_bytes, usr, grp, md, \ - selinux, pindir, share) \ - DEFINE_BPF_MAP_BASE(the_map, RINGBUF, 0, 0, size_bytes, usr, grp, md, \ - selinux, pindir, share, KVER(5, 8, 0), KVER_INF); \ - static inline __always_inline __unused int bpf_##the_map##_output( \ - const ValueType* v) { \ - return bpf_ringbuf_output_unsafe(&the_map, v, sizeof(*v), 0); \ - } \ - static inline __always_inline __unused \ - ValueType* bpf_##the_map##_reserve() { \ - return bpf_ringbuf_reserve_unsafe(&the_map, sizeof(ValueType), 0); \ - } \ - static inline __always_inline __unused void bpf_##the_map##_submit( \ - const ValueType* v) { \ - bpf_ringbuf_submit_unsafe(v, 0); \ - } +#define DEFINE_BPF_RINGBUF_EXT(the_map, ValueType, size_bytes, usr, grp, md, \ + selinux, pindir, share, min_loader, max_loader, \ + ignore_eng, ignore_user, ignore_userdebug) \ + DEFINE_BPF_MAP_BASE(the_map, RINGBUF, 0, 0, size_bytes, usr, grp, md, \ + selinux, pindir, share, KVER(5, 8, 0), KVER_INF, \ + min_loader, max_loader, ignore_eng, ignore_user, \ + ignore_userdebug); \ + static inline __always_inline __unused int bpf_##the_map##_output( \ + const ValueType* v) { \ + return bpf_ringbuf_output_unsafe(&the_map, v, sizeof(*v), 0); \ + } \ + static inline __always_inline __unused \ + ValueType* bpf_##the_map##_reserve() { \ + return bpf_ringbuf_reserve_unsafe(&the_map, sizeof(ValueType), 0); \ + } \ + static inline __always_inline __unused void bpf_##the_map##_submit( \ + const ValueType* v) { \ + bpf_ringbuf_submit_unsafe(v, 0); \ + } /* There exist buggy kernels with pre-T OS, that due to * kernel patch "[ALPS05162612] bpf: fix ubsan error" @@ -221,7 +238,8 @@ static void (*bpf_ringbuf_submit_unsafe)(const void* data, __u64 flags) = (void* selinux, pindir, share) \ DEFINE_BPF_MAP_BASE(the_map, TYPE, sizeof(KeyType), sizeof(ValueType), \ num_entries, usr, grp, md, selinux, pindir, share, \ - KVER_NONE, KVER_INF); \ + KVER_NONE, KVER_INF, BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, \ + false, false, false); \ BPF_MAP_ASSERT_OK(BPF_MAP_TYPE_##TYPE, (num_entries), (md)); \ BPF_ANNOTATE_KV_PAIR(the_map, KeyType, ValueType); \ \ @@ -293,20 +311,24 @@ static unsigned long long (*bpf_get_smp_processor_id)(void) = (void*) BPF_FUNC_g static long (*bpf_get_stackid)(void* ctx, void* map, uint64_t flags) = (void*) BPF_FUNC_get_stackid; static long (*bpf_get_current_comm)(void* buf, uint32_t buf_size) = (void*) BPF_FUNC_get_current_comm; -#define DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, opt, \ - selinux, pindir) \ - const struct bpf_prog_def SECTION("progs") the_prog##_def = { \ - .uid = (prog_uid), \ - .gid = (prog_gid), \ - .min_kver = (min_kv), \ - .max_kver = (max_kv), \ - .optional = (opt), \ - .bpfloader_min_ver = BPFLOADER_MIN_VER, \ - .bpfloader_max_ver = BPFLOADER_MAX_VER, \ - .selinux_context = selinux, \ - .pin_subdir = pindir, \ - }; \ - SECTION(SECTION_NAME) \ +#define DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \ + min_loader, max_loader, opt, selinux, pindir, ignore_eng, \ + ignore_user, ignore_userdebug) \ + const struct bpf_prog_def SECTION("progs") the_prog##_def = { \ + .uid = (prog_uid), \ + .gid = (prog_gid), \ + .min_kver = (min_kv), \ + .max_kver = (max_kv), \ + .optional = (opt), \ + .bpfloader_min_ver = (min_loader), \ + .bpfloader_max_ver = (max_loader), \ + .selinux_context = (selinux), \ + .pin_subdir = (pindir), \ + .ignore_on_eng = (ignore_eng), \ + .ignore_on_user = (ignore_user), \ + .ignore_on_userdebug = (ignore_userdebug), \ + }; \ + SECTION(SECTION_NAME) \ int the_prog #ifndef DEFAULT_BPF_PROG_SELINUX_CONTEXT @@ -318,9 +340,11 @@ static long (*bpf_get_current_comm)(void* buf, uint32_t buf_size) = (void*) BPF_ #endif #define DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \ - opt) \ - DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, opt, \ - DEFAULT_BPF_PROG_SELINUX_CONTEXT, DEFAULT_BPF_PROG_PIN_SUBDIR) + opt) \ + DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \ + BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, opt, \ + DEFAULT_BPF_PROG_SELINUX_CONTEXT, DEFAULT_BPF_PROG_PIN_SUBDIR, \ + false, false, false) // Programs (here used in the sense of functions/sections) marked optional are allowed to fail // to load (for example due to missing kernel patches). diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h index f17cf3ac1a..d286eba001 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h @@ -204,8 +204,8 @@ struct bpf_prog_def { bool optional; // program section (ie. function) may fail to load, continue onto next func. - // The following 3 ignore_on_* fields were added in version 0.32 (U). These are ignored in - // older bpfloader versions, and zero in programs compiled before 0.32. + // The following 3 ignore_on_* fields were added in version 0.33 (U). These are ignored in + // older bpfloader versions, and zero in programs compiled before 0.33. bool ignore_on_eng:1; bool ignore_on_user:1; bool ignore_on_userdebug:1; From 5987fc4fbe986a38ffbf4c9a6806ba072cfbf5fb Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 6 Jan 2023 15:23:57 +0900 Subject: [PATCH 632/777] Cleanup TestableNetworkCallback#assertNoCallback Test: FrameworksNetTests CtsNetTestCases FrameworksNetIntegrationTests NetworkStackTests NetworkStaticLibTests TetheringTests MtsTetheringTestLatestSdk TetheringIntegrationTests Bug: 157405399 Change-Id: I43eb47bbcf947899c18fcd9498c9064edceb0ecf --- .../testutils/TestableNetworkCallbackTest.kt | 30 +++++------ .../testutils/TestableNetworkCallback.kt | 54 ++++++++++++------- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt index f8f2da085b..eed31e0f1b 100644 --- a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt +++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt @@ -22,29 +22,29 @@ import android.net.LinkProperties import android.net.Network import android.net.NetworkCapabilities import com.android.testutils.RecorderCallback.CallbackEntry +import com.android.testutils.RecorderCallback.CallbackEntry.Available +import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatus +import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged import com.android.testutils.RecorderCallback.CallbackEntry.Companion.AVAILABLE import com.android.testutils.RecorderCallback.CallbackEntry.Companion.BLOCKED_STATUS import com.android.testutils.RecorderCallback.CallbackEntry.Companion.LINK_PROPERTIES_CHANGED import com.android.testutils.RecorderCallback.CallbackEntry.Companion.LOSING -import com.android.testutils.RecorderCallback.CallbackEntry.Companion.NETWORK_CAPS_UPDATED import com.android.testutils.RecorderCallback.CallbackEntry.Companion.LOST +import com.android.testutils.RecorderCallback.CallbackEntry.Companion.NETWORK_CAPS_UPDATED import com.android.testutils.RecorderCallback.CallbackEntry.Companion.RESUMED import com.android.testutils.RecorderCallback.CallbackEntry.Companion.SUSPENDED import com.android.testutils.RecorderCallback.CallbackEntry.Companion.UNAVAILABLE -import com.android.testutils.RecorderCallback.CallbackEntry.Available -import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatus -import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.JUnit4 -import org.junit.Assume.assumeTrue import kotlin.reflect.KClass import kotlin.test.assertEquals import kotlin.test.assertFails import kotlin.test.assertNull import kotlin.test.assertTrue import kotlin.test.fail +import org.junit.Assume.assumeTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 const val SHORT_TIMEOUT_MS = 20L const val DEFAULT_LINGER_DELAY_MS = 30000 @@ -121,20 +121,16 @@ class TestableNetworkCallbackTest { mCallback.assertNoCallback(SHORT_TIMEOUT_MS) mCallback.onAvailable(Network(100)) assertFails { mCallback.assertNoCallback(SHORT_TIMEOUT_MS) } - } - - @Test - fun testAssertNoCallbackThat() { val net = Network(101) - mCallback.assertNoCallbackThat { it is Available } + mCallback.assertNoCallback { it is Available } mCallback.onAvailable(net) // Expect no blocked status change. Receive other callback does not fail the test. - mCallback.assertNoCallbackThat { it is BlockedStatus } + mCallback.assertNoCallback { it is BlockedStatus } mCallback.onBlockedStatusChanged(net, true) - assertFails { mCallback.assertNoCallbackThat { it is BlockedStatus } } + assertFails { mCallback.assertNoCallback { it is BlockedStatus } } mCallback.onBlockedStatusChanged(net, false) mCallback.onCapabilitiesChanged(net, NetworkCapabilities()) - assertFails { mCallback.assertNoCallbackThat { it is CapabilitiesChanged } } + assertFails { mCallback.assertNoCallback { it is CapabilitiesChanged } } } @Test diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index 124d13402f..68d5fa91fd 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -167,20 +167,43 @@ open class RecorderCallback private constructor( private const val DEFAULT_TIMEOUT = 30_000L // ms private const val DEFAULT_NO_CALLBACK_TIMEOUT = 200L // ms +private val NOOP = Runnable {} +/** + * See comments on the public constructor below for a description of the arguments. + */ open class TestableNetworkCallback private constructor( src: TestableNetworkCallback?, val defaultTimeoutMs: Long = DEFAULT_TIMEOUT, - val defaultNoCallbackTimeoutMs: Long = DEFAULT_NO_CALLBACK_TIMEOUT + val defaultNoCallbackTimeoutMs: Long = DEFAULT_NO_CALLBACK_TIMEOUT, + val waiterFunc: Runnable = NOOP // "() -> Unit" would forbid calling with a void func from Java ) : RecorderCallback(src) { + /** + * Construct a testable network callback. + * @param timeoutMs the default timeout for expecting a callback. Default 30 seconds. This + * should be long in most cases, because the success case doesn't incur + * the wait. + * @param noCallbackTimeoutMs the timeout for expecting that no callback is received. Default + * 200ms. Because the success case does incur the timeout, this + * should be short in most cases, but not so short as to frequently + * time out before an incorrect callback is received. + * @param waiterFunc a function to use before asserting no callback. For some specific tests, + * it is useful to run test-specific code before asserting no callback to + * increase the likelihood that a spurious callback is correctly detected. + * As an example, a unit test using mock loopers may want to use this to + * make sure the loopers are drained before asserting no callback, since + * one of them may cause a callback to be called. @see ConnectivityServiceTest + * for such an example. + */ @JvmOverloads constructor( timeoutMs: Long = DEFAULT_TIMEOUT, - noCallbackTimeoutMs: Long = DEFAULT_NO_CALLBACK_TIMEOUT - ) : this(null, timeoutMs, noCallbackTimeoutMs) + noCallbackTimeoutMs: Long = DEFAULT_NO_CALLBACK_TIMEOUT, + waiterFunc: Runnable = NOOP + ) : this(null, timeoutMs, noCallbackTimeoutMs, waiterFunc) fun createLinkedCopy() = TestableNetworkCallback( - this, defaultTimeoutMs, defaultNoCallbackTimeoutMs) + this, defaultTimeoutMs, defaultNoCallbackTimeoutMs, waiterFunc) // The last available network, or null if any network was lost since the last call to // onAvailable. TODO : fix this by fixing the tests that rely on this behavior @@ -343,25 +366,18 @@ open class TestableNetworkCallback private constructor( test: (T) -> Boolean = { true } ) = expect(network.network, timeoutMs, errorMsg, test) - // Make open for use in ConnectivityServiceTest which is the only one knowing its handlers. - // TODO : remove the necessity to overload this, remove the open qualifier, and give a - // default argument to assertNoCallback instead, possibly with @JvmOverloads if necessary. - open fun assertNoCallback() = assertNoCallback(defaultNoCallbackTimeoutMs) - - fun assertNoCallback(timeoutMs: Long) { - val cb = history.poll(timeoutMs) - if (null != cb) fail("Expected no callback but got $cb") - } - - fun assertNoCallbackThat( + @JvmOverloads + fun assertNoCallback( timeoutMs: Long = defaultNoCallbackTimeoutMs, - valid: (CallbackEntry) -> Boolean + valid: (CallbackEntry) -> Boolean = { true } ) { - val cb = history.poll(timeoutMs) { valid(it) }.let { - if (null != it) fail("Expected no callback but got $it") - } + waiterFunc.run() + history.poll(timeoutMs) { valid(it) }?.let { fail("Expected no callback but got $it") } } + fun assertNoCallback(valid: (CallbackEntry) -> Boolean) = + assertNoCallback(defaultNoCallbackTimeoutMs, valid) + // Expects a callback of the specified type matching the predicate within the timeout. // Any callback that doesn't match the predicate will be skipped. Fails only if // no matching callback is received within the timeout. From b4ecb5e750397554f39460305ad92ceffc1e775e Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 12 Jan 2023 15:04:06 +0800 Subject: [PATCH 633/777] Return default value when getModuleVersion throwed In aosp, getModuleVersion would always throw since there is no meta-info for modules. Currently it would make isFeatureEnabled method return false, which is not a right thing for features are default enabled. Change it to return default value when throwed. Test: atest NetworkStaticLibTests Bug: 263219497 Change-Id: Iadcdcedac1f1da7d894e03b76b3e985f87ca8b0e --- .../device/com/android/net/module/util/DeviceConfigUtils.java | 2 +- .../com/android/net/module/util/DeviceConfigUtilsTest.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index f8f250d745..1225aa7e23 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -194,7 +194,7 @@ public final class DeviceConfigUtils { return isFeatureEnabled(context, packageVersion, namespace, name, defaultEnabled); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Could not find the module name", e); - return false; + return defaultEnabled; } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java index a8e7993ae9..302388db31 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -223,9 +223,13 @@ public class DeviceConfigUtilsTest { TEST_EXPERIMENT_FLAG)); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, true /* defaultEnabled */)); doThrow(NameNotFoundException.class).when(mPm).getModuleInfo(anyString(), anyInt()); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, true /* defaultEnabled */)); } From 004c5b422bcb1457c5a06f64ec362acdb8dbea9d Mon Sep 17 00:00:00 2001 From: Igor Chernyshev Date: Thu, 5 Jan 2023 19:25:18 -0800 Subject: [PATCH 634/777] Add OS access interfaces and test impl for wear tethering Bug: 245971639 Change-Id: I750c2e9bbe8c9a3992ae91d9fea4958bfce60828 --- .../net/module/util/async/OsAccess.java | 66 ++ staticlibs/testutils/Android.bp | 1 + .../android/testutils/async/FakeOsAccess.java | 568 ++++++++++++++++++ .../android/testutils/async/RateLimiter.java | 131 ++++ 4 files changed, 766 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/async/OsAccess.java create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/async/FakeOsAccess.java create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/async/RateLimiter.java diff --git a/staticlibs/device/com/android/net/module/util/async/OsAccess.java b/staticlibs/device/com/android/net/module/util/async/OsAccess.java new file mode 100644 index 0000000000..df0ded219c --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/async/OsAccess.java @@ -0,0 +1,66 @@ +/* + * 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 com.android.net.module.util.async; + +import android.os.ParcelFileDescriptor; +import android.system.StructPollfd; + +import java.io.FileDescriptor; +import java.io.IOException; + +/** + * Provides access to all relevant OS functions.. + * + * @hide + */ +public abstract class OsAccess { + /** Closes the given file, suppressing IO exceptions. */ + public abstract void close(ParcelFileDescriptor fd); + + /** Returns file name for debugging purposes. */ + public abstract String getFileDebugName(ParcelFileDescriptor fd); + + /** Returns inner FileDescriptor instance. */ + public abstract FileDescriptor getInnerFileDescriptor(ParcelFileDescriptor fd); + + /** + * Reads available data from the given non-blocking file descriptor. + * + * Returns zero if there's no data to read at this moment. + * Returns -1 if the file has reached its end or the input stream has been closed. + * Otherwise returns the number of bytes read. + */ + public abstract int read(FileDescriptor fd, byte[] buffer, int pos, int len) + throws IOException; + + /** + * Writes data into the given non-blocking file descriptor. + * + * Returns zero if there's no buffer space to write to at this moment. + * Otherwise returns the number of bytes written. + */ + public abstract int write(FileDescriptor fd, byte[] buffer, int pos, int len) + throws IOException; + + public abstract long monotonicTimeMillis(); + public abstract void setNonBlocking(FileDescriptor fd) throws IOException; + public abstract ParcelFileDescriptor[] pipe() throws IOException; + + public abstract int poll(StructPollfd[] fds, int timeoutMs) throws IOException; + public abstract short getPollInMask(); + public abstract short getPollOutMask(); +} diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index c9b3d070f8..bcf89b3417 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -36,6 +36,7 @@ java_library { "libnanohttpd", "net-tests-utils-host-device-common", "net-utils-device-common", + "net-utils-device-common-async", "net-utils-device-common-netlink", "modules-utils-build_system", ], diff --git a/staticlibs/testutils/devicetests/com/android/testutils/async/FakeOsAccess.java b/staticlibs/testutils/devicetests/com/android/testutils/async/FakeOsAccess.java new file mode 100644 index 0000000000..1b8e26b30f --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/async/FakeOsAccess.java @@ -0,0 +1,568 @@ +/* + * 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 com.android.testutils; + +import android.os.ParcelFileDescriptor; +import android.system.StructPollfd; +import android.util.Log; + +import com.android.net.module.util.async.CircularByteBuffer; +import com.android.net.module.util.async.OsAccess; + +import java.io.FileDescriptor; +import java.io.InterruptedIOException; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.concurrent.TimeUnit; + +public class FakeOsAccess extends OsAccess { + public static final boolean ENABLE_FINE_DEBUG = true; + + public static final int DEFAULT_FILE_DATA_QUEUE_SIZE = 8 * 1024; + + private enum FileType { PAIR, PIPE } + + // Common poll() constants: + private static final short POLLIN = 0x0001; + private static final short POLLOUT = 0x0004; + private static final short POLLERR = 0x0008; + private static final short POLLHUP = 0x0010; + + private static final Constructor FD_CONSTRUCTOR; + private static final Field FD_FIELD_DESCRIPTOR; + private static final Field PFD_FIELD_DESCRIPTOR; + private static final Field PFD_FIELD_GUARD; + private static final Method CLOSE_GUARD_METHOD_CLOSE; + + private final int mReadQueueSize = DEFAULT_FILE_DATA_QUEUE_SIZE; + private final int mWriteQueueSize = DEFAULT_FILE_DATA_QUEUE_SIZE; + private final HashMap mFiles = new HashMap<>(); + private final byte[] mTmpBuffer = new byte[1024]; + private final long mStartTime; + private final String mLogTag; + private int mFileNumberGen = 3; + private boolean mHasRateLimitedData; + + public FakeOsAccess(String logTag) { + mLogTag = logTag; + mStartTime = monotonicTimeMillis(); + } + + @Override + public long monotonicTimeMillis() { + return System.nanoTime() / 1000000; + } + + @Override + public FileDescriptor getInnerFileDescriptor(ParcelFileDescriptor fd) { + try { + return (FileDescriptor) PFD_FIELD_DESCRIPTOR.get(fd); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void close(ParcelFileDescriptor fd) { + if (fd != null) { + close(getInnerFileDescriptor(fd)); + + try { + // Reduce CloseGuard warnings. + Object guard = PFD_FIELD_GUARD.get(fd); + CLOSE_GUARD_METHOD_CLOSE.invoke(guard); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + public synchronized void close(FileDescriptor fd) { + if (fd != null) { + File file = getFileOrNull(fd); + if (file != null) { + file.decreaseRefCount(); + mFiles.remove(getFileDescriptorNumber(fd)); + setFileDescriptorNumber(fd, -1); + notifyAll(); + } + } + } + + private File getFile(String func, FileDescriptor fd) throws IOException { + File file = getFileOrNull(fd); + if (file == null) { + throw newIOException(func, "Unknown file descriptor: " + getFileDebugName(fd)); + } + return file; + } + + private File getFileOrNull(FileDescriptor fd) { + return mFiles.get(getFileDescriptorNumber(fd)); + } + + @Override + public String getFileDebugName(ParcelFileDescriptor fd) { + return (fd != null ? getFileDebugName(getInnerFileDescriptor(fd)) : "null"); + } + + public String getFileDebugName(FileDescriptor fd) { + if (fd == null) { + return "null"; + } + + final int fdNumber = getFileDescriptorNumber(fd); + File file = mFiles.get(fdNumber); + + StringBuilder sb = new StringBuilder(); + if (file != null) { + if (file.name != null) { + sb.append(file.name); + sb.append("/"); + } + sb.append(file.type); + sb.append("/"); + } else { + sb.append("BADFD/"); + } + sb.append(fdNumber); + return sb.toString(); + } + + public synchronized void setFileName(FileDescriptor fd, String name) { + File file = getFileOrNull(fd); + if (file != null) { + file.name = name; + } + } + + @Override + public synchronized void setNonBlocking(FileDescriptor fd) throws IOException { + File file = getFile("fcntl", fd); + file.isBlocking = false; + } + + @Override + public synchronized int read(FileDescriptor fd, byte[] buffer, int pos, int len) + throws IOException { + checkBoundaries("read", buffer, pos, len); + + File file = getFile("read", fd); + if (file.readQueue == null) { + throw newIOException("read", "File not readable"); + } + file.checkNonBlocking("read"); + + if (len == 0) { + return 0; + } + + final int availSize = file.readQueue.size(); + if (availSize == 0) { + if (file.isEndOfStream) { + // Java convention uses -1 to indicate end of stream. + return -1; + } + return 0; // EAGAIN + } + + final int readCount = Math.min(len, availSize); + file.readQueue.readBytes(buffer, pos, readCount); + maybeTransferData(file); + return readCount; + } + + @Override + public synchronized int write(FileDescriptor fd, byte[] buffer, int pos, int len) + throws IOException { + checkBoundaries("write", buffer, pos, len); + + File file = getFile("write", fd); + if (file.writeQueue == null) { + throw newIOException("read", "File not writable"); + } + if (file.type == FileType.PIPE && file.sink.openCount == 0) { + throw newIOException("write", "The other end of pipe is closed"); + } + file.checkNonBlocking("write"); + + if (len == 0) { + return 0; + } + + final int originalFreeSize = file.writeQueue.freeSize(); + if (originalFreeSize == 0) { + return 0; // EAGAIN + } + + final int writeCount = Math.min(len, originalFreeSize); + file.writeQueue.writeBytes(buffer, pos, writeCount); + maybeTransferData(file); + + if (file.writeQueue.freeSize() < originalFreeSize) { + final int additionalQueuedCount = originalFreeSize - file.writeQueue.freeSize(); + Log.i(mLogTag, logStr("Delaying transfer of " + additionalQueuedCount + + " bytes, queued=" + file.writeQueue.size() + ", type=" + file.type + + ", src_red=" + file.outboundLimiter + ", dst_red=" + file.sink.inboundLimiter)); + } + + return writeCount; + } + + private void maybeTransferData(File file) { + boolean hasChanges = copyFileBuffers(file, file.sink); + hasChanges = copyFileBuffers(file.source, file) || hasChanges; + + if (hasChanges) { + // TODO(b/245971639): Avoid notifying if no-one is polling. + notifyAll(); + } + } + + private boolean copyFileBuffers(File src, File dst) { + if (src.writeQueue == null || dst.readQueue == null) { + return false; + } + + final int originalCopyCount = Math.min(mTmpBuffer.length, + Math.min(src.writeQueue.size(), dst.readQueue.freeSize())); + + final int allowedCopyCount = RateLimiter.limit( + src.outboundLimiter, dst.inboundLimiter, originalCopyCount); + + if (allowedCopyCount < originalCopyCount) { + if (ENABLE_FINE_DEBUG) { + Log.i(mLogTag, logStr("Delaying transfer of " + + (originalCopyCount - allowedCopyCount) + " bytes, original=" + + originalCopyCount + ", allowed=" + allowedCopyCount + + ", type=" + src.type)); + } + if (originalCopyCount > 0) { + mHasRateLimitedData = true; + } + if (allowedCopyCount == 0) { + return false; + } + } + + boolean hasChanges = false; + if (allowedCopyCount > 0) { + if (dst.readQueue.size() == 0 || src.writeQueue.freeSize() == 0) { + hasChanges = true; // Read queue had no data, or write queue was full. + } + src.writeQueue.readBytes(mTmpBuffer, 0, allowedCopyCount); + dst.readQueue.writeBytes(mTmpBuffer, 0, allowedCopyCount); + } + + if (!dst.isEndOfStream && src.openCount == 0 + && src.writeQueue.size() == 0 && dst.readQueue.size() == 0) { + dst.isEndOfStream = true; + hasChanges = true; + } + + return hasChanges; + } + + public void clearInboundRateLimit(FileDescriptor fd) { + setInboundRateLimit(fd, Integer.MAX_VALUE); + } + + public void clearOutboundRateLimit(FileDescriptor fd) { + setOutboundRateLimit(fd, Integer.MAX_VALUE); + } + + public synchronized void setInboundRateLimit(FileDescriptor fd, int bytesPerSecond) { + File file = getFileOrNull(fd); + if (file != null) { + file.inboundLimiter.setBytesPerSecond(bytesPerSecond); + maybeTransferData(file); + } + } + + public synchronized void setOutboundRateLimit(FileDescriptor fd, int bytesPerSecond) { + File file = getFileOrNull(fd); + if (file != null) { + file.outboundLimiter.setBytesPerSecond(bytesPerSecond); + maybeTransferData(file); + } + } + + public synchronized ParcelFileDescriptor[] socketpair() throws IOException { + int fdNumber1 = getNextFd("socketpair"); + int fdNumber2 = getNextFd("socketpair"); + + File file1 = new File(FileType.PAIR, mReadQueueSize, mWriteQueueSize); + File file2 = new File(FileType.PAIR, mReadQueueSize, mWriteQueueSize); + + return registerFilePair(fdNumber1, file1, fdNumber2, file2); + } + + @Override + public synchronized ParcelFileDescriptor[] pipe() throws IOException { + int fdNumber1 = getNextFd("pipe"); + int fdNumber2 = getNextFd("pipe"); + + File file1 = new File(FileType.PIPE, mReadQueueSize, 0); + File file2 = new File(FileType.PIPE, 0, mWriteQueueSize); + + return registerFilePair(fdNumber1, file1, fdNumber2, file2); + } + + private ParcelFileDescriptor[] registerFilePair( + int fdNumber1, File file1, int fdNumber2, File file2) { + file1.sink = file2; + file1.source = file2; + file2.sink = file1; + file2.source = file1; + + mFiles.put(fdNumber1, file1); + mFiles.put(fdNumber2, file2); + return new ParcelFileDescriptor[] { + newParcelFileDescriptor(fdNumber1), newParcelFileDescriptor(fdNumber2)}; + } + + @Override + public short getPollInMask() { + return POLLIN; + } + + @Override + public short getPollOutMask() { + return POLLOUT; + } + + @Override + public synchronized int poll(StructPollfd[] fds, int timeoutMs) throws IOException { + if (timeoutMs < 0) { + timeoutMs = (int) TimeUnit.HOURS.toMillis(1); // Make "infinite" equal to 1 hour. + } + + if (fds == null || fds.length > 1000) { + throw newIOException("poll", "Invalid fds param"); + } + for (StructPollfd pollFd : fds) { + getFile("poll", pollFd.fd); + } + + int waitCallCount = 0; + final long deadline = monotonicTimeMillis() + timeoutMs; + while (true) { + if (mHasRateLimitedData) { + mHasRateLimitedData = false; + for (File file : mFiles.values()) { + if (file.inboundLimiter.getLastRequestReduction() != 0) { + copyFileBuffers(file.source, file); + } + if (file.outboundLimiter.getLastRequestReduction() != 0) { + copyFileBuffers(file, file.sink); + } + } + } + + final int readyCount = calculateReadyCount(fds); + if (readyCount > 0) { + if (ENABLE_FINE_DEBUG) { + Log.v(mLogTag, logStr("Poll returns " + readyCount + + " after " + waitCallCount + " wait calls")); + } + return readyCount; + } + + long remainingTimeoutMs = deadline - monotonicTimeMillis(); + if (remainingTimeoutMs <= 0) { + if (ENABLE_FINE_DEBUG) { + Log.v(mLogTag, logStr("Poll timeout " + timeoutMs + + "ms after " + waitCallCount + " wait calls")); + } + return 0; + } + + if (mHasRateLimitedData) { + remainingTimeoutMs = Math.min(RateLimiter.BUCKET_DURATION_MS, remainingTimeoutMs); + } + + try { + wait(remainingTimeoutMs); + } catch (InterruptedException e) { + // Ignore and retry + } + waitCallCount++; + } + } + + private int calculateReadyCount(StructPollfd[] fds) { + int fdCount = 0; + for (StructPollfd pollFd : fds) { + pollFd.revents = 0; + + File file = getFileOrNull(pollFd.fd); + if (file == null) { + Log.w(mLogTag, logStr("Ignoring FD concurrently closed by a buggy app: " + + getFileDebugName(pollFd.fd))); + continue; + } + + if (ENABLE_FINE_DEBUG) { + Log.v(mLogTag, logStr("calculateReadyCount fd=" + getFileDebugName(pollFd.fd) + + ", events=" + pollFd.events + ", eof=" + file.isEndOfStream + + ", r=" + (file.readQueue != null ? file.readQueue.size() : -1) + + ", w=" + (file.writeQueue != null ? file.writeQueue.freeSize() : -1))); + } + + if ((pollFd.events & POLLIN) != 0) { + if (file.readQueue != null && file.readQueue.size() != 0) { + pollFd.revents |= POLLIN; + } + if (file.isEndOfStream) { + pollFd.revents |= POLLHUP; + } + } + + if ((pollFd.events & POLLOUT) != 0) { + if (file.type == FileType.PIPE && file.sink.openCount == 0) { + pollFd.revents |= POLLERR; + } + if (file.writeQueue != null && file.writeQueue.freeSize() != 0) { + pollFd.revents |= POLLOUT; + } + } + + if (pollFd.revents != 0) { + fdCount++; + } + } + return fdCount; + } + + private int getNextFd(String func) throws IOException { + if (mFileNumberGen > 100000) { + throw newIOException(func, "Too many files open"); + } + + return mFileNumberGen++; + } + + private static IOException newIOException(String func, String message) { + return new IOException(message + ", func=" + func); + } + + public static void checkBoundaries(String func, byte[] buffer, int pos, int len) + throws IOException { + if (((buffer.length | pos | len) < 0 || pos > buffer.length - len)) { + throw newIOException(func, "Invalid array bounds"); + } + } + + private ParcelFileDescriptor newParcelFileDescriptor(int fdNumber) { + try { + return new ParcelFileDescriptor(newFileDescriptor(fdNumber)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private FileDescriptor newFileDescriptor(int fdNumber) { + try { + return FD_CONSTRUCTOR.newInstance(Integer.valueOf(fdNumber)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public int getFileDescriptorNumber(FileDescriptor fd) { + try { + return (Integer) FD_FIELD_DESCRIPTOR.get(fd); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void setFileDescriptorNumber(FileDescriptor fd, int fdNumber) { + try { + FD_FIELD_DESCRIPTOR.set(fd, Integer.valueOf(fdNumber)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private String logStr(String message) { + return "[FakeOs " + (monotonicTimeMillis() - mStartTime) + "] " + message; + } + + private class File { + final FileType type; + final CircularByteBuffer readQueue; + final CircularByteBuffer writeQueue; + final RateLimiter inboundLimiter = new RateLimiter(FakeOsAccess.this, Integer.MAX_VALUE); + final RateLimiter outboundLimiter = new RateLimiter(FakeOsAccess.this, Integer.MAX_VALUE); + String name; + int openCount = 1; + boolean isBlocking = true; + File sink; + File source; + boolean isEndOfStream; + + File(FileType type, int readQueueSize, int writeQueueSize) { + this.type = type; + readQueue = (readQueueSize > 0 ? new CircularByteBuffer(readQueueSize) : null); + writeQueue = (writeQueueSize > 0 ? new CircularByteBuffer(writeQueueSize) : null); + } + + void decreaseRefCount() { + if (openCount <= 0) { + throw new IllegalStateException(); + } + openCount--; + } + + void checkNonBlocking(String func) throws IOException { + if (isBlocking) { + throw newIOException(func, "File in blocking mode"); + } + } + } + + static { + try { + FD_CONSTRUCTOR = FileDescriptor.class.getDeclaredConstructor(int.class); + FD_CONSTRUCTOR.setAccessible(true); + + Field descriptorIntField; + try { + descriptorIntField = FileDescriptor.class.getDeclaredField("descriptor"); + } catch (NoSuchFieldException e) { + descriptorIntField = FileDescriptor.class.getDeclaredField("fd"); + } + FD_FIELD_DESCRIPTOR = descriptorIntField; + FD_FIELD_DESCRIPTOR.setAccessible(true); + + PFD_FIELD_DESCRIPTOR = ParcelFileDescriptor.class.getDeclaredField("mFd"); + PFD_FIELD_DESCRIPTOR.setAccessible(true); + + PFD_FIELD_GUARD = ParcelFileDescriptor.class.getDeclaredField("mGuard"); + PFD_FIELD_GUARD.setAccessible(true); + + CLOSE_GUARD_METHOD_CLOSE = Class.forName("dalvik.system.CloseGuard") + .getDeclaredMethod("close"); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/staticlibs/testutils/devicetests/com/android/testutils/async/RateLimiter.java b/staticlibs/testutils/devicetests/com/android/testutils/async/RateLimiter.java new file mode 100644 index 0000000000..137873dbab --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/async/RateLimiter.java @@ -0,0 +1,131 @@ +/* + * 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 com.android.testutils; + +import com.android.net.module.util.async.OsAccess; + +import java.util.Arrays; + +/** + * Limits the number of bytes processed to the given maximum of bytes per second. + * + * The limiter tracks the total for the past second, along with sums for each 10ms + * in the past second, allowing the total to be adjusted as the time passes. + */ +public final class RateLimiter { + private static final int PERIOD_DURATION_MS = 1000; + private static final int BUCKET_COUNT = 100; + + public static final int BUCKET_DURATION_MS = PERIOD_DURATION_MS / BUCKET_COUNT; + + private final OsAccess mOsAccess; + private final int[] mStatBuckets = new int[BUCKET_COUNT]; + private int mMaxPerPeriodBytes; + private int mMaxPerBucketBytes; + private int mRecordedPeriodBytes; + private long mLastLimitTimestamp; + private int mLastRequestReduction; + + public RateLimiter(OsAccess osAccess, int bytesPerSecond) { + mOsAccess = osAccess; + setBytesPerSecond(bytesPerSecond); + clear(); + } + + public int getBytesPerSecond() { + return mMaxPerPeriodBytes; + } + + public void setBytesPerSecond(int bytesPerSecond) { + mMaxPerPeriodBytes = bytesPerSecond; + mMaxPerBucketBytes = Math.max(1, (mMaxPerPeriodBytes / BUCKET_COUNT) * 2); + } + + public void clear() { + mLastLimitTimestamp = mOsAccess.monotonicTimeMillis(); + mRecordedPeriodBytes = 0; + Arrays.fill(mStatBuckets, 0); + } + + public static int limit(RateLimiter limiter1, RateLimiter limiter2, int requestedBytes) { + final long now = limiter1.mOsAccess.monotonicTimeMillis(); + final int allowedCount = Math.min(limiter1.calculateLimit(now, requestedBytes), + limiter2.calculateLimit(now, requestedBytes)); + limiter1.recordBytes(now, requestedBytes, allowedCount); + limiter2.recordBytes(now, requestedBytes, allowedCount); + return allowedCount; + } + + public int limit(int requestedBytes) { + final long now = mOsAccess.monotonicTimeMillis(); + final int allowedCount = calculateLimit(now, requestedBytes); + recordBytes(now, requestedBytes, allowedCount); + return allowedCount; + } + + public int getLastRequestReduction() { + return mLastRequestReduction; + } + + public boolean acceptAllOrNone(int requestedBytes) { + final long now = mOsAccess.monotonicTimeMillis(); + final int allowedCount = calculateLimit(now, requestedBytes); + if (allowedCount < requestedBytes) { + return false; + } + recordBytes(now, requestedBytes, allowedCount); + return true; + } + + private int calculateLimit(long now, int requestedBytes) { + // First remove all stale bucket data and adjust the total. + final long currentBucketAbsIdx = now / BUCKET_DURATION_MS; + final long staleCutoffIdx = currentBucketAbsIdx - BUCKET_COUNT; + for (long i = mLastLimitTimestamp / BUCKET_DURATION_MS; i < staleCutoffIdx; i++) { + final int idx = (int) (i % BUCKET_COUNT); + mRecordedPeriodBytes -= mStatBuckets[idx]; + mStatBuckets[idx] = 0; + } + + final int bucketIdx = (int) (currentBucketAbsIdx % BUCKET_COUNT); + final int maxAllowed = Math.min(mMaxPerPeriodBytes - mRecordedPeriodBytes, + Math.min(mMaxPerBucketBytes - mStatBuckets[bucketIdx], requestedBytes)); + return Math.max(0, maxAllowed); + } + + private void recordBytes(long now, int requestedBytes, int actualBytes) { + mStatBuckets[(int) ((now / BUCKET_DURATION_MS) % BUCKET_COUNT)] += actualBytes; + mRecordedPeriodBytes += actualBytes; + mLastRequestReduction = requestedBytes - actualBytes; + mLastLimitTimestamp = now; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("{max="); + sb.append(mMaxPerPeriodBytes); + sb.append(",max_bucket="); + sb.append(mMaxPerBucketBytes); + sb.append(",total="); + sb.append(mRecordedPeriodBytes); + sb.append(",last_red="); + sb.append(mLastRequestReduction); + sb.append('}'); + return sb.toString(); + } +} From be2ff67dae097dc735eca53ad622e861fdd610a4 Mon Sep 17 00:00:00 2001 From: Ryan Zuklie Date: Thu, 19 Jan 2023 15:24:38 -0800 Subject: [PATCH 635/777] Add macro support for ignore_on BPF maps. This is similar to https://r.android.com/2374598 for maps. Bug: 246985031 Test: build connectivity module Change-Id: Id4c9f93b69e808d461b4554bf3fa591828635dd1 --- .../native/bpf_headers/include/bpf/bpf_helpers.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index ed1ee51143..36865f33db 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -235,11 +235,12 @@ static void (*bpf_ringbuf_submit_unsafe)(const void* data, __u64 flags) = (void* /* type safe macro to declare a map and related accessor functions */ #define DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, \ - selinux, pindir, share) \ + selinux, pindir, share, min_loader, max_loader, ignore_eng, \ + ignore_user, ignore_userdebug) \ DEFINE_BPF_MAP_BASE(the_map, TYPE, sizeof(KeyType), sizeof(ValueType), \ num_entries, usr, grp, md, selinux, pindir, share, \ - KVER_NONE, KVER_INF, BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, \ - false, false, false); \ + KVER_NONE, KVER_INF, min_loader, max_loader, \ + ignore_eng, ignore_user, ignore_userdebug); \ BPF_MAP_ASSERT_OK(BPF_MAP_TYPE_##TYPE, (num_entries), (md)); \ BPF_ANNOTATE_KV_PAIR(the_map, KeyType, ValueType); \ \ @@ -271,9 +272,11 @@ static void (*bpf_ringbuf_submit_unsafe)(const void* data, __u64 flags) = (void* #error "Bpf Map UID must be left at default of AID_ROOT for BpfLoader prior to v0.28" #endif -#define DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md) \ - DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, \ - DEFAULT_BPF_MAP_SELINUX_CONTEXT, DEFAULT_BPF_MAP_PIN_SUBDIR, false) +#define DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md) \ + DEFINE_BPF_MAP_EXT(the_map, TYPE, KeyType, ValueType, num_entries, usr, grp, md, \ + DEFAULT_BPF_MAP_SELINUX_CONTEXT, DEFAULT_BPF_MAP_PIN_SUBDIR, false, \ + BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, /*ignore_on_eng*/false, \ + /*ignore_on_user*/false, /*ignore_on_userdebug*/false) #define DEFINE_BPF_MAP(the_map, TYPE, KeyType, ValueType, num_entries) \ DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \ From bcdc972c8698e451786d025c334490bb2d954554 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 23 Jan 2023 18:20:16 +0900 Subject: [PATCH 636/777] Add packet filters for IPv6 UDP This is useful to test mDNS. Bug: 266151066 Test: atest NsdManagerTest (with related change) Change-Id: I790da3f3be5277f2480600cfbbaeac86c306f77d --- .../module/util/NetworkStackConstants.java | 2 + .../com/android/testutils/ArpResponder.kt | 4 + .../com/android/testutils/PacketFilter.kt | 81 +++++++++++++------ 3 files changed, 64 insertions(+), 23 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 7b3943cea7..7d4ae3053f 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -197,6 +197,8 @@ public final class NetworkStackConstants { * - https://tools.ietf.org/html/rfc768 */ public static final int UDP_HEADER_LEN = 8; + public static final int UDP_SRCPORT_OFFSET = 0; + public static final int UDP_DSTPORT_OFFSET = 2; public static final int UDP_LENGTH_OFFSET = 4; public static final int UDP_CHECKSUM_OFFSET = 6; diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ArpResponder.kt b/staticlibs/testutils/devicetests/com/android/testutils/ArpResponder.kt index 86631c3d4b..cf0490c565 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/ArpResponder.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/ArpResponder.kt @@ -17,10 +17,14 @@ package com.android.testutils import android.net.MacAddress +import com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN import java.net.Inet4Address import java.net.InetAddress import java.nio.ByteBuffer +private const val ARP_SENDER_MAC_OFFSET = ETHER_HEADER_LEN + 8 +private const val ARP_TARGET_IPADDR_OFFSET = ETHER_HEADER_LEN + 24 + private val TYPE_ARP = byteArrayOf(0x08, 0x06) // Arp reply header for IPv4 over ethernet private val ARP_REPLY_IPV4 = byteArrayOf(0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02) diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/PacketFilter.kt b/staticlibs/testutils/hostdevice/com/android/testutils/PacketFilter.kt index 7c615d0b25..1bb6d683e2 100644 --- a/staticlibs/testutils/hostdevice/com/android/testutils/PacketFilter.kt +++ b/staticlibs/testutils/hostdevice/com/android/testutils/PacketFilter.kt @@ -19,24 +19,25 @@ package com.android.testutils import java.net.Inet4Address import java.util.function.Predicate -const val ETHER_TYPE_OFFSET = 12 -const val ETHER_HEADER_LENGTH = 14 -const val IPV4_PROTOCOL_OFFSET = ETHER_HEADER_LENGTH + 9 -const val IPV4_CHECKSUM_OFFSET = ETHER_HEADER_LENGTH + 10 -const val IPV4_DST_OFFSET = ETHER_HEADER_LENGTH + 16 -const val IPV4_HEADER_LENGTH = 20 -const val IPV4_UDP_OFFSET = ETHER_HEADER_LENGTH + IPV4_HEADER_LENGTH -const val IPV4_UDP_SRCPORT_OFFSET = IPV4_UDP_OFFSET -const val IPV4_UDP_DSTPORT_OFFSET = IPV4_UDP_OFFSET + 2 -const val UDP_HEADER_LENGTH = 8 -const val BOOTP_OFFSET = IPV4_UDP_OFFSET + UDP_HEADER_LENGTH -const val BOOTP_TID_OFFSET = BOOTP_OFFSET + 4 -const val BOOTP_CLIENT_MAC_OFFSET = BOOTP_OFFSET + 28 -const val DHCP_OPTIONS_OFFSET = BOOTP_OFFSET + 240 - -const val ARP_OPCODE_OFFSET = ETHER_HEADER_LENGTH + 6 -const val ARP_SENDER_MAC_OFFSET = ETHER_HEADER_LENGTH + 8 -const val ARP_TARGET_IPADDR_OFFSET = ETHER_HEADER_LENGTH + 24 +// Some of the below constants are duplicated with NetworkStackConstants, but this is a hostdevice +// library usable for host-side tests, so device-side utils are not usable, and there is no +// host-side non-test library to host common constants. +private const val ETHER_TYPE_OFFSET = 12 +private const val ETHER_HEADER_LENGTH = 14 +private const val IPV4_PROTOCOL_OFFSET = ETHER_HEADER_LENGTH + 9 +private const val IPV6_PROTOCOL_OFFSET = ETHER_HEADER_LENGTH + 6 +private const val IPV4_CHECKSUM_OFFSET = ETHER_HEADER_LENGTH + 10 +private const val IPV4_DST_OFFSET = ETHER_HEADER_LENGTH + 16 +private const val IPV4_HEADER_LENGTH = 20 +private const val IPV6_HEADER_LENGTH = 40 +private const val IPV4_PAYLOAD_OFFSET = ETHER_HEADER_LENGTH + IPV4_HEADER_LENGTH +private const val IPV6_PAYLOAD_OFFSET = ETHER_HEADER_LENGTH + IPV6_HEADER_LENGTH +private const val UDP_HEADER_LENGTH = 8 +private const val BOOTP_OFFSET = IPV4_PAYLOAD_OFFSET + UDP_HEADER_LENGTH +private const val BOOTP_TID_OFFSET = BOOTP_OFFSET + 4 +private const val BOOTP_CLIENT_MAC_OFFSET = BOOTP_OFFSET + 28 +private const val DHCP_OPTIONS_OFFSET = BOOTP_OFFSET + 240 +private const val ARP_OPCODE_OFFSET = ETHER_HEADER_LENGTH + 6 /** * A [Predicate] that matches a [ByteArray] if it contains the specified [bytes] at the specified @@ -47,12 +48,48 @@ class OffsetFilter(val offset: Int, vararg val bytes: Byte) : Predicate { + override fun test(t: ByteArray): Boolean { + if (src != null && !OffsetFilter(udpOffset, + src.toInt().ushr(8).toByte(), src.toByte()).test(t)) { + return false + } + + if (dst != null && !OffsetFilter(udpOffset + 2, + dst.toInt().ushr(8).toByte(), dst.toByte()).test(t)) { + return false + } + return true + } +} + /** * A [Predicate] that matches ethernet-encapped packets that contain an UDP over IPv4 datagram. */ -class IPv4UdpFilter : Predicate { +class IPv4UdpFilter @JvmOverloads constructor( + srcPort: Short? = null, + dstPort: Short? = null +) : Predicate { private val impl = OffsetFilter(ETHER_TYPE_OFFSET, 0x08, 0x00 /* IPv4 */).and( - OffsetFilter(IPV4_PROTOCOL_OFFSET, 17 /* UDP */)) + OffsetFilter(IPV4_PROTOCOL_OFFSET, 17 /* UDP */)).and( + UdpPortFilter(IPV4_PAYLOAD_OFFSET, srcPort, dstPort)) + override fun test(t: ByteArray) = impl.test(t) +} + +/** + * A [Predicate] that matches ethernet-encapped packets that contain an UDP over IPv6 datagram. + */ +class IPv6UdpFilter @JvmOverloads constructor( + srcPort: Short? = null, + dstPort: Short? = null +) : Predicate { + private val impl = OffsetFilter(ETHER_TYPE_OFFSET, 0x86.toByte(), 0xdd.toByte() /* IPv6 */).and( + OffsetFilter(IPV6_PROTOCOL_OFFSET, 17 /* UDP */)).and( + UdpPortFilter(IPV6_PAYLOAD_OFFSET, srcPort, dstPort)) override fun test(t: ByteArray) = impl.test(t) } @@ -77,9 +114,7 @@ class ArpRequestFilter : Predicate { * A [Predicate] that matches ethernet-encapped DHCP packets sent from a DHCP client. */ class DhcpClientPacketFilter : Predicate { - private val impl = IPv4UdpFilter() - .and(OffsetFilter(IPV4_UDP_SRCPORT_OFFSET, 0x00, 0x44 /* 68 */)) - .and(OffsetFilter(IPV4_UDP_DSTPORT_OFFSET, 0x00, 0x43 /* 67 */)) + private val impl = IPv4UdpFilter(srcPort = 68, dstPort = 67) override fun test(t: ByteArray) = impl.test(t) } From 2669e240580f8811be74a59daf87fcbea455d537 Mon Sep 17 00:00:00 2001 From: Ryan Zuklie Date: Wed, 30 Nov 2022 11:12:41 -0800 Subject: [PATCH 637/777] Add BpfRingbuf class to wrap ringbuf access This implements the bare minimum to read from BPF ring buffers in userspace. The implementation uses two shared memory regions with atomic-like access. Currently, the class only guarantees that the element type has the same size (later can add btf support). The alternative would be to use libbpf or bcc, but since this is a small header-only library that seemed like it could end up being more difficulty than it was worth. Bug: 246985031 Test: atest libbpf_android_test Change-Id: I7f08e76db9cb9672ef66c629bccb3db63d3c2229 --- .../native/bpf_headers/BpfRingbufTest.cpp | 87 +++++- .../bpf_headers/include/bpf/BpfRingbuf.h | 261 ++++++++++++++++++ .../include/BpfSyscallWrappers.h | 12 + 3 files changed, 356 insertions(+), 4 deletions(-) create mode 100644 staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h diff --git a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp index 4a45a93b3e..d23afaeeeb 100644 --- a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp +++ b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp @@ -23,14 +23,20 @@ #include #include "BpfSyscallWrappers.h" +#include "bpf/BpfRingbuf.h" #include "bpf/BpfUtils.h" +#define TEST_RINGBUF_MAGIC_NUM 12345 + namespace android { namespace bpf { using ::android::base::testing::HasError; using ::android::base::testing::HasValue; -using ::android::base::testing::WithMessage; +using ::android::base::testing::WithCode; +using ::testing::AllOf; +using ::testing::Gt; using ::testing::HasSubstr; +using ::testing::Lt; class BpfRingbufTest : public ::testing::Test { protected: @@ -40,8 +46,11 @@ class BpfRingbufTest : public ::testing::Test { void SetUp() { if (!android::bpf::isAtLeastKernelVersion(5, 8, 0)) { - GTEST_SKIP() << "BPF ring buffers not supported"; - return; + GTEST_SKIP() << "BPF ring buffers not supported below 5.8"; + } + + if (sizeof(unsigned long) != 8) { + GTEST_SKIP() << "BPF ring buffers not supported on 32 bit arch"; } errno = 0; @@ -51,12 +60,82 @@ class BpfRingbufTest : public ::testing::Test { << mProgPath << " was either not found or inaccessible."; } + void RunProgram() { + char fake_skb[128] = {}; + EXPECT_EQ(runProgram(mProgram, fake_skb, sizeof(fake_skb)), 0); + } + + void RunTestN(int n) { + int run_count = 0; + uint64_t output = 0; + auto callback = [&](const uint64_t& value) { + output = value; + run_count++; + }; + + auto result = BpfRingbuf::Create(mRingbufPath.c_str()); + ASSERT_RESULT_OK(result); + + for (int i = 0; i < n; i++) { + RunProgram(); + } + + EXPECT_THAT(result.value()->ConsumeAll(callback), HasValue(n)); + EXPECT_EQ(output, TEST_RINGBUF_MAGIC_NUM); + EXPECT_EQ(run_count, n); + } + std::string mProgPath; std::string mRingbufPath; android::base::unique_fd mProgram; }; -TEST_F(BpfRingbufTest, CheckSetUp) {} +TEST_F(BpfRingbufTest, ConsumeSingle) { RunTestN(1); } +TEST_F(BpfRingbufTest, ConsumeMultiple) { RunTestN(3); } + +TEST_F(BpfRingbufTest, FillAndWrap) { + int run_count = 0; + auto callback = [&](const uint64_t&) { run_count++; }; + + auto result = BpfRingbuf::Create(mRingbufPath.c_str()); + ASSERT_RESULT_OK(result); + + // 4kb buffer with 16 byte payloads (8 byte data, 8 byte header) should fill + // after 255 iterations. Exceed that so that some events are dropped. + constexpr int iterations = 300; + for (int i = 0; i < iterations; i++) { + RunProgram(); + } + + // Some events were dropped, but consume all that succeeded. + EXPECT_THAT(result.value()->ConsumeAll(callback), + HasValue(AllOf(Gt(250), Lt(260)))); + EXPECT_THAT(run_count, AllOf(Gt(250), Lt(260))); + + // After consuming everything, we should be able to use the ring buffer again. + run_count = 0; + RunProgram(); + EXPECT_THAT(result.value()->ConsumeAll(callback), HasValue(1)); + EXPECT_EQ(run_count, 1); +} + +TEST_F(BpfRingbufTest, WrongTypeSize) { + // The program under test writes 8-byte uint64_t values so a ringbuffer for + // 1-byte uint8_t values will fail to read from it. Note that the map_def does + // not specify the value size, so we fail on read, not creation. + auto result = BpfRingbuf::Create(mRingbufPath.c_str()); + ASSERT_RESULT_OK(result); + + RunProgram(); + + EXPECT_THAT(result.value()->ConsumeAll([](const uint8_t&) {}), + HasError(WithCode(EMSGSIZE))); +} + +TEST_F(BpfRingbufTest, InvalidPath) { + EXPECT_THAT(BpfRingbuf::Create("/sys/fs/bpf/bad_path"), + HasError(WithCode(ENOENT))); +} } // namespace bpf } // namespace android diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h new file mode 100644 index 0000000000..cac1e43076 --- /dev/null +++ b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h @@ -0,0 +1,261 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include "bpf/BpfUtils.h" + +namespace android { +namespace bpf { + +// BpfRingbufBase contains the non-templated functionality of BPF ring buffers. +class BpfRingbufBase { + public: + ~BpfRingbufBase() { + if (mConsumerPos) munmap(mConsumerPos, mConsumerSize); + if (mProducerPos) munmap(mProducerPos, mProducerSize); + mConsumerPos = nullptr; + mProducerPos = nullptr; + } + + protected: + // Non-initializing constructor, used by Create. + BpfRingbufBase(size_t value_size) : mValueSize(value_size) {} + + // Full construction that aborts on error (use Create/Init to handle errors). + BpfRingbufBase(const char* path, size_t value_size) : mValueSize(value_size) { + if (auto status = Init(path); !status.ok()) { + ALOGE("BpfRingbuf init failed: %s", status.error().message().c_str()); + abort(); + } + } + + // Delete copy constructor (class owns raw pointers). + BpfRingbufBase(const BpfRingbufBase&) = delete; + + // Initialize the base ringbuffer components. Must be called exactly once. + base::Result Init(const char* path); + + // Consumes all messages from the ring buffer, passing them to the callback. + base::Result ConsumeAll( + const std::function& callback); + + // Replicates c-style void* "byte-wise" pointer addition. + template + static Ptr pointerAddBytes(void* base, ssize_t offset_bytes) { + return reinterpret_cast(reinterpret_cast(base) + offset_bytes); + } + + // Rounds len by clearing bitmask, adding header, and aligning to 8 bytes. + static uint32_t roundLength(uint32_t len) { + len &= ~(BPF_RINGBUF_BUSY_BIT | BPF_RINGBUF_DISCARD_BIT); + len += BPF_RINGBUF_HDR_SZ; + return (len + 7) & ~7; + } + + const size_t mValueSize; + + size_t mConsumerSize; + size_t mProducerSize; + unsigned long mPosMask; + android::base::unique_fd mRingFd; + + void* mDataPos = nullptr; + unsigned long* mConsumerPos = nullptr; + unsigned long* mProducerPos = nullptr; +}; + +// This is a class wrapper for eBPF ring buffers. An eBPF ring buffer is a +// special type of eBPF map used for sending messages from eBPF to userspace. +// The implementation relies on fast shared memory and atomics for the producer +// and consumer management. Ring buffers are a faster alternative to eBPF perf +// buffers. +// +// This class is thread compatible, but not thread safe. +// +// Note: A kernel eBPF ring buffer may be accessed by both kernel and userspace +// processes at the same time. However, the userspace consumers of a given ring +// buffer all share a single read pointer. There is no guarantee which readers +// will read which messages. +template +class BpfRingbuf : public BpfRingbufBase { + public: + using MessageCallback = std::function; + + // Creates a ringbuffer wrapper from a pinned path. This initialization will + // abort on error. To handle errors, initialize with Create instead. + BpfRingbuf(const char* path) : BpfRingbufBase(path, sizeof(Value)) {} + + // Creates a ringbuffer wrapper from a pinned path. There are no guarantees + // that the ringbuf outputs messaged of type `Value`, only that they are the + // same size. Size is only checked in ConsumeAll. + static base::Result>> Create( + const char* path); + + // Consumes all messages from the ring buffer, passing them to the callback. + // Returns the number of messages consumed or a non-ok result on error. If the + // ring buffer has no pending messages an OK result with count 0 is returned. + base::Result ConsumeAll(const MessageCallback& callback); + + private: + // Empty ctor for use by Create. + BpfRingbuf() : BpfRingbufBase(sizeof(Value)) {} +}; + +#define ACCESS_ONCE(x) (*(volatile typeof(x)*)&(x)) + +#if defined(__i386__) || defined(__x86_64__) +#define smp_sync() asm volatile("" ::: "memory") +#elif defined(__aarch64__) +#define smp_sync() asm volatile("dmb ish" ::: "memory") +#else +#define smp_sync() __sync_synchronize() +#endif + +#define smp_store_release(p, v) \ + do { \ + smp_sync(); \ + ACCESS_ONCE(*(p)) = (v); \ + } while (0) + +#define smp_load_acquire(p) \ + ({ \ + auto ___p = ACCESS_ONCE(*(p)); \ + smp_sync(); \ + ___p; \ + }) + +inline base::Result BpfRingbufBase::Init(const char* path) { + if (sizeof(unsigned long) != 8) { + return android::base::Error() + << "BpfRingbuf does not support 32 bit architectures"; + } + mRingFd.reset(mapRetrieveRW(path)); + if (!mRingFd.ok()) { + return android::base::ErrnoError() + << "failed to retrieve ringbuffer at " << path; + } + + int map_type = android::bpf::bpfGetFdMapType(mRingFd); + if (map_type != BPF_MAP_TYPE_RINGBUF) { + errno = EINVAL; + return android::base::ErrnoError() + << "bpf map has wrong type: want BPF_MAP_TYPE_RINGBUF (" + << BPF_MAP_TYPE_RINGBUF << ") got " << map_type; + } + + int max_entries = android::bpf::bpfGetFdMaxEntries(mRingFd); + if (max_entries < 0) { + return android::base::ErrnoError() + << "failed to read max_entries from ringbuf"; + } + if (max_entries == 0) { + errno = EINVAL; + return android::base::ErrnoError() << "max_entries must be non-zero"; + } + + mPosMask = max_entries - 1; + mConsumerSize = getpagesize(); + mProducerSize = getpagesize() + 2 * max_entries; + + { + void* ptr = mmap(NULL, mConsumerSize, PROT_READ | PROT_WRITE, MAP_SHARED, + mRingFd, 0); + if (ptr == MAP_FAILED) { + return android::base::ErrnoError() + << "failed to mmap ringbuf consumer pages"; + } + mConsumerPos = reinterpret_cast(ptr); + } + + { + void* ptr = mmap(NULL, mProducerSize, PROT_READ, MAP_SHARED, mRingFd, + mConsumerSize); + if (ptr == MAP_FAILED) { + return android::base::ErrnoError() + << "failed to mmap ringbuf producer page"; + } + mProducerPos = reinterpret_cast(ptr); + } + + mDataPos = pointerAddBytes(mProducerPos, getpagesize()); + return {}; +} + +inline base::Result BpfRingbufBase::ConsumeAll( + const std::function& callback) { + int64_t count = 0; + unsigned long cons_pos = smp_load_acquire(mConsumerPos); + unsigned long prod_pos = smp_load_acquire(mProducerPos); + while (cons_pos < prod_pos) { + // Find the start of the entry for this read (wrapping is done here). + void* start_ptr = pointerAddBytes(mDataPos, cons_pos & mPosMask); + + // The entry has an 8 byte header containing the sample length. + uint32_t length = smp_load_acquire(reinterpret_cast(start_ptr)); + + // If the sample isn't committed, we're caught up with the producer. + if (length & BPF_RINGBUF_BUSY_BIT) return count; + + cons_pos += roundLength(length); + + if ((length & BPF_RINGBUF_DISCARD_BIT) == 0) { + if (length != mValueSize) { + smp_store_release(mConsumerPos, cons_pos); + errno = EMSGSIZE; + return android::base::ErrnoError() + << "BPF ring buffer message has unexpected size (want " + << mValueSize << " bytes, got " << length << " bytes)"; + } + callback(pointerAddBytes(start_ptr, BPF_RINGBUF_HDR_SZ)); + count++; + } + + smp_store_release(mConsumerPos, cons_pos); + } + + return count; +} + +template +inline base::Result>> +BpfRingbuf::Create(const char* path) { + auto rb = std::unique_ptr(new BpfRingbuf); + if (auto status = rb->Init(path); !status.ok()) return status.error(); + return rb; +} + +template +inline base::Result BpfRingbuf::ConsumeAll( + const MessageCallback& callback) { + return BpfRingbufBase::ConsumeAll([&](const void* value) { + callback(*reinterpret_cast(value)); + }); +} + +#undef ACCESS_ONCE +#undef smp_sync +#undef smp_store_release +#undef smp_load_acquire + +} // namespace bpf +} // namespace android diff --git a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h index f7d6a380c7..8502961ec8 100644 --- a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h +++ b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h @@ -150,6 +150,18 @@ inline int detachSingleProgram(bpf_attach_type type, const BPF_FD_TYPE prog_fd, }); } +// Available in 4.12 and later kernels. +inline int runProgram(const BPF_FD_TYPE prog_fd, const void* data, + const uint32_t data_size) { + return bpf(BPF_PROG_RUN, { + .test = { + .prog_fd = BPF_FD_TO_U32(prog_fd), + .data_in = ptr_to_u64(data), + .data_size_in = data_size, + }, + }); +} + // BPF_OBJ_GET_INFO_BY_FD requires 4.14+ kernel // // Note: some fields are only defined in newer kernels (ie. the map_info struct grows From 60b95c4090b270c3d15c198ac58127088689c3a1 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 27 Jan 2023 16:45:35 +0900 Subject: [PATCH 638/777] Factorize describeDifferences Fixes: 259479229 Test: new test for this in this patch Change-Id: Iecbccd10b04ada49f3485097dfcf3511c26c0925 --- .../com/android/net/module/util/BitUtils.java | 30 +++++++++++++++++++ .../android/net/module/util/BitUtilsTests.kt | 23 +++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/staticlibs/framework/com/android/net/module/util/BitUtils.java b/staticlibs/framework/com/android/net/module/util/BitUtils.java index 2b32e86023..3062d8cf31 100644 --- a/staticlibs/framework/com/android/net/module/util/BitUtils.java +++ b/staticlibs/framework/com/android/net/module/util/BitUtils.java @@ -17,6 +17,7 @@ package com.android.net.module.util; import android.annotation.NonNull; +import android.annotation.Nullable; /** * @hide @@ -107,4 +108,33 @@ public class BitUtils { ++bitPos; } } + + /** + * Returns a short but human-readable string of updates between an old and a new bit fields. + * + * @param oldVal the old bit field to diff from + * @param newVal the new bit field to diff to + * @return a string fit for logging differences, or null if no differences. + * this method cannot return the empty string. + */ + @Nullable + public static String describeDifferences(final long oldVal, final long newVal, + @NonNull final NameOf nameFetcher) { + final long changed = oldVal ^ newVal; + if (0 == changed) return null; + // If the control reaches here, there are changes (additions, removals, or both) so + // the code below is guaranteed to add something to the string and can't return "". + final long removed = oldVal & changed; + final long added = newVal & changed; + final StringBuilder sb = new StringBuilder(); + if (0 != removed) { + sb.append("-"); + appendStringRepresentationOfBitMaskToStringBuilder(sb, removed, nameFetcher, "-"); + } + if (0 != added) { + sb.append("+"); + appendStringRepresentationOfBitMaskToStringBuilder(sb, added, nameFetcher, "+"); + } + return sb.toString(); + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/BitUtilsTests.kt b/staticlibs/tests/unit/src/com/android/net/module/util/BitUtilsTests.kt index 02367162a5..49940ea85c 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/BitUtilsTests.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/BitUtilsTests.kt @@ -17,11 +17,13 @@ package com.android.net.module.util import com.android.net.module.util.BitUtils.appendStringRepresentationOfBitMaskToStringBuilder +import com.android.net.module.util.BitUtils.describeDifferences import com.android.net.module.util.BitUtils.packBits import com.android.net.module.util.BitUtils.unpackBits -import org.junit.Test import kotlin.test.assertEquals +import kotlin.test.assertNull import kotlin.test.assertTrue +import org.junit.Test class BitUtilsTests { @Test @@ -58,4 +60,23 @@ class BitUtilsTests { assertEquals(expected, it.toString()) } } + + @Test + fun testDescribeDifferences() { + fun describe(a: Long, b: Long) = describeDifferences(a, b, Integer::toString) + assertNull(describe(0, 0)) + assertNull(describe(5, 5)) + assertNull(describe(Long.MAX_VALUE, Long.MAX_VALUE)) + + assertEquals("+0", describe(0, 1)) + assertEquals("-0", describe(1, 0)) + + assertEquals("+0+2", describe(0, 5)) + assertEquals("+2", describe(1, 5)) + assertEquals("-0+2", describe(1, 4)) + + fun makeField(vararg i: Int) = i.sumOf { 1L shl it } + assertEquals("-0-4-6-9+1+3+11", describe(makeField(0, 4, 6, 9), makeField(1, 3, 11))) + assertEquals("-1-5-9+6+8", describe(makeField(0, 1, 3, 4, 5, 9), makeField(0, 3, 4, 6, 8))) + } } From bdb79c510fa3e2600cceb865d1fba12b156e7b4f Mon Sep 17 00:00:00 2001 From: Yuyang Huang Date: Thu, 2 Feb 2023 13:22:12 +0900 Subject: [PATCH 639/777] Add CtsNetTestCasesMaxTargetSdk33 The annotation is used to verify behavior for apps with max target SDK 33. Bug: 267102290 Test: atest CtsNetTestCasesMaxTargetSdk33 Change-Id: I71ba4433389ba07553ea3d6d34a2bf64fdc132ad --- .../filters/CtsNetTestCasesMaxTargetSdk33.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/filters/CtsNetTestCasesMaxTargetSdk33.kt diff --git a/staticlibs/testutils/devicetests/com/android/testutils/filters/CtsNetTestCasesMaxTargetSdk33.kt b/staticlibs/testutils/devicetests/com/android/testutils/filters/CtsNetTestCasesMaxTargetSdk33.kt new file mode 100644 index 0000000000..5af890ff8b --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/filters/CtsNetTestCasesMaxTargetSdk33.kt @@ -0,0 +1,22 @@ +/* + * 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 com.android.testutils.filters + +/** + * Only run this test in the CtsNetTestCasesMaxTargetSdk33 suite. + */ +annotation class CtsNetTestCasesMaxTargetSdk33(val reason: String) From c0ba521f79360cb7d0b2a6b279447b690631fa7a Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 13 Jan 2023 21:33:43 +0900 Subject: [PATCH 640/777] Replace expectCapabilitiesThat with expectCaps Add all the necessary overloads too. Bug: 157405399 Test: ConnectivityServiceTest NetworkStaticLibTests Change-Id: Idea768934182d4e2226c273fda0189942dcbf62e --- .../testutils/TestableNetworkCallbackTest.kt | 22 ++++----- .../testutils/TestableNetworkCallback.kt | 46 ++++++++++--------- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt index eed31e0f1b..5acdb34733 100644 --- a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt +++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt @@ -179,33 +179,31 @@ class TestableNetworkCallbackTest { } @Test - fun testCapabilitiesThat() { + fun testExpectCaps() { val net = Network(101) val netCaps = NetworkCapabilities().addCapability(NOT_METERED).addTransportType(WIFI) // Check that expecting capabilitiesThat anything fails when no callback has been received. - assertFails { mCallback.expectCapabilitiesThat(net, SHORT_TIMEOUT_MS) { true } } + assertFails { mCallback.expectCaps(net, SHORT_TIMEOUT_MS) { true } } // Basic test for true and false mCallback.onCapabilitiesChanged(net, netCaps) - mCallback.expectCapabilitiesThat(net) { true } + mCallback.expectCaps(net) { true } mCallback.onCapabilitiesChanged(net, netCaps) - assertFails { mCallback.expectCapabilitiesThat(net, SHORT_TIMEOUT_MS) { false } } + assertFails { mCallback.expectCaps(net, SHORT_TIMEOUT_MS) { false } } // Try a positive and a negative case mCallback.onCapabilitiesChanged(net, netCaps) - mCallback.expectCapabilitiesThat(net) { caps -> - caps.hasCapability(NOT_METERED) && - caps.hasTransport(WIFI) && - !caps.hasTransport(CELLULAR) + mCallback.expectCaps(net) { + it.hasCapability(NOT_METERED) && it.hasTransport(WIFI) && !it.hasTransport(CELLULAR) } mCallback.onCapabilitiesChanged(net, netCaps) - assertFails { mCallback.expectCapabilitiesThat(net, SHORT_TIMEOUT_MS) { caps -> - caps.hasTransport(CELLULAR) - } } + assertFails { mCallback.expectCaps(net, SHORT_TIMEOUT_MS) { it.hasTransport(CELLULAR) } } // Try a matching callback on the wrong network mCallback.onCapabilitiesChanged(net, netCaps) - assertFails { mCallback.expectCapabilitiesThat(Network(100), SHORT_TIMEOUT_MS) { true } } + assertFails { + mCallback.expectCaps(Network(100), SHORT_TIMEOUT_MS) { true } + } } @Test diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index 68d5fa91fd..d58d5824a6 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -414,13 +414,6 @@ open class TestableNetworkCallback private constructor( crossinline predicate: (T) -> Boolean = { true } ) = history.poll(timeoutMs, from) { it is T && predicate(it) } as T? - inline fun expectCapabilitiesThat( - net: Network, - tmt: Long = defaultTimeoutMs, - valid: (NetworkCapabilities) -> Boolean - ): CapabilitiesChanged = - expect(net, tmt, "Capabilities don't match expectations") { valid(it.caps) } - inline fun expectLinkPropertiesThat( net: Network, tmt: Long = defaultTimeoutMs, @@ -472,10 +465,8 @@ open class TestableNetworkCallback private constructor( if (suspended) { expect(net, tmt) } - expectCapabilitiesThat(net, tmt) { - validated == null || validated == it.hasCapability( - NET_CAPABILITY_VALIDATED - ) + expect(net, tmt) { + validated == null || validated == it.caps.hasCapability(NET_CAPABILITY_VALIDATED) } expect(net, tmt) } @@ -514,7 +505,7 @@ open class TestableNetworkCallback private constructor( // when a network connects and satisfies a callback, and then immediately validates. fun expectAvailableThenValidatedCallbacks(net: Network, tmt: Long = defaultTimeoutMs) { expectAvailableCallbacks(net, validated = false, tmt = tmt) - expectCapabilitiesThat(net, tmt) { it.hasCapability(NET_CAPABILITY_VALIDATED) } + expectCaps(net, tmt) { it.hasCapability(NET_CAPABILITY_VALIDATED) } } fun expectAvailableThenValidatedCallbacks( @@ -524,7 +515,7 @@ open class TestableNetworkCallback private constructor( ) { expectAvailableCallbacks(net, validated = false, suspended = false, blockedStatus = blockedStatus, tmt = tmt) - expectCapabilitiesThat(net, tmt) { it.hasCapability(NET_CAPABILITY_VALIDATED) } + expectCaps(net, tmt) { it.hasCapability(NET_CAPABILITY_VALIDATED) } } // Temporary Java compat measure : have MockNetworkAgent implement this so that all existing @@ -578,29 +569,42 @@ open class TestableNetworkCallback private constructor( ) = expectLinkPropertiesThat(n.network, tmt, valid) @JvmOverloads - fun expectCapabilitiesThat( + fun expectCaps( n: HasNetwork, tmt: Long = defaultTimeoutMs, + valid: (NetworkCapabilities) -> Boolean = { true } + ) = expect(n.network, tmt) { valid(it.caps) }.caps + + @JvmOverloads + fun expectCaps( + n: Network, + tmt: Long = defaultTimeoutMs, valid: (NetworkCapabilities) -> Boolean - ) = expectCapabilitiesThat(n.network, tmt, valid) + ) = expect(n, tmt) { valid(it.caps) }.caps + + fun expectCaps( + n: HasNetwork, + valid: (NetworkCapabilities) -> Boolean + ) = expect(n.network) { valid(it.caps) }.caps + + fun expectCaps( + tmt: Long, + valid: (NetworkCapabilities) -> Boolean + ) = expect(ANY_NETWORK, tmt) { valid(it.caps) }.caps @JvmOverloads fun expectCapabilitiesWith( capability: Int, n: HasNetwork, timeoutMs: Long = defaultTimeoutMs - ): NetworkCapabilities { - return expectCapabilitiesThat(n.network, timeoutMs) { it.hasCapability(capability) }.caps - } + ) = expectCaps(n, timeoutMs) { it.hasCapability(capability) } @JvmOverloads fun expectCapabilitiesWithout( capability: Int, n: HasNetwork, timeoutMs: Long = defaultTimeoutMs - ): NetworkCapabilities { - return expectCapabilitiesThat(n.network, timeoutMs) { !it.hasCapability(capability) }.caps - } + ) = expectCaps(n, timeoutMs) { !it.hasCapability(capability) } fun expectBlockedStatusCallback(expectBlocked: Boolean, n: HasNetwork) { expectBlockedStatusCallback(expectBlocked, n.network, defaultTimeoutMs) From ab521cf49daf49d09d69f83aa650989dfdaf2091 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 13 Jan 2023 20:32:54 +0900 Subject: [PATCH 641/777] Remove expectCapabilitiesWith and without This is not clearer than using the base method. Test: ConnectivityServiceTest NetworkStaticLibTests Bug: 157405399 Change-Id: Iac9aeffb563d0a1cb6c1287b46b9bbfffc0c75ca --- .../testutils/TestableNetworkCallbackTest.kt | 20 +++++++++++++------ .../testutils/TestableNetworkCallback.kt | 14 ------------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt index 5acdb34733..d36f52a379 100644 --- a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt +++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt @@ -140,20 +140,28 @@ class TestableNetworkCallbackTest { val meteredNc = NetworkCapabilities() val unmeteredNc = NetworkCapabilities().addCapability(NOT_METERED) // Check that expecting caps (with or without) fails when no callback has been received. - assertFails { mCallback.expectCapabilitiesWith(NOT_METERED, matcher, SHORT_TIMEOUT_MS) } - assertFails { mCallback.expectCapabilitiesWithout(NOT_METERED, matcher, SHORT_TIMEOUT_MS) } + assertFails { + mCallback.expectCaps(matcher, SHORT_TIMEOUT_MS) { it.hasCapability(NOT_METERED) } + } + assertFails { + mCallback.expectCaps(matcher, SHORT_TIMEOUT_MS) { !it.hasCapability(NOT_METERED) } + } // Add NOT_METERED and check that With succeeds and Without fails. mCallback.onCapabilitiesChanged(net, unmeteredNc) - mCallback.expectCapabilitiesWith(NOT_METERED, matcher) + mCallback.expectCaps(matcher) { it.hasCapability(NOT_METERED) } mCallback.onCapabilitiesChanged(net, unmeteredNc) - assertFails { mCallback.expectCapabilitiesWithout(NOT_METERED, matcher, SHORT_TIMEOUT_MS) } + assertFails { + mCallback.expectCaps(matcher, SHORT_TIMEOUT_MS) { !it.hasCapability(NOT_METERED) } + } // Don't add NOT_METERED and check that With fails and Without succeeds. mCallback.onCapabilitiesChanged(net, meteredNc) - assertFails { mCallback.expectCapabilitiesWith(NOT_METERED, matcher, SHORT_TIMEOUT_MS) } + assertFails { + mCallback.expectCaps(matcher, SHORT_TIMEOUT_MS) { it.hasCapability(NOT_METERED) } + } mCallback.onCapabilitiesChanged(net, meteredNc) - mCallback.expectCapabilitiesWithout(NOT_METERED, matcher) + mCallback.expectCaps(matcher) { !it.hasCapability(NOT_METERED) } } @Test diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index d58d5824a6..533ec224c8 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -592,20 +592,6 @@ open class TestableNetworkCallback private constructor( valid: (NetworkCapabilities) -> Boolean ) = expect(ANY_NETWORK, tmt) { valid(it.caps) }.caps - @JvmOverloads - fun expectCapabilitiesWith( - capability: Int, - n: HasNetwork, - timeoutMs: Long = defaultTimeoutMs - ) = expectCaps(n, timeoutMs) { it.hasCapability(capability) } - - @JvmOverloads - fun expectCapabilitiesWithout( - capability: Int, - n: HasNetwork, - timeoutMs: Long = defaultTimeoutMs - ) = expectCaps(n, timeoutMs) { !it.hasCapability(capability) } - fun expectBlockedStatusCallback(expectBlocked: Boolean, n: HasNetwork) { expectBlockedStatusCallback(expectBlocked, n.network, defaultTimeoutMs) } From ab47793183a24fdb9ddd39a53ac9117191aff551 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 13 Jan 2023 21:55:19 +0900 Subject: [PATCH 642/777] Rename BlockedStatusInt.blocked to .reason It's a reason, so it's a lot clearer this way Bug: 157405399 Test: ConnectivityServiceTest NetworkStaticLibTests Change-Id: Id71d710a33b4df3c211e40141adb2aa0a535f458 --- .../com/android/testutils/TestableNetworkCallback.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index 4f0f1db382..71f40ec696 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -83,7 +83,7 @@ open class RecorderCallback private constructor( ) : CallbackEntry() data class BlockedStatusInt( override val network: Network, - val blocked: Int + val reason: Int ) : CallbackEntry() // Convenience constants for expecting a type companion object { @@ -448,11 +448,11 @@ open class TestableNetworkCallback private constructor( net: Network, suspended: Boolean, validated: Boolean, - blockedStatus: Int, + blockedReason: Int, tmt: Long ) { expectAvailableCallbacksCommon(net, suspended, validated, tmt) - expect(net) { it.blocked == blockedStatus } + expect(net) { it.reason == blockedReason } } private fun expectAvailableCallbacksCommon( @@ -500,11 +500,11 @@ open class TestableNetworkCallback private constructor( fun expectAvailableThenValidatedCallbacks( net: Network, - blockedStatus: Int, + blockedReason: Int, tmt: Long = defaultTimeoutMs ) { expectAvailableCallbacks(net, validated = false, suspended = false, - blockedStatus = blockedStatus, tmt = tmt) + blockedReason = blockedReason, tmt = tmt) expectCaps(net, tmt) { it.hasCapability(NET_CAPABILITY_VALIDATED) } } From 12038d2e287c58a7b38603d823dacd3deeadeca1 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 13 Jan 2023 21:47:40 +0900 Subject: [PATCH 643/777] Remove expectBlockedStatusCallback expect() does a better job. Bug: 157405399 Test: ConnectivityServiceTest NetworkStaticLibTests Change-Id: I2bc4dc0f175b8d46784dbdb3a4724dea41200dc7 --- .../testutils/TestableNetworkCallback.kt | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index 533ec224c8..4f0f1db382 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -441,7 +441,7 @@ open class TestableNetworkCallback private constructor( tmt: Long = defaultTimeoutMs ) { expectAvailableCallbacksCommon(net, suspended, validated, tmt) - expectBlockedStatusCallback(blocked, net, tmt) + expect(net, tmt) { it.blocked == blocked } } fun expectAvailableCallbacks( @@ -452,7 +452,7 @@ open class TestableNetworkCallback private constructor( tmt: Long ) { expectAvailableCallbacksCommon(net, suspended, validated, tmt) - expectBlockedStatusCallback(blockedStatus, net) + expect(net) { it.blocked == blockedStatus } } private fun expectAvailableCallbacksCommon( @@ -479,16 +479,6 @@ open class TestableNetworkCallback private constructor( tmt: Long = defaultTimeoutMs ) = expectAvailableCallbacks(net, suspended = true, validated = validated, tmt = tmt) - fun expectBlockedStatusCallback(blocked: Boolean, net: Network, tmt: Long = defaultTimeoutMs) = - expect(net, tmt, "Unexpected blocked status") { - it.blocked == blocked - } - - fun expectBlockedStatusCallback(blocked: Int, net: Network, tmt: Long = defaultTimeoutMs) = - expect(net, tmt, "Unexpected blocked status") { - it.blocked == blocked - } - // Expects the available callbacks (where the onCapabilitiesChanged must contain the // VALIDATED capability), plus another onCapabilitiesChanged which is identical to the // one we just sent. @@ -591,8 +581,4 @@ open class TestableNetworkCallback private constructor( tmt: Long, valid: (NetworkCapabilities) -> Boolean ) = expect(ANY_NETWORK, tmt) { valid(it.caps) }.caps - - fun expectBlockedStatusCallback(expectBlocked: Boolean, n: HasNetwork) { - expectBlockedStatusCallback(expectBlocked, n.network, defaultTimeoutMs) - } } From 36e8ff3f87decc5e4121a17983cc6784c8abcd2a Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 13 Jan 2023 22:08:02 +0900 Subject: [PATCH 644/777] Remove expectLinkPropertiesThat expect() is simply better Bug: 157405399 Test: ConnectivityServiceTest NetworkStaticLibTests Change-Id: If8da940e378722f4cde2a4e7ea3eaef3b1380f18 --- .../testutils/TestableNetworkCallbackTest.kt | 25 ++++++++++--------- .../testutils/TestableNetworkCallback.kt | 14 ----------- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt index d36f52a379..ec7cdbdfee 100644 --- a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt +++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt @@ -34,6 +34,7 @@ import com.android.testutils.RecorderCallback.CallbackEntry.Companion.NETWORK_CA import com.android.testutils.RecorderCallback.CallbackEntry.Companion.RESUMED import com.android.testutils.RecorderCallback.CallbackEntry.Companion.SUSPENDED import com.android.testutils.RecorderCallback.CallbackEntry.Companion.UNAVAILABLE +import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged import kotlin.reflect.KClass import kotlin.test.assertEquals import kotlin.test.assertFails @@ -215,7 +216,7 @@ class TestableNetworkCallbackTest { } @Test - fun testLinkPropertiesThat() { + fun testLinkPropertiesCallbacks() { val net = Network(112) val linkAddress = LinkAddress("fe80::ace:d00d/64") val mtu = 1984 @@ -226,30 +227,30 @@ class TestableNetworkCallbackTest { } // Check that expecting linkPropsThat anything fails when no callback has been received. - assertFails { mCallback.expectLinkPropertiesThat(net, SHORT_TIMEOUT_MS) { true } } + assertFails { mCallback.expect(net, SHORT_TIMEOUT_MS) { true } } // Basic test for true and false mCallback.onLinkPropertiesChanged(net, linkProps) - mCallback.expectLinkPropertiesThat(net) { true } + mCallback.expect(net) { true } mCallback.onLinkPropertiesChanged(net, linkProps) - assertFails { mCallback.expectLinkPropertiesThat(net, SHORT_TIMEOUT_MS) { false } } + assertFails { mCallback.expect(net, SHORT_TIMEOUT_MS) { false } } // Try a positive and negative case mCallback.onLinkPropertiesChanged(net, linkProps) - mCallback.expectLinkPropertiesThat(net) { lp -> - lp.interfaceName == TEST_INTERFACE_NAME && - lp.linkAddresses.contains(linkAddress) && - lp.mtu == mtu + mCallback.expect(net) { + it.lp.interfaceName == TEST_INTERFACE_NAME && + it.lp.linkAddresses.contains(linkAddress) && + it.lp.mtu == mtu } mCallback.onLinkPropertiesChanged(net, linkProps) - assertFails { mCallback.expectLinkPropertiesThat(net, SHORT_TIMEOUT_MS) { lp -> - lp.interfaceName != TEST_INTERFACE_NAME + assertFails { mCallback.expect(net, SHORT_TIMEOUT_MS) { + it.lp.interfaceName != TEST_INTERFACE_NAME } } // Try a matching callback on the wrong network mCallback.onLinkPropertiesChanged(net, linkProps) - assertFails { mCallback.expectLinkPropertiesThat(Network(114), SHORT_TIMEOUT_MS) { lp -> - lp.interfaceName == TEST_INTERFACE_NAME + assertFails { mCallback.expect(Network(114), SHORT_TIMEOUT_MS) { + it.lp.interfaceName == TEST_INTERFACE_NAME } } } diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index 71f40ec696..485799c194 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -414,13 +414,6 @@ open class TestableNetworkCallback private constructor( crossinline predicate: (T) -> Boolean = { true } ) = history.poll(timeoutMs, from) { it is T && predicate(it) } as T? - inline fun expectLinkPropertiesThat( - net: Network, - tmt: Long = defaultTimeoutMs, - valid: (LinkProperties) -> Boolean - ): LinkPropertiesChanged = - expect(net, tmt, "LinkProperties don't match expectations") { valid(it.lp) } - // Expects onAvailable and the callbacks that follow it. These are: // - onSuspended, iff the network was suspended when the callbacks fire. // - onCapabilitiesChanged. @@ -551,13 +544,6 @@ open class TestableNetworkCallback private constructor( expectAvailableThenValidatedCallbacks(n.network, defaultTimeoutMs) } - @JvmOverloads - fun expectLinkPropertiesThat( - n: HasNetwork, - tmt: Long = defaultTimeoutMs, - valid: (LinkProperties) -> Boolean - ) = expectLinkPropertiesThat(n.network, tmt, valid) - @JvmOverloads fun expectCaps( n: HasNetwork, From 188387ebc64cdeeb4dda0d57bd7fe8243ef227f3 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Tue, 14 Feb 2023 12:10:18 +0900 Subject: [PATCH 645/777] Add DHCPv6 IA_PD and IA_PREFIX option constants. Bug: 260934173 Test: m Change-Id: I2f6692f4915c937787f023d40924f17f61d4a44e --- .../com/android/net/module/util/NetworkStackConstants.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 7b3943cea7..1d88d6ef86 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -214,11 +214,14 @@ public final class NetworkStackConstants { * * See also: * - https://datatracker.ietf.org/doc/html/rfc8415 + * - https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml */ public static final int DHCP6_CLIENT_PORT = 546; public static final int DHCP6_SERVER_PORT = 547; public static final Inet6Address ALL_DHCP_RELAY_AGENTS_AND_SERVERS = (Inet6Address) InetAddresses.parseNumericAddress("ff02::1:2"); + public static final int DHCP6_OPTION_IA_PD = 25; + public static final int DHCP6_OPTION_IAPREFIX = 26; /** * IEEE802.11 standard constants. From b9ecc44a05732aaa94e13c16553b00f445fa035a Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 15 Dec 2022 13:17:45 +0900 Subject: [PATCH 646/777] Add DHCPv6 IA_PD option structure. Bug: 260934173 Test: m Change-Id: I890f9c651dc9089d463783725731903bd3969e4e --- .../net/module/util/structs/IaPdOption.java | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/structs/IaPdOption.java diff --git a/staticlibs/device/com/android/net/module/util/structs/IaPdOption.java b/staticlibs/device/com/android/net/module/util/structs/IaPdOption.java new file mode 100644 index 0000000000..5a09c40b8f --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/IaPdOption.java @@ -0,0 +1,81 @@ +/* + * 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 com.android.net.module.util.structs; + +import static com.android.net.module.util.NetworkStackConstants.DHCP6_OPTION_IA_PD; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * DHCPv6 IA_PD option. + * https://tools.ietf.org/html/rfc8415. This does not contain any option. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_IA_PD | option-len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | IAID (4 octets) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | T1 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | T2 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * . . + * . IA_PD-options . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ +public class IaPdOption extends Struct { + public static final int LENGTH = 12; // option length excluding IA_PD options + + @Field(order = 0, type = Type.S16) + public short code; + @Field(order = 1, type = Type.S16) + public short length; + @Field(order = 2, type = Type.U32) + public long id; + @Field(order = 3, type = Type.U32) + public long t1; + @Field(order = 4, type = Type.U32) + public long t2; + + IaPdOption(final short code, final short length, final long id, final long t1, + final long t2) { + this.code = code; + this.length = length; + this.id = id; + this.t1 = t1; + this.t2 = t2; + } + + /** + * Build an IA_PD option from the required specific parameters. + */ + public static ByteBuffer build(final short length, final long id, final long t1, + final long t2) { + final IaPdOption option = new IaPdOption((short) DHCP6_OPTION_IA_PD, + length /* 12 + IA_PD options length */, id, t1, t2); + return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN)); + } +} From fa4c0c5c3e6d294bcbfdf03ab08883c6b2954a2b Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 15 Dec 2022 13:20:10 +0900 Subject: [PATCH 647/777] Add DHCPv6 IA Prefix Option structure. Bug: 260934173 Test: m Change-Id: Iba9be5ad6c696b6b44c39bd50f5f27ade3e33846 --- .../module/util/structs/IaPrefixOption.java | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java diff --git a/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java b/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java new file mode 100644 index 0000000000..1ac21ffbaf --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java @@ -0,0 +1,89 @@ +/* + * 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 com.android.net.module.util.structs; + +import static com.android.net.module.util.NetworkStackConstants.DHCP6_OPTION_IAPREFIX; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * DHCPv6 IA Prefix Option. + * https://tools.ietf.org/html/rfc8415. This does not contain any option. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_IAPREFIX | option-len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | preferred-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | valid-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | prefix-length | | + * +-+-+-+-+-+-+-+-+ IPv6-prefix | + * | (16 octets) | + * | | + * | | + * | | + * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | . + * +-+-+-+-+-+-+-+-+ . + * . IAprefix-options . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class IaPrefixOption extends Struct { + public static final int LENGTH = 25; // option length excluding IAprefix-options + + @Field(order = 0, type = Type.S16) + public short code; + @Field(order = 1, type = Type.S16) + public short length; + @Field(order = 2, type = Type.U32) + public long preferred; + @Field(order = 3, type = Type.U32) + public long valid; + @Field(order = 4, type = Type.U8) + public short prefixLen; + @Field(order = 5, type = Type.ByteArray, arraysize = 16) + public byte[] prefix; + + IaPrefixOption(final short code, final short length, final long preferred, + final long valid, final short prefixLen, final byte[] prefix) { + this.code = code; + this.length = length; + this.preferred = preferred; + this.valid = valid; + this.prefixLen = prefixLen; + this.prefix = prefix.clone(); + } + + /** + * Build an IA_PD prefix option with given specific parameters. + */ + public static ByteBuffer build(final short length, final long preferred, final long valid, + final short prefixLen, final byte[] prefix) { + final IaPrefixOption option = new IaPrefixOption((byte) DHCP6_OPTION_IAPREFIX, + length /* 25 + IAPrefix options length */, preferred, valid, prefixLen, prefix); + return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN)); + } +} From 5b4050448d2db9124164a644857da771c6f1b84f Mon Sep 17 00:00:00 2001 From: Suprabh Shukla Date: Mon, 13 Feb 2023 22:27:48 -0800 Subject: [PATCH 648/777] Add an empty implementation of INetdEventListener Adding a class that has maintains no-op implementation for all methods in INetdEventListener to allow extending in a compatible way across projects Test: Builds, boots Bug: 265742148 Change-Id: I46327d78a3685848e06f7a369e238d2952410296 --- .../module/util/BaseNetdEventListener.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 staticlibs/client-libs/netd/com/android/net/module/util/BaseNetdEventListener.java diff --git a/staticlibs/client-libs/netd/com/android/net/module/util/BaseNetdEventListener.java b/staticlibs/client-libs/netd/com/android/net/module/util/BaseNetdEventListener.java new file mode 100644 index 0000000000..4180732f31 --- /dev/null +++ b/staticlibs/client-libs/netd/com/android/net/module/util/BaseNetdEventListener.java @@ -0,0 +1,61 @@ +/* + * 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 com.android.net.module.util; + +import android.net.metrics.INetdEventListener; + +/** + * Base {@link INetdEventListener} that provides no-op implementations which can + * be overridden. + */ +public class BaseNetdEventListener extends INetdEventListener.Stub { + + @Override + public void onDnsEvent(int netId, int eventType, int returnCode, + int latencyMs, String hostname, String[] ipAddresses, + int ipAddressesCount, int uid) { } + + @Override + public void onPrivateDnsValidationEvent(int netId, String ipAddress, + String hostname, boolean validated) { } + + @Override + public void onConnectEvent(int netId, int error, int latencyMs, + String ipAddr, int port, int uid) { } + + @Override + public void onWakeupEvent(String prefix, int uid, int ethertype, + int ipNextHeader, byte[] dstHw, String srcIp, String dstIp, + int srcPort, int dstPort, long timestampNs) { } + + @Override + public void onTcpSocketStatsEvent(int[] networkIds, int[] sentPackets, + int[] lostPackets, int[] rttUs, int[] sentAckDiffMs) { } + + @Override + public void onNat64PrefixEvent(int netId, boolean added, + String prefixString, int prefixLength) { } + + @Override + public int getInterfaceVersion() { + return INetdEventListener.VERSION; + } + + @Override + public String getInterfaceHash() { + return INetdEventListener.HASH; + } +} From 1236b9e8092189892216b676157cf10e50ba8209 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 16 Feb 2023 02:29:42 +0000 Subject: [PATCH 649/777] Revert "Return default value when getModuleVersion throwed" This reverts commit 76a97e81f51cb28e9c2b9eaf039e4186029989a3. Reason for revert: b/269391238 Fix: 269391238 Change-Id: Ic1fbe09c341f147350e64357f9f647ec61d7e828 --- .../device/com/android/net/module/util/DeviceConfigUtils.java | 2 +- .../com/android/net/module/util/DeviceConfigUtilsTest.java | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index 1225aa7e23..f8f250d745 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -194,7 +194,7 @@ public final class DeviceConfigUtils { return isFeatureEnabled(context, packageVersion, namespace, name, defaultEnabled); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Could not find the module name", e); - return defaultEnabled; + return false; } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java index 302388db31..a8e7993ae9 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -223,13 +223,9 @@ public class DeviceConfigUtilsTest { TEST_EXPERIMENT_FLAG)); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, true /* defaultEnabled */)); doThrow(NameNotFoundException.class).when(mPm).getModuleInfo(anyString(), anyInt()); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, true /* defaultEnabled */)); } From 2695fdf6cecc97bc3c25b8249680769ae4a53fcf Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 17 Feb 2023 16:16:13 +0900 Subject: [PATCH 650/777] Bubble up exceptions in visibleOnHandlerThread Test: NetworkStaticLibTests Fixes: 269390906 Change-Id: I3c2d330dd719869562f437c1995e85abd32dbd68 --- .../tests/unit/src/com/android/testutils/HandlerUtilsTest.kt | 5 +++++ .../devicetests/com/android/testutils/HandlerUtils.kt | 3 +++ 2 files changed, 8 insertions(+) diff --git a/staticlibs/tests/unit/src/com/android/testutils/HandlerUtilsTest.kt b/staticlibs/tests/unit/src/com/android/testutils/HandlerUtilsTest.kt index 46a3588f9b..30e0dafe19 100644 --- a/staticlibs/tests/unit/src/com/android/testutils/HandlerUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/testutils/HandlerUtilsTest.kt @@ -19,6 +19,7 @@ package com.android.testutils import android.os.Handler import android.os.HandlerThread import kotlin.test.assertEquals +import kotlin.test.assertFailsWith import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 @@ -72,5 +73,9 @@ class HandlerUtilsTest { assertEquals(attempt, x) handler.post { assertEquals(attempt, x) } } + + assertFailsWith { + visibleOnHandlerThread(handler) { throw IllegalArgumentException() } + } } } diff --git a/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt b/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt index 68713490d2..aa252a56e6 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt @@ -65,11 +65,13 @@ fun waitForIdleSerialExecutor(executor: Executor, timeoutMs: Long) { */ fun visibleOnHandlerThread(handler: Handler, r: ThrowingRunnable) { val cv = ConditionVariable() + var e: Exception? = null handler.post { try { r.run() } catch (exception: Exception) { Log.e(TAG, "visibleOnHandlerThread caught exception", exception) + e = exception } cv.open() } @@ -77,4 +79,5 @@ fun visibleOnHandlerThread(handler: Handler, r: ThrowingRunnable) { // and this thread also has seen the change (since cv.open() happens-before cv.block() // returns). cv.block() + e?.let { throw it } } From aa9063c3d5fa1a73b16d8b6b0a987c2ab8b3baec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 23 Feb 2023 04:13:05 +0000 Subject: [PATCH 651/777] improve getSocketCookie() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (and a few minor cleanups while at it) Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I657c3314fb0ad2519dc4d1b0743e1be6a81a887a --- .../native/bpf_headers/include/bpf/BpfUtils.h | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index e2cb67681c..206acba921 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -33,17 +33,26 @@ namespace android { namespace bpf { +// See kernel's net/core/sock_diag.c __sock_gen_cookie() +// the implementation of which guarantees 0 will never be returned, +// primarily because 0 is used to mean not yet initialized, +// and socket cookies are only assigned on first fetch. constexpr const uint64_t NONEXISTENT_COOKIE = 0; static inline uint64_t getSocketCookie(int sockFd) { uint64_t sock_cookie; socklen_t cookie_len = sizeof(sock_cookie); - int res = getsockopt(sockFd, SOL_SOCKET, SO_COOKIE, &sock_cookie, &cookie_len); - if (res < 0) { - res = -errno; - ALOGE("Failed to get socket cookie: %s\n", strerror(errno)); - errno = -res; - // 0 is an invalid cookie. See sock_gen_cookie. + if (getsockopt(sockFd, SOL_SOCKET, SO_COOKIE, &sock_cookie, &cookie_len)) { + // Failure is almost certainly either EBADF or ENOTSOCK + const int err = errno; + ALOGE("Failed to get socket cookie: %s\n", strerror(err)); + errno = err; + return NONEXISTENT_COOKIE; + } + if (cookie_len != sizeof(sock_cookie)) { + // This probably cannot actually happen, but... + ALOGE("Failed to get socket cookie: len %d != 8\n", cookie_len); + errno = 523; // EBADCOOKIE: kernel internal, seems reasonable enough... return NONEXISTENT_COOKIE; } return sock_cookie; @@ -56,19 +65,19 @@ static inline int synchronizeKernelRCU() { // // Linux 4.14/4.19/5.4/5.10/5.15 (and 5.18) still have this same behaviour. // see net/key/af_key.c: pfkey_release() -> synchronize_rcu() - int pfSocket = socket(AF_KEY, SOCK_RAW | SOCK_CLOEXEC, PF_KEY_V2); + const int pfSocket = socket(AF_KEY, SOCK_RAW | SOCK_CLOEXEC, PF_KEY_V2); if (pfSocket < 0) { - int ret = -errno; - ALOGE("create PF_KEY socket failed: %s", strerror(errno)); - return ret; + const int err = errno; + ALOGE("create PF_KEY socket failed: %s", strerror(err)); + return -err; } // When closing socket, synchronize_rcu() gets called in sock_release(). if (close(pfSocket)) { - int ret = -errno; - ALOGE("failed to close the PF_KEY socket: %s", strerror(errno)); - return ret; + const int err = errno; + ALOGE("failed to close the PF_KEY socket: %s", strerror(err)); + return -err; } return 0; } @@ -79,10 +88,8 @@ static inline int setrlimitForTest() { .rlim_cur = 1073741824, // 1 GiB .rlim_max = 1073741824, // 1 GiB }; - int res = setrlimit(RLIMIT_MEMLOCK, &limit); - if (res) { - ALOGE("Failed to set the default MEMLOCK rlimit: %s", strerror(errno)); - } + const int res = setrlimit(RLIMIT_MEMLOCK, &limit); + if (res) ALOGE("Failed to set the default MEMLOCK rlimit: %s", strerror(errno)); return res; } From 17edf2c7336b8f3ea365995f78cbb9582493a8ce Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Tue, 7 Mar 2023 11:18:25 +0900 Subject: [PATCH 652/777] Mark struct member as final in IaPdOption and IaPrefixOption. Bug: 271797628 Test: m Change-Id: I6b4ae9e9b4011f705831eec48ebab813ab5911b6 --- .../android/net/module/util/structs/IaPdOption.java | 10 +++++----- .../net/module/util/structs/IaPrefixOption.java | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/structs/IaPdOption.java b/staticlibs/device/com/android/net/module/util/structs/IaPdOption.java index 5a09c40b8f..dbf79dcbaf 100644 --- a/staticlibs/device/com/android/net/module/util/structs/IaPdOption.java +++ b/staticlibs/device/com/android/net/module/util/structs/IaPdOption.java @@ -50,15 +50,15 @@ public class IaPdOption extends Struct { public static final int LENGTH = 12; // option length excluding IA_PD options @Field(order = 0, type = Type.S16) - public short code; + public final short code; @Field(order = 1, type = Type.S16) - public short length; + public final short length; @Field(order = 2, type = Type.U32) - public long id; + public final long id; @Field(order = 3, type = Type.U32) - public long t1; + public final long t1; @Field(order = 4, type = Type.U32) - public long t2; + public final long t2; IaPdOption(final short code, final short length, final long id, final long t1, final long t2) { diff --git a/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java b/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java index 1ac21ffbaf..cd974e6f08 100644 --- a/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java +++ b/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java @@ -55,17 +55,17 @@ public class IaPrefixOption extends Struct { public static final int LENGTH = 25; // option length excluding IAprefix-options @Field(order = 0, type = Type.S16) - public short code; + public final short code; @Field(order = 1, type = Type.S16) - public short length; + public final short length; @Field(order = 2, type = Type.U32) - public long preferred; + public final long preferred; @Field(order = 3, type = Type.U32) - public long valid; + public final long valid; @Field(order = 4, type = Type.U8) - public short prefixLen; + public final short prefixLen; @Field(order = 5, type = Type.ByteArray, arraysize = 16) - public byte[] prefix; + public final byte[] prefix; IaPrefixOption(final short code, final short length, final long preferred, final long valid, final short prefixLen, final byte[] prefix) { From febf4ab6fb323b3278aba174049723f84fe7b77e Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 27 Feb 2023 18:30:11 +0900 Subject: [PATCH 653/777] Remove eventuallyExpectOrNull usages from AOSP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is not useful because it has the exact same semantics as poll() : it returns the first event that matches the predicate within the timeout, or null if none. Unfortunately the method can't be removed until all uses in internal master are removed, so the actual removal will have to wait for the next patch. Test: TH Bug: 157405399 Change-Id: I471c44568e359f8686dcb21ae04c76ca8095f02f --- .../connectivitychecker/ConnectivityCheckTest.kt | 8 ++++---- .../devicetests/com/android/testutils/ConnectUtil.kt | 7 +++---- .../com/android/testutils/TestableNetworkCallback.kt | 7 ++++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitychecker/ConnectivityCheckTest.kt b/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitychecker/ConnectivityCheckTest.kt index f34ca22f62..f72938d945 100644 --- a/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitychecker/ConnectivityCheckTest.kt +++ b/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitychecker/ConnectivityCheckTest.kt @@ -29,10 +29,10 @@ import com.android.testutils.ConnectUtil import com.android.testutils.RecorderCallback import com.android.testutils.TestableNetworkCallback import com.android.testutils.tryTest -import org.junit.Test -import org.junit.runner.RunWith import kotlin.test.assertTrue import kotlin.test.fail +import org.junit.Test +import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class ConnectivityCheckTest { @@ -76,7 +76,7 @@ class ConnectivityCheckTest { .addTransportType(TRANSPORT_CELLULAR) .addCapability(NET_CAPABILITY_INTERNET).build(), cb) tryTest { - cb.eventuallyExpectOrNull() + cb.poll { it is RecorderCallback.CallbackEntry.Available } ?: fail("The device does not have mobile data available. Check that it is " + "setup with a SIM card that has a working data plan, and that the " + "APN configuration is valid.") @@ -84,4 +84,4 @@ class ConnectivityCheckTest { cm.unregisterNetworkCallback(cb) } } -} \ No newline at end of file +} diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt index 7b5ad0107c..71f7877e1a 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt @@ -32,6 +32,7 @@ import android.os.ParcelFileDescriptor import android.os.SystemClock import android.util.Log import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation +import com.android.testutils.RecorderCallback.CallbackEntry import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit import kotlin.test.assertNotNull @@ -72,9 +73,7 @@ class ConnectUtil(private val context: Context) { val config = getOrCreateWifiConfiguration() connectToWifiConfig(config) } - val cb = callback.eventuallyExpectOrNull( - timeoutMs = WIFI_CONNECT_TIMEOUT_MS) - + val cb = callback.poll(WIFI_CONNECT_TIMEOUT_MS) { it is CallbackEntry.Available } assertNotNull(cb, "Could not connect to a wifi access point within " + "$WIFI_CONNECT_TIMEOUT_MS ms. Check that the test device has a wifi network " + "configured, and that the test access point is functioning properly.") @@ -201,4 +200,4 @@ class ConnectUtil(private val context: Context) { } } } -} \ No newline at end of file +} diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index 485799c194..e7d86e00ee 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -220,7 +220,8 @@ open class TestableNetworkCallback private constructor( * Long.MAX_VALUE. */ @JvmOverloads - fun poll(timeoutMs: Long = defaultTimeoutMs): CallbackEntry? = history.poll(timeoutMs) + fun poll(timeoutMs: Long = defaultTimeoutMs, predicate: (CallbackEntry) -> Boolean = { true }) = + history.poll(timeoutMs, predicate) /** * Get the next callback or throw if timeout. @@ -385,7 +386,7 @@ open class TestableNetworkCallback private constructor( timeoutMs: Long = defaultTimeoutMs, from: Int = mark, crossinline predicate: (T) -> Boolean = { true } - ): T = eventuallyExpectOrNull(timeoutMs, from, predicate).also { + ): T = history.poll(timeoutMs, from) { it is T && predicate(it) }.also { assertNotNull(it, "Callback ${T::class} not received within ${timeoutMs}ms") } as T @@ -407,7 +408,7 @@ open class TestableNetworkCallback private constructor( assertNotNull(it, "Callback ${type.java} not received within ${timeoutMs}ms") } as T - // TODO (b/157405399) straighten and unify the method names + // TODO (b/157405399) remove this method when there are no longer any uses of it. inline fun eventuallyExpectOrNull( timeoutMs: Long = defaultTimeoutMs, from: Int = mark, From 0784d5dbd1b4c3cc26473125306a3b88b15e6fab Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 7 Mar 2023 21:46:50 +0900 Subject: [PATCH 654/777] Remove eventuallyExpectOrNull This is no longer used and is advantageously replaced by a call to poll(), which has the same semantics. Test: TH Bug: 157405399 Change-Id: I3182fd3e3ac749e11a8f962ef1acfdca5d031b05 --- .../com/android/testutils/TestableNetworkCallback.kt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index e7d86e00ee..a2cdf440e9 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -408,13 +408,6 @@ open class TestableNetworkCallback private constructor( assertNotNull(it, "Callback ${type.java} not received within ${timeoutMs}ms") } as T - // TODO (b/157405399) remove this method when there are no longer any uses of it. - inline fun eventuallyExpectOrNull( - timeoutMs: Long = defaultTimeoutMs, - from: Int = mark, - crossinline predicate: (T) -> Boolean = { true } - ) = history.poll(timeoutMs, from) { it is T && predicate(it) } as T? - // Expects onAvailable and the callbacks that follow it. These are: // - onSuspended, iff the network was suspended when the callbacks fire. // - onCapabilitiesChanged. From 2725af813a4b1f80a15b3741d91813b9e2ef0a11 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 27 Feb 2023 18:49:07 +0900 Subject: [PATCH 655/777] Add javadoc descriptions for family of methods Test: comment-only change Bug: 157405399 Change-Id: I58ccb8b05a8ffb82d4575b727bb48dfb21b191fd --- .../android/testutils/TestableNetworkCallback.kt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index a2cdf440e9..cb3be45bc3 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -367,6 +367,12 @@ open class TestableNetworkCallback private constructor( test: (T) -> Boolean = { true } ) = expect(network.network, timeoutMs, errorMsg, test) + /***** + * assertNoCallback family of methods. + * These methods make sure that no callback that matches the predicate was received. + * If no predicate is given, they make sure that no callback at all was received. + * These methods run the waiter func given in the constructor if any. + */ @JvmOverloads fun assertNoCallback( timeoutMs: Long = defaultNoCallbackTimeoutMs, @@ -379,9 +385,12 @@ open class TestableNetworkCallback private constructor( fun assertNoCallback(valid: (CallbackEntry) -> Boolean) = assertNoCallback(defaultNoCallbackTimeoutMs, valid) - // Expects a callback of the specified type matching the predicate within the timeout. - // Any callback that doesn't match the predicate will be skipped. Fails only if - // no matching callback is received within the timeout. + /***** + * eventuallyExpect family of methods. + * These methods make sure a callback that matches the type/predicate is received eventually. + * Any callback of the wrong type, or doesn't match the optional predicate, is ignored. + * They fail if no callback matching the predicate is received within the timeout. + */ inline fun eventuallyExpect( timeoutMs: Long = defaultTimeoutMs, from: Int = mark, From c2cf7eb82d2bb76d07e9a29b131deaba6bb13dd0 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 27 Feb 2023 19:13:46 +0900 Subject: [PATCH 656/777] Remove pollOrThrow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This method is better removed, because it doesn't follow the naming conventions we want to keep in this file. It also isn't useful : • There is only one use of it outside tests, and it's in the same file. It's trivial to inline it. • The method has a unit test, which becomes useless once the method is inlined. • There is a corresponding command in the interpreter, but it's only used by the unit test and therefore can be removed once the unit test is removed. Test: TH Bug: 157405399 Change-Id: Ib5b1369ac28e4577adc98204e42ff2f27729e64c --- .../testutils/TestableNetworkCallbackTest.kt | 13 -------- .../testutils/TestableNetworkCallback.kt | 31 ++++++------------- 2 files changed, 10 insertions(+), 34 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt index ec7cdbdfee..4ed881af33 100644 --- a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt +++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt @@ -365,18 +365,6 @@ class TestableNetworkCallbackTest { """) } - @Test - fun testPollOrThrow() { - assertFails { mCallback.pollOrThrow(SHORT_TIMEOUT_MS) } - TNCInterpreter.interpretTestSpec(initial = mCallback, lineShift = 1, - threadTransform = { cb -> cb.createLinkedCopy() }, spec = """ - sleep; onAvailable(133) | pollOrThrow(2) = Available(133) time 1..4 - | pollOrThrow(1) fails - onCapabilitiesChanged(108) | pollOrThrow(1) = CapabilitiesChanged(108) time 0..3 - onBlockedStatus(199) | pollOrThrow(1) = BlockedStatus(199) time 0..3 - """) - } - @Test fun testEventuallyExpect() { // TODO: Current test does not verify the inline one. Also verify the behavior after @@ -455,7 +443,6 @@ private val interpretTable = listOf>( } }, Regex("""poll\((\d+)\)""") to { i, cb, t -> cb.poll(t.timeArg(1)) }, - Regex("""pollOrThrow\((\d+)\)""") to { i, cb, t -> cb.pollOrThrow(t.timeArg(1)) }, // Interpret "eventually(Available(xx), timeout)" as calling eventuallyExpect that expects // CallbackEntry.AVAILABLE with netId of xx within timeout*INTERPRET_TIME_UNIT timeout, and // likewise for all callback types. diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index cb3be45bc3..0e73112d1b 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -223,18 +223,6 @@ open class TestableNetworkCallback private constructor( fun poll(timeoutMs: Long = defaultTimeoutMs, predicate: (CallbackEntry) -> Boolean = { true }) = history.poll(timeoutMs, predicate) - /** - * Get the next callback or throw if timeout. - * - * With no argument, this method waits out the default timeout. To wait forever, pass - * Long.MAX_VALUE. - */ - @JvmOverloads - fun pollOrThrow( - timeoutMs: Long = defaultTimeoutMs, - errorMsg: String = "Did not receive callback after $timeoutMs" - ): CallbackEntry = poll(timeoutMs) ?: fail(errorMsg) - /***** * expect family of methods. * These methods fetch the next callback and assert it matches the conditions : type, @@ -350,15 +338,16 @@ open class TestableNetworkCallback private constructor( timeoutMs: Long = defaultTimeoutMs, errorMsg: String? = null, test: (T) -> Boolean = { true } - ) = pollOrThrow(timeoutMs, "Did not receive ${T::class.simpleName} after ${timeoutMs}ms").also { - if (it !is T) fail("Expected callback ${T::class.simpleName}, got $it") - if (ANY_NETWORK !== network && it.network != network) { - fail("Expected network $network for callback : $it") - } - if (!test(it)) { - fail("${errorMsg ?: "Callback doesn't match predicate"} : $it") - } - } as T + ) = (poll(timeoutMs) ?: fail("Did not receive ${T::class.simpleName} after ${timeoutMs}ms")) + .also { + if (it !is T) fail("Expected callback ${T::class.simpleName}, got $it") + if (ANY_NETWORK !== network && it.network != network) { + fail("Expected network $network for callback : $it") + } + if (!test(it)) { + fail("${errorMsg ?: "Callback doesn't match predicate"} : $it") + } + } as T inline fun expect( network: HasNetwork, From aab04f1455eacacbaf235da52c25c024d32bed8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 8 Mar 2023 19:02:48 -0800 Subject: [PATCH 657/777] introduce BpfClassic.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit with helper macros for writing classic bpf code Bug: 265591307 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ibffad51668303ddc5d6850409f9058dfc2894ef6 --- .../bpf_headers/include/bpf/BpfClassic.h | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 staticlibs/native/bpf_headers/include/bpf/BpfClassic.h diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfClassic.h b/staticlibs/native/bpf_headers/include/bpf/BpfClassic.h new file mode 100644 index 0000000000..9b38deec9f --- /dev/null +++ b/staticlibs/native/bpf_headers/include/bpf/BpfClassic.h @@ -0,0 +1,96 @@ +/* + * 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. + */ + +#pragma once + +// Accept the full packet +#define BPF_ACCEPT BPF_STMT(BPF_RET | BPF_K, 0xFFFFFFFF) + +// Reject the packet +#define BPF_REJECT BPF_STMT(BPF_RET | BPF_K, 0) + +// *TWO* instructions: compare and if equal jump over the reject statement +#define BPF2_REJECT_IF_NOT_EQUAL(v) \ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, (v), 1, 0), \ + BPF_REJECT + +// 8-bit load relative to start of link layer (mac/ethernet) header. +#define BPF_LOAD_MAC_RELATIVE_U8(ofs) \ + BPF_STMT(BPF_LD | BPF_B | BPF_ABS, (__u32)SKF_LL_OFF + (ofs)) + +// Big/Network Endian 16-bit load relative to start of link layer (mac/ethernet) header. +#define BPF_LOAD_MAC_RELATIVE_BE16(ofs) \ + BPF_STMT(BPF_LD | BPF_H | BPF_ABS, (__u32)SKF_LL_OFF + (ofs)) + +// Big/Network Endian 32-bit load relative to start of link layer (mac/ethernet) header. +#define BPF_LOAD_MAC_RELATIVE_BE32(ofs) \ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (__u32)SKF_LL_OFF + (ofs)) + +// 8-bit load relative to start of network (IPv4/IPv6) header. +#define BPF_LOAD_NET_RELATIVE_U8(ofs) \ + BPF_STMT(BPF_LD | BPF_B | BPF_ABS, (__u32)SKF_NET_OFF + (ofs)) + +// Big/Network Endian 16-bit load relative to start of network (IPv4/IPv6) header. +#define BPF_LOAD_NET_RELATIVE_BE16(ofs) \ + BPF_STMT(BPF_LD | BPF_H | BPF_ABS, (__u32)SKF_NET_OFF + (ofs)) + +// Big/Network Endian 32-bit load relative to start of network (IPv4/IPv6) header. +#define BPF_LOAD_NET_RELATIVE_BE32(ofs) \ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (__u32)SKF_NET_OFF + (ofs)) + +#define field_sizeof(struct_type,field) sizeof(((struct_type *)0)->field) + +// 8-bit load from IPv4 header field. +#define BPF_LOAD_IPV4_U8(field) \ + BPF_LOAD_NET_RELATIVE_U8(({ \ + _Static_assert(field_sizeof(struct iphdr, field) == 1, "field of wrong size"); \ + offsetof(iphdr, field); \ + })) + +// Big/Network Endian 16-bit load from IPv4 header field. +#define BPF_LOAD_IPV4_BE16(field) \ + BPF_LOAD_NET_RELATIVE_BE16(({ \ + _Static_assert(field_sizeof(struct iphdr, field) == 2, "field of wrong size"); \ + offsetof(iphdr, field); \ + })) + +// Big/Network Endian 32-bit load from IPv4 header field. +#define BPF_LOAD_IPV4_BE32(field) \ + BPF_LOAD_NET_RELATIVE_BE32(({ \ + _Static_assert(field_sizeof(struct iphdr, field) == 4, "field of wrong size"); \ + offsetof(iphdr, field); \ + })) + +// 8-bit load from IPv6 header field. +#define BPF_LOAD_IPV6_U8(field) \ + BPF_LOAD_NET_RELATIVE_U8(({ \ + _Static_assert(field_sizeof(struct ipv6hdr, field) == 1, "field of wrong size"); \ + offsetof(ipv6hdr, field); \ + })) + +// Big/Network Endian 16-bit load from IPv6 header field. +#define BPF_LOAD_IPV6_BE16(field) \ + BPF_LOAD_NET_RELATIVE_BE16(({ \ + _Static_assert(field_sizeof(struct ipv6hdr, field) == 2, "field of wrong size"); \ + offsetof(ipv6hdr, field); \ + })) + +// Big/Network Endian 32-bit load from IPv6 header field. +#define BPF_LOAD_IPV6_BE32(field) \ + BPF_LOAD_NET_RELATIVE_BE32(({ \ + _Static_assert(field_sizeof(struct ipv6hdr, field) == 4, "field of wrong size"); \ + offsetof(ipv6hdr, field); \ + })) From 048a452551987c5765926423dfedbcbaf89fc093 Mon Sep 17 00:00:00 2001 From: Yuyang Huang Date: Mon, 13 Mar 2023 18:48:52 +0900 Subject: [PATCH 658/777] Adds constructors for RtNetlinkAddressMessage and StructIfaddrMsg Adds constructors for RtNetlinkAddressMessage and StructIfaddrMsg to make it possible to directly construct RtNetlinkAddressMessage in the test cases. Bug: 267980538 Test: m Change-Id: I21bf0cbef888495dc9a165a0fe6d5b39135e4c18 --- .../util/netlink/RtNetlinkAddressMessage.java | 18 +++++++++++++----- .../module/util/netlink/StructIfaddrMsg.java | 4 +++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java index c07cec08f7..31c3a2e1b3 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java @@ -58,12 +58,20 @@ public class RtNetlinkAddressMessage extends NetlinkMessage { @Nullable private StructIfacacheInfo mIfacacheInfo; - private RtNetlinkAddressMessage(@NonNull StructNlMsgHdr header) { + @VisibleForTesting + public RtNetlinkAddressMessage(@NonNull final StructNlMsgHdr header, + @NonNull final StructIfaddrMsg ifaddrMsg, + @NonNull final InetAddress ipAddress, + @Nullable final StructIfacacheInfo structIfacacheInfo, + int flags) { super(header); - mIfaddrmsg = null; - mIpAddress = null; - mIfacacheInfo = null; - mFlags = 0; + mIfaddrmsg = ifaddrMsg; + mIpAddress = ipAddress; + mIfacacheInfo = structIfacacheInfo; + mFlags = flags; + } + private RtNetlinkAddressMessage(@NonNull StructNlMsgHdr header) { + this(header, null, null, null, 0); } public int getFlags() { diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructIfaddrMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructIfaddrMsg.java index 9196feba20..2802726352 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructIfaddrMsg.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructIfaddrMsg.java @@ -18,6 +18,7 @@ package com.android.net.module.util.netlink; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import com.android.net.module.util.Struct; import com.android.net.module.util.Struct.Field; @@ -49,7 +50,8 @@ public class StructIfaddrMsg extends Struct { @Field(order = 4, type = Type.S32) public final int index; - StructIfaddrMsg(short family, short prefixLen, short flags, short scope, int index) { + @VisibleForTesting + public StructIfaddrMsg(short family, short prefixLen, short flags, short scope, int index) { this.family = family; this.prefixLen = prefixLen; this.flags = flags; From 6ba8685aba95a732c6d2aa30db07c238f70f7b53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 15 Mar 2023 00:22:59 +0000 Subject: [PATCH 659/777] minor checksum changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit main change is checksum of zero buffer is now 0 instead of the equivalent, but technically incorrect 0xFFFF. Test: TreeHugger Bug: 265591307 Signed-off-by: Maciej Żenczykowski Change-Id: I1a8b0ace704009f82d3b7ad1c299bf8a6d8964d8 --- staticlibs/native/ip_checksum/checksum.c | 36 ++++++++---------------- staticlibs/native/ip_checksum/checksum.h | 7 +---- 2 files changed, 12 insertions(+), 31 deletions(-) diff --git a/staticlibs/native/ip_checksum/checksum.c b/staticlibs/native/ip_checksum/checksum.c index 04217a7992..5641fad4e6 100644 --- a/staticlibs/native/ip_checksum/checksum.c +++ b/staticlibs/native/ip_checksum/checksum.c @@ -32,20 +32,16 @@ * len - length of data */ uint32_t ip_checksum_add(uint32_t current, const void* data, int len) { - uint32_t checksum = current; - int left = len; const uint16_t* data_16 = data; - while (left > 1) { - checksum += *data_16; + while (len >= 2) { + current += *data_16; data_16++; - left -= 2; - } - if (left) { - checksum += *(uint8_t*)data_16; + len -= 2; } + if (len) current += *(uint8_t*)data_16; // assumes little endian! - return checksum; + return current; } /* function: ip_checksum_fold @@ -54,9 +50,8 @@ uint32_t ip_checksum_add(uint32_t current, const void* data, int len) { * returns: the folded checksum in network byte order */ uint16_t ip_checksum_fold(uint32_t temp_sum) { - while (temp_sum > 0xffff) { - temp_sum = (temp_sum >> 16) + (temp_sum & 0xFFFF); - } + temp_sum = (temp_sum >> 16) + (temp_sum & 0xFFFF); + temp_sum = (temp_sum >> 16) + (temp_sum & 0xFFFF); return temp_sum; } @@ -75,12 +70,7 @@ uint16_t ip_checksum_finish(uint32_t temp_sum) { * len - length of data */ uint16_t ip_checksum(const void* data, int len) { - // TODO: consider starting from 0xffff so the checksum of a buffer entirely consisting of zeros - // is correctly calculated as 0. - uint32_t temp_sum; - - temp_sum = ip_checksum_add(0, data, len); - return ip_checksum_finish(temp_sum); + return ip_checksum_finish(ip_checksum_add(0xFFFF, data, len)); } /* function: ipv6_pseudo_header_checksum @@ -92,7 +82,6 @@ uint16_t ip_checksum(const void* data, int len) { uint32_t ipv6_pseudo_header_checksum(const struct ip6_hdr* ip6, uint32_t len, uint8_t protocol) { uint32_t checksum_len = htonl(len); uint32_t checksum_next = htonl(protocol); - uint32_t current = 0; current = ip_checksum_add(current, &(ip6->ip6_src), sizeof(struct in6_addr)); @@ -109,11 +98,8 @@ uint32_t ipv6_pseudo_header_checksum(const struct ip6_hdr* ip6, uint32_t len, ui * len - the transport length (transport header + payload) */ uint32_t ipv4_pseudo_header_checksum(const struct iphdr* ip, uint16_t len) { - uint16_t temp_protocol, temp_length; - - temp_protocol = htons(ip->protocol); - temp_length = htons(len); - + uint16_t temp_protocol = htons(ip->protocol); + uint16_t temp_length = htons(len); uint32_t current = 0; current = ip_checksum_add(current, &(ip->saddr), sizeof(uint32_t)); @@ -135,7 +121,7 @@ uint16_t ip_checksum_adjust(uint16_t checksum, uint32_t old_hdr_sum, uint32_t ne // Algorithm suggested in RFC 1624. // http://tools.ietf.org/html/rfc1624#section-3 checksum = ~checksum; - uint16_t folded_sum = ip_checksum_fold(checksum + new_hdr_sum); + uint16_t folded_sum = ip_checksum_fold(new_hdr_sum + checksum); uint16_t folded_old = ip_checksum_fold(old_hdr_sum); if (folded_sum > folded_old) { return ~(folded_sum - folded_old); diff --git a/staticlibs/native/ip_checksum/checksum.h b/staticlibs/native/ip_checksum/checksum.h index 868217c5d1..87393c9613 100644 --- a/staticlibs/native/ip_checksum/checksum.h +++ b/staticlibs/native/ip_checksum/checksum.h @@ -12,11 +12,8 @@ * 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. - * - * checksum.h - checksum functions */ -#ifndef __CHECKSUM_H__ -#define __CHECKSUM_H__ +#pragma once #include #include @@ -30,5 +27,3 @@ uint32_t ipv6_pseudo_header_checksum(const struct ip6_hdr* ip6, uint32_t len, ui uint32_t ipv4_pseudo_header_checksum(const struct iphdr* ip, uint16_t len); uint16_t ip_checksum_adjust(uint16_t checksum, uint32_t old_hdr_sum, uint32_t new_hdr_sum); - -#endif /* __CHECKSUM_H__ */ From 5622c37a85bd49ca2390b9786d2c1160631d2245 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 15 Mar 2023 11:39:49 +0800 Subject: [PATCH 660/777] [ST04.1] Move PacketReflector to static library This is also needed by integration test in NetworkStack module in follow-up CLs. Move to a common place first. This is a no-op refactoring. Test: atest com.android.cts.net.HostsideVpnTests Bug: 139774492 Change-Id: Ifc7ed4c93edfb0f6f8eb47231f6df40332d2c10c --- .../android/testutils/PacketReflector.java | 254 ++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/PacketReflector.java diff --git a/staticlibs/testutils/devicetests/com/android/testutils/PacketReflector.java b/staticlibs/testutils/devicetests/com/android/testutils/PacketReflector.java new file mode 100644 index 0000000000..b05bb9b276 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/PacketReflector.java @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2014 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 com.android.testutils; + +import static android.system.OsConstants.ICMP6_ECHO_REPLY; +import static android.system.OsConstants.ICMP6_ECHO_REQUEST; +import static android.system.OsConstants.ICMP_ECHO; +import static android.system.OsConstants.ICMP_ECHOREPLY; + +import android.system.ErrnoException; +import android.system.Os; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.IOException; + +public class PacketReflector extends Thread { + + private static int IPV4_HEADER_LENGTH = 20; + private static int IPV6_HEADER_LENGTH = 40; + + private static int IPV4_ADDR_OFFSET = 12; + private static int IPV6_ADDR_OFFSET = 8; + private static int IPV4_ADDR_LENGTH = 4; + private static int IPV6_ADDR_LENGTH = 16; + + private static int IPV4_PROTO_OFFSET = 9; + private static int IPV6_PROTO_OFFSET = 6; + + private static final byte IPPROTO_ICMP = 1; + private static final byte IPPROTO_TCP = 6; + private static final byte IPPROTO_UDP = 17; + private static final byte IPPROTO_ICMPV6 = 58; + + private static int ICMP_HEADER_LENGTH = 8; + private static int TCP_HEADER_LENGTH = 20; + private static int UDP_HEADER_LENGTH = 8; + + private static final byte ICMP_ECHO = 8; + private static final byte ICMP_ECHOREPLY = 0; + + private static String TAG = "PacketReflector"; + + private FileDescriptor mFd; + private byte[] mBuf; + + public PacketReflector(FileDescriptor fd, int mtu) { + super("PacketReflector"); + mFd = fd; + mBuf = new byte[mtu]; + } + + private static void swapBytes(byte[] buf, int pos1, int pos2, int len) { + for (int i = 0; i < len; i++) { + byte b = buf[pos1 + i]; + buf[pos1 + i] = buf[pos2 + i]; + buf[pos2 + i] = b; + } + } + + private static void swapAddresses(byte[] buf, int version) { + int addrPos, addrLen; + switch(version) { + case 4: + addrPos = IPV4_ADDR_OFFSET; + addrLen = IPV4_ADDR_LENGTH; + break; + case 6: + addrPos = IPV6_ADDR_OFFSET; + addrLen = IPV6_ADDR_LENGTH; + break; + default: + throw new IllegalArgumentException(); + } + swapBytes(buf, addrPos, addrPos + addrLen, addrLen); + } + + // Reflect TCP packets: swap the source and destination addresses, but don't change the ports. + // This is used by the test to "connect to itself" through the VPN. + private void processTcpPacket(byte[] buf, int version, int len, int hdrLen) { + if (len < hdrLen + TCP_HEADER_LENGTH) { + return; + } + + // Swap src and dst IP addresses. + swapAddresses(buf, version); + + // Send the packet back. + writePacket(buf, len); + } + + // Echo UDP packets: swap source and destination addresses, and source and destination ports. + // This is used by the test to check that the bytes it sends are echoed back. + private void processUdpPacket(byte[] buf, int version, int len, int hdrLen) { + if (len < hdrLen + UDP_HEADER_LENGTH) { + return; + } + + // Swap src and dst IP addresses. + swapAddresses(buf, version); + + // Swap dst and src ports. + int portOffset = hdrLen; + swapBytes(buf, portOffset, portOffset + 2, 2); + + // Send the packet back. + writePacket(buf, len); + } + + private void processIcmpPacket(byte[] buf, int version, int len, int hdrLen) { + if (len < hdrLen + ICMP_HEADER_LENGTH) { + return; + } + + byte type = buf[hdrLen]; + if (!(version == 4 && type == ICMP_ECHO) && + !(version == 6 && type == (byte) ICMP6_ECHO_REQUEST)) { + return; + } + + // Save the ping packet we received. + byte[] request = buf.clone(); + + // Swap src and dst IP addresses, and send the packet back. + // This effectively pings the device to see if it replies. + swapAddresses(buf, version); + writePacket(buf, len); + + // The device should have replied, and buf should now contain a ping response. + int received = readPacket(buf); + if (received != len) { + Log.i(TAG, "Reflecting ping did not result in ping response: " + + "read=" + received + " expected=" + len); + return; + } + + byte replyType = buf[hdrLen]; + if ((type == ICMP_ECHO && replyType != ICMP_ECHOREPLY) + || (type == (byte) ICMP6_ECHO_REQUEST && replyType != (byte) ICMP6_ECHO_REPLY)) { + Log.i(TAG, "Received unexpected ICMP reply: original " + type + + ", reply " + replyType); + return; + } + + // Compare the response we got with the original packet. + // The only thing that should have changed are addresses, type and checksum. + // Overwrite them with the received bytes and see if the packet is otherwise identical. + request[hdrLen] = buf[hdrLen]; // Type + request[hdrLen + 2] = buf[hdrLen + 2]; // Checksum byte 1. + request[hdrLen + 3] = buf[hdrLen + 3]; // Checksum byte 2. + + // Since Linux kernel 4.2, net.ipv6.auto_flowlabels is set by default, and therefore + // the request and reply may have different IPv6 flow label: ignore that as well. + if (version == 6) { + request[1] = (byte)(request[1] & 0xf0 | buf[1] & 0x0f); + request[2] = buf[2]; + request[3] = buf[3]; + } + + for (int i = 0; i < len; i++) { + if (buf[i] != request[i]) { + Log.i(TAG, "Received non-matching packet when expecting ping response."); + return; + } + } + + // Now swap the addresses again and reflect the packet. This sends a ping reply. + swapAddresses(buf, version); + writePacket(buf, len); + } + + private void writePacket(byte[] buf, int len) { + try { + Os.write(mFd, buf, 0, len); + } catch (ErrnoException|IOException e) { + Log.e(TAG, "Error writing packet: " + e.getMessage()); + } + } + + private int readPacket(byte[] buf) { + int len; + try { + len = Os.read(mFd, buf, 0, buf.length); + } catch (ErrnoException|IOException e) { + Log.e(TAG, "Error reading packet: " + e.getMessage()); + len = -1; + } + return len; + } + + // Reads one packet from our mFd, and possibly writes the packet back. + private void processPacket() { + int len = readPacket(mBuf); + if (len < 1) { + return; + } + + int version = mBuf[0] >> 4; + int addrPos, protoPos, hdrLen, addrLen; + if (version == 4) { + hdrLen = IPV4_HEADER_LENGTH; + protoPos = IPV4_PROTO_OFFSET; + addrPos = IPV4_ADDR_OFFSET; + addrLen = IPV4_ADDR_LENGTH; + } else if (version == 6) { + hdrLen = IPV6_HEADER_LENGTH; + protoPos = IPV6_PROTO_OFFSET; + addrPos = IPV6_ADDR_OFFSET; + addrLen = IPV6_ADDR_LENGTH; + } else { + return; + } + + if (len < hdrLen) { + return; + } + + byte proto = mBuf[protoPos]; + switch (proto) { + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + processIcmpPacket(mBuf, version, len, hdrLen); + break; + case IPPROTO_TCP: + processTcpPacket(mBuf, version, len, hdrLen); + break; + case IPPROTO_UDP: + processUdpPacket(mBuf, version, len, hdrLen); + break; + } + } + + public void run() { + Log.i(TAG, "PacketReflector starting fd=" + mFd + " valid=" + mFd.valid()); + while (!interrupted() && mFd.valid()) { + processPacket(); + } + Log.i(TAG, "PacketReflector exiting fd=" + mFd + " valid=" + mFd.valid()); + } +} From 388204218b58e663530f783128a87aa6e30703e3 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 15 Mar 2023 13:36:42 +0800 Subject: [PATCH 661/777] Fix lint errors and adding nullability annotations in PacketReflector This is a no-op refactoring. Test: TH Bug: 139774492 Change-Id: Ibb6605a9f7add8319321e5b4960a0b9b637f1434 --- .../android/testutils/PacketReflector.java | 64 +++++++++---------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/PacketReflector.java b/staticlibs/testutils/devicetests/com/android/testutils/PacketReflector.java index b05bb9b276..96bca624d6 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/PacketReflector.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/PacketReflector.java @@ -18,9 +18,8 @@ package com.android.testutils; import static android.system.OsConstants.ICMP6_ECHO_REPLY; import static android.system.OsConstants.ICMP6_ECHO_REQUEST; -import static android.system.OsConstants.ICMP_ECHO; -import static android.system.OsConstants.ICMP_ECHOREPLY; +import android.annotation.NonNull; import android.system.ErrnoException; import android.system.Os; import android.util.Log; @@ -30,41 +29,41 @@ import java.io.IOException; public class PacketReflector extends Thread { - private static int IPV4_HEADER_LENGTH = 20; - private static int IPV6_HEADER_LENGTH = 40; + private static final int IPV4_HEADER_LENGTH = 20; + private static final int IPV6_HEADER_LENGTH = 40; - private static int IPV4_ADDR_OFFSET = 12; - private static int IPV6_ADDR_OFFSET = 8; - private static int IPV4_ADDR_LENGTH = 4; - private static int IPV6_ADDR_LENGTH = 16; + private static final int IPV4_ADDR_OFFSET = 12; + private static final int IPV6_ADDR_OFFSET = 8; + private static final int IPV4_ADDR_LENGTH = 4; + private static final int IPV6_ADDR_LENGTH = 16; - private static int IPV4_PROTO_OFFSET = 9; - private static int IPV6_PROTO_OFFSET = 6; + private static final int IPV4_PROTO_OFFSET = 9; + private static final int IPV6_PROTO_OFFSET = 6; private static final byte IPPROTO_ICMP = 1; private static final byte IPPROTO_TCP = 6; private static final byte IPPROTO_UDP = 17; private static final byte IPPROTO_ICMPV6 = 58; - private static int ICMP_HEADER_LENGTH = 8; - private static int TCP_HEADER_LENGTH = 20; - private static int UDP_HEADER_LENGTH = 8; + private static final int ICMP_HEADER_LENGTH = 8; + private static final int TCP_HEADER_LENGTH = 20; + private static final int UDP_HEADER_LENGTH = 8; private static final byte ICMP_ECHO = 8; private static final byte ICMP_ECHOREPLY = 0; private static String TAG = "PacketReflector"; - private FileDescriptor mFd; - private byte[] mBuf; + @NonNull private FileDescriptor mFd; + @NonNull private byte[] mBuf; - public PacketReflector(FileDescriptor fd, int mtu) { + public PacketReflector(@NonNull FileDescriptor fd, int mtu) { super("PacketReflector"); mFd = fd; mBuf = new byte[mtu]; } - private static void swapBytes(byte[] buf, int pos1, int pos2, int len) { + private static void swapBytes(@NonNull byte[] buf, int pos1, int pos2, int len) { for (int i = 0; i < len; i++) { byte b = buf[pos1 + i]; buf[pos1 + i] = buf[pos2 + i]; @@ -72,9 +71,9 @@ public class PacketReflector extends Thread { } } - private static void swapAddresses(byte[] buf, int version) { + private static void swapAddresses(@NonNull byte[] buf, int version) { int addrPos, addrLen; - switch(version) { + switch (version) { case 4: addrPos = IPV4_ADDR_OFFSET; addrLen = IPV4_ADDR_LENGTH; @@ -91,7 +90,7 @@ public class PacketReflector extends Thread { // Reflect TCP packets: swap the source and destination addresses, but don't change the ports. // This is used by the test to "connect to itself" through the VPN. - private void processTcpPacket(byte[] buf, int version, int len, int hdrLen) { + private void processTcpPacket(@NonNull byte[] buf, int version, int len, int hdrLen) { if (len < hdrLen + TCP_HEADER_LENGTH) { return; } @@ -105,7 +104,7 @@ public class PacketReflector extends Thread { // Echo UDP packets: swap source and destination addresses, and source and destination ports. // This is used by the test to check that the bytes it sends are echoed back. - private void processUdpPacket(byte[] buf, int version, int len, int hdrLen) { + private void processUdpPacket(@NonNull byte[] buf, int version, int len, int hdrLen) { if (len < hdrLen + UDP_HEADER_LENGTH) { return; } @@ -121,14 +120,14 @@ public class PacketReflector extends Thread { writePacket(buf, len); } - private void processIcmpPacket(byte[] buf, int version, int len, int hdrLen) { + private void processIcmpPacket(@NonNull byte[] buf, int version, int len, int hdrLen) { if (len < hdrLen + ICMP_HEADER_LENGTH) { return; } byte type = buf[hdrLen]; if (!(version == 4 && type == ICMP_ECHO) && - !(version == 6 && type == (byte) ICMP6_ECHO_REQUEST)) { + !(version == 6 && type == (byte) ICMP6_ECHO_REQUEST)) { return; } @@ -144,7 +143,7 @@ public class PacketReflector extends Thread { int received = readPacket(buf); if (received != len) { Log.i(TAG, "Reflecting ping did not result in ping response: " + - "read=" + received + " expected=" + len); + "read=" + received + " expected=" + len); return; } @@ -166,7 +165,7 @@ public class PacketReflector extends Thread { // Since Linux kernel 4.2, net.ipv6.auto_flowlabels is set by default, and therefore // the request and reply may have different IPv6 flow label: ignore that as well. if (version == 6) { - request[1] = (byte)(request[1] & 0xf0 | buf[1] & 0x0f); + request[1] = (byte) (request[1] & 0xf0 | buf[1] & 0x0f); request[2] = buf[2]; request[3] = buf[3]; } @@ -183,19 +182,19 @@ public class PacketReflector extends Thread { writePacket(buf, len); } - private void writePacket(byte[] buf, int len) { + private void writePacket(@NonNull byte[] buf, int len) { try { Os.write(mFd, buf, 0, len); - } catch (ErrnoException|IOException e) { + } catch (ErrnoException | IOException e) { Log.e(TAG, "Error writing packet: " + e.getMessage()); } } - private int readPacket(byte[] buf) { + private int readPacket(@NonNull byte[] buf) { int len; try { len = Os.read(mFd, buf, 0, buf.length); - } catch (ErrnoException|IOException e) { + } catch (ErrnoException | IOException e) { Log.e(TAG, "Error reading packet: " + e.getMessage()); len = -1; } @@ -210,17 +209,13 @@ public class PacketReflector extends Thread { } int version = mBuf[0] >> 4; - int addrPos, protoPos, hdrLen, addrLen; + int protoPos, hdrLen; if (version == 4) { hdrLen = IPV4_HEADER_LENGTH; protoPos = IPV4_PROTO_OFFSET; - addrPos = IPV4_ADDR_OFFSET; - addrLen = IPV4_ADDR_LENGTH; } else if (version == 6) { hdrLen = IPV6_HEADER_LENGTH; protoPos = IPV6_PROTO_OFFSET; - addrPos = IPV6_ADDR_OFFSET; - addrLen = IPV6_ADDR_LENGTH; } else { return; } @@ -232,6 +227,7 @@ public class PacketReflector extends Thread { byte proto = mBuf[protoPos]; switch (proto) { case IPPROTO_ICMP: + // fall through case IPPROTO_ICMPV6: processIcmpPacket(mBuf, version, len, hdrLen); break; From 9a1359b46c58b47387bf84cfc80fb13431484b6c Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 22 Mar 2023 19:56:15 +0900 Subject: [PATCH 662/777] Support NLM_F_REPLACE flag when sending a RTM_NEWADDR message. NLM_F_REPLACE is helpful when we only want to update the preferred and valid lifetime for a specific IPv6 address. DHCPv6 prefix delegation gives a concrete example, once client refreshes the delegated prefix successfully in RENEW or REBIND state, it also needs to extend the preferred and valid lifetime of an IPv6 address, otherwise, it becomes depreacated when the lifetime expires. Add the NLM_F_REPLACE flag to replace the existing matching address object with updated fields. Bug: 260934173 Test: atest NetworkStaticLibsTests Change-Id: Ic001ddf9cfb031a586bbe177819e7666eaf7cde0 --- .../net/module/util/netlink/RtNetlinkAddressMessage.java | 3 ++- .../net/module/util/netlink/RtNetlinkAddressMessageTest.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java index 31c3a2e1b3..2829b927e8 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java @@ -17,6 +17,7 @@ package com.android.net.module.util.netlink; import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REPLACE; import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; import android.system.OsConstants; @@ -168,7 +169,7 @@ public class RtNetlinkAddressMessage extends NetlinkMessage { final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWADDR; - nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_ACK; nlmsghdr.nlmsg_seq = seqNo; final RtNetlinkAddressMessage msg = new RtNetlinkAddressMessage(nlmsghdr); diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java index f845eb426b..99d96b5a62 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java @@ -144,7 +144,7 @@ public class RtNetlinkAddressMessageTest { // struct nlmsghdr "48000000" + // length = 72 "1400" + // type = 20 (RTM_NEWADDR) - "0500" + // flags = NLM_F_ACK | NLM_F_REQUEST + "0501" + // flags = NLM_F_ACK | NLM_F_REQUEST | NLM_F_REPLACE "01000000" + // seqno = 1 "00000000" + // pid = 0 (send to kernel) // struct IfaddrMsg @@ -195,7 +195,7 @@ public class RtNetlinkAddressMessageTest { // struct nlmsghdr "48000000" + // length = 72 "1400" + // type = 20 (RTM_NEWADDR) - "0500" + // flags = NLM_F_ACK | NLM_F_REQUEST + "0501" + // flags = NLM_F_ACK | NLM_F_REQUEST | NLM_F_REPLACE "01000000" + // seqno = 1 "00000000" + // pid = 0 (send to kernel) // struct IfaddrMsg From 06e615e3cefacd396522936f47caafb9a23b02e1 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Wed, 22 Feb 2023 17:21:08 +0900 Subject: [PATCH 663/777] Fix StructInetDiagMsg#parse bug StructInetDiagMsg#parse used absolute position to parse id and idiag_uid fields. This causes an issue when byte buffer contains multiple netlink messages and parsed netlink message starts from the middle of byte buffer. This CL fixes above issue and adds test for the case that single byte buffer contains multiple netlink messages. Test: atest NetworkStaticLibTests Change-Id: I771daf17b4a606915d5edefd9f0e90ef01abf168 --- .../util/netlink/StructInetDiagMsg.java | 16 ++- .../util/netlink/InetDiagSocketTest.java | 125 ++++++++++++++---- 2 files changed, 111 insertions(+), 30 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagMsg.java index ea018cf692..e7fc02f604 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagMsg.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagMsg.java @@ -43,9 +43,11 @@ import java.nio.ByteBuffer; */ public class StructInetDiagMsg { public static final int STRUCT_SIZE = 4 + StructInetDiagSockId.STRUCT_SIZE + 20; - private static final int IDIAG_SOCK_ID_OFFSET = StructNlMsgHdr.STRUCT_SIZE + 4; - private static final int IDIAG_UID_OFFSET = StructNlMsgHdr.STRUCT_SIZE + 4 - + StructInetDiagSockId.STRUCT_SIZE + 12; + // Offset to the id field from the beginning of inet_diag_msg struct + private static final int IDIAG_SOCK_ID_OFFSET = 4; + // Offset to the idiag_uid field from the beginning of inet_diag_msg struct + private static final int IDIAG_UID_OFFSET = + IDIAG_SOCK_ID_OFFSET + StructInetDiagSockId.STRUCT_SIZE + 12; public int idiag_uid; @NonNull public StructInetDiagSockId id; @@ -58,14 +60,18 @@ public class StructInetDiagMsg { if (byteBuffer.remaining() < STRUCT_SIZE) { return null; } + final int baseOffset = byteBuffer.position(); StructInetDiagMsg struct = new StructInetDiagMsg(); final byte family = byteBuffer.get(); - byteBuffer.position(IDIAG_SOCK_ID_OFFSET); + byteBuffer.position(baseOffset + IDIAG_SOCK_ID_OFFSET); struct.id = StructInetDiagSockId.parse(byteBuffer, family); if (struct.id == null) { return null; } - struct.idiag_uid = byteBuffer.getInt(IDIAG_UID_OFFSET); + struct.idiag_uid = byteBuffer.getInt(baseOffset + IDIAG_UID_OFFSET); + + // Move position to the end of the inet_diag_msg + byteBuffer.position(baseOffset + STRUCT_SIZE); return struct; } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java index c7e2a4db00..d81422fbb9 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java @@ -221,14 +221,31 @@ public class InetDiagSocketTest { assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_BYTES, msgExt); } - // Hexadecimal representation of InetDiagReqV2 request. - private static final String INET_DIAG_MSG_HEX = + private void assertNlMsgHdr(StructNlMsgHdr hdr, short type, short flags, int seq, int pid) { + assertNotNull(hdr); + assertEquals(type, hdr.nlmsg_type); + assertEquals(flags, hdr.nlmsg_flags); + assertEquals(seq, hdr.nlmsg_seq); + assertEquals(pid, hdr.nlmsg_pid); + } + + private void assertInetDiagSockId(StructInetDiagSockId sockId, + InetSocketAddress locSocketAddress, InetSocketAddress remSocketAddress, + int ifIndex, long cookie) { + assertEquals(locSocketAddress, sockId.locSocketAddress); + assertEquals(remSocketAddress, sockId.remSocketAddress); + assertEquals(ifIndex, sockId.ifIndex); + assertEquals(cookie, sockId.cookie); + } + + // Hexadecimal representation of InetDiagMessage + private static final String INET_DIAG_MSG_HEX1 = // struct nlmsghdr "58000000" + // length = 88 "1400" + // type = SOCK_DIAG_BY_FAMILY "0200" + // flags = NLM_F_MULTI "00000000" + // seqno - "f5220000" + // pid (0 == kernel) + "f5220000" + // pid // struct inet_diag_msg "0a" + // family = AF_INET6 "01" + // idiag_state @@ -244,36 +261,94 @@ public class InetDiagSocketTest { "00000000" + // idiag_expires "00000000" + // idiag_rqueue "00000000" + // idiag_wqueue - "a3270000" + // idiag_uid + "a3270000" + // idiag_uid = 10147 "A57E1900"; // idiag_inode + + private void assertInetDiagMsg1(final NetlinkMessage msg) { + assertNotNull(msg); + + assertTrue(msg instanceof InetDiagMessage); + final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg; + + assertNlMsgHdr(inetDiagMsg.getHeader(), + NetlinkConstants.SOCK_DIAG_BY_FAMILY, + StructNlMsgHdr.NLM_F_MULTI, + 0 /* seq */, + 8949 /* pid */); + + assertEquals(10147, inetDiagMsg.inetDiagMsg.idiag_uid); + assertInetDiagSockId(inetDiagMsg.inetDiagMsg.id, + new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::1"), 43031), + new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::2"), 38415), + 7 /* ifIndex */, + 88 /* cookie */); + } + + // Hexadecimal representation of InetDiagMessage + private static final String INET_DIAG_MSG_HEX2 = + // struct nlmsghdr + "58000000" + // length = 88 + "1400" + // type = SOCK_DIAG_BY_FAMILY + "0200" + // flags = NLM_F_MULTI + "00000000" + // seqno + "f5220000" + // pid + // struct inet_diag_msg + "0a" + // family = AF_INET6 + "01" + // idiag_state + "00" + // idiag_timer + "00" + // idiag_retrans + // inet_diag_sockid + "a845" + // idiag_sport = 43077 + "01bb" + // idiag_dport = 443 + "20010db8000000000000000000000003" + // idiag_src = 2001:db8::3 + "20010db8000000000000000000000004" + // idiag_dst = 2001:db8::4 + "08000000" + // idiag_if = 8 + "6300000000000000" + // idiag_cookie = 99 + "00000000" + // idiag_expires + "00000000" + // idiag_rqueue + "00000000" + // idiag_wqueue + "39300000" + // idiag_uid = 12345 + "A57E1900"; // idiag_inode + + private void assertInetDiagMsg2(final NetlinkMessage msg) { + assertNotNull(msg); + + assertTrue(msg instanceof InetDiagMessage); + final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg; + + assertNlMsgHdr(inetDiagMsg.getHeader(), + NetlinkConstants.SOCK_DIAG_BY_FAMILY, + StructNlMsgHdr.NLM_F_MULTI, + 0 /* seq */, + 8949 /* pid */); + + assertEquals(12345, inetDiagMsg.inetDiagMsg.idiag_uid); + assertInetDiagSockId(inetDiagMsg.inetDiagMsg.id, + new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::3"), 43077), + new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::4"), 443), + 8 /* ifIndex */, + 99 /* cookie */); + } + private static final byte[] INET_DIAG_MSG_BYTES = - HexEncoding.decode(INET_DIAG_MSG_HEX.toCharArray(), false); + HexEncoding.decode(INET_DIAG_MSG_HEX1.toCharArray(), false); @Test public void testParseInetDiagResponse() throws Exception { final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); - final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_INET_DIAG); - assertNotNull(msg); + assertInetDiagMsg1(NetlinkMessage.parse(byteBuffer, NETLINK_INET_DIAG)); + } - assertTrue(msg instanceof InetDiagMessage); - final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg; - assertEquals(10147, inetDiagMsg.inetDiagMsg.idiag_uid); - final StructInetDiagSockId sockId = inetDiagMsg.inetDiagMsg.id; - assertEquals(43031, sockId.locSocketAddress.getPort()); - assertEquals(InetAddresses.parseNumericAddress("2001:db8::1"), - sockId.locSocketAddress.getAddress()); - assertEquals(38415, sockId.remSocketAddress.getPort()); - assertEquals(InetAddresses.parseNumericAddress("2001:db8::2"), - sockId.remSocketAddress.getAddress()); - assertEquals(7, sockId.ifIndex); - assertEquals(88, sockId.cookie); - final StructNlMsgHdr hdr = inetDiagMsg.getHeader(); - assertNotNull(hdr); - assertEquals(NetlinkConstants.SOCK_DIAG_BY_FAMILY, hdr.nlmsg_type); - assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags); - assertEquals(0, hdr.nlmsg_seq); - assertEquals(8949, hdr.nlmsg_pid); + private static final byte[] INET_DIAG_MSG_BYTES_MULTIPLE = + HexEncoding.decode((INET_DIAG_MSG_HEX1 + INET_DIAG_MSG_HEX2).toCharArray(), false); + + @Test + public void testParseInetDiagResponseMultiple() { + final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES_MULTIPLE); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); + assertInetDiagMsg1(NetlinkMessage.parse(byteBuffer, NETLINK_INET_DIAG)); + assertInetDiagMsg2(NetlinkMessage.parse(byteBuffer, NETLINK_INET_DIAG)); } } From 86c95b49257abe6797a111ba7ae48d7f92388056 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 20 Mar 2023 17:15:21 +0800 Subject: [PATCH 664/777] [ST05.3] Support PacketBridge For testing purposes, a TestNetworkInterface provides a FileDescriptor which allows content injection on the test network. However, this could be hard to use because the callers need to compose IP packets in order to inject content to the test network. In order to remove the need of composing the IP packets, this class forwards IP packets between two TestNetworkInterface instances. Thus, the TCP/IP headers could be parsed/composed automatically by the protocol stack of this additional TestNetworkInterface, while the payload is supplied by the servers run on the interface. Test: 1. atest android.net.NetworkStatsIntegrationTest 2. atest com.android.cts.net.HostsideVpnTests Bug: 139774492 Change-Id: I8fe5a434d6d727a81d106a967dcdca157424e12e --- .../testutils/NatExternalPacketForwarder.kt | 81 +++++++ .../testutils/NatInternalPacketForwarder.kt | 78 +++++++ .../testutils/NatPacketForwarderBase.java | 206 ++++++++++++++++++ .../com/android/testutils/PacketBridge.kt | 173 +++++++++++++++ .../android/testutils/PacketReflector.java | 59 +++-- .../android/testutils/PacketReflectorUtil.kt | 106 +++++++++ 6 files changed, 670 insertions(+), 33 deletions(-) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/NatExternalPacketForwarder.kt create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/NatInternalPacketForwarder.kt create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/NatPacketForwarderBase.java create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/PacketBridge.kt create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/PacketReflectorUtil.kt diff --git a/staticlibs/testutils/devicetests/com/android/testutils/NatExternalPacketForwarder.kt b/staticlibs/testutils/devicetests/com/android/testutils/NatExternalPacketForwarder.kt new file mode 100644 index 0000000000..d7961a08f5 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/NatExternalPacketForwarder.kt @@ -0,0 +1,81 @@ +/* + * 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 com.android.testutils + +import java.io.FileDescriptor +import java.net.InetAddress + +/** + * A class that forwards packets from the external {@link TestNetworkInterface} to the internal + * {@link TestNetworkInterface} with NAT. See {@link NatPacketForwarderBase} for detail. + */ +class NatExternalPacketForwarder( + srcFd: FileDescriptor, + mtu: Int, + dstFd: FileDescriptor, + extAddr: InetAddress, + natMap: PacketBridge.NatMap +) : NatPacketForwarderBase(srcFd, mtu, dstFd, extAddr, natMap) { + + /** + * Rewrite addresses, ports and fix up checksums for packets received on the external + * interface. + * + * Incoming response from external interface which is being forwarded to the internal + * interface with translated address, e.g. 1.2.3.4:80 -> 8.8.8.8:1234 + * will be translated into 8.8.8.8:80 -> 192.168.1.1:5678. + * + * For packets that are not an incoming response, do not forward them to the + * internal interface. + */ + override fun preparePacketForForwarding(buf: ByteArray, len: Int, version: Int, proto: Int) { + val (addrPos, addrLen) = getAddressPositionAndLength(version) + + // TODO: support one external address per ip version. + val extAddrBuf = mExtAddr.address + if (addrLen != extAddrBuf.size) throw IllegalStateException("Packet IP version mismatch") + + // Get internal address by port. + val transportOffset = + if (version == 4) PacketReflector.IPV4_HEADER_LENGTH + else PacketReflector.IPV6_HEADER_LENGTH + val dstPort = getPortAt(buf, transportOffset + DESTINATION_PORT_OFFSET) + val intAddrInfo = synchronized(mNatMap) { mNatMap.fromExternalPort(dstPort) } + // No mapping, skip. This usually happens if the connection is initiated directly on + // the external interface, e.g. DNS64 resolution, network validation, etc. + if (intAddrInfo == null) return + + val intAddrBuf = intAddrInfo.address.address + val intPort = intAddrInfo.port + + // Copy the original destination to into the source address. + for (i in 0 until addrLen) { + buf[addrPos + i] = buf[addrPos + addrLen + i] + } + + // Copy the internal address into the destination address. + for (i in 0 until addrLen) { + buf[addrPos + addrLen + i] = intAddrBuf[i] + } + + // Copy the internal port into the destination port. + setPortAt(intPort, buf, transportOffset + DESTINATION_PORT_OFFSET) + + // Fix IP and Transport layer checksum. + fixPacketChecksum(buf, len, version, proto.toByte()) + } +} diff --git a/staticlibs/testutils/devicetests/com/android/testutils/NatInternalPacketForwarder.kt b/staticlibs/testutils/devicetests/com/android/testutils/NatInternalPacketForwarder.kt new file mode 100644 index 0000000000..fa39d19e1c --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/NatInternalPacketForwarder.kt @@ -0,0 +1,78 @@ +/* + * 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 com.android.testutils + +import java.io.FileDescriptor +import java.net.InetAddress + +/** + * A class that forwards packets from the internal {@link TestNetworkInterface} to the external + * {@link TestNetworkInterface} with NAT. See {@link NatPacketForwarderBase} for detail. + */ +class NatInternalPacketForwarder( + srcFd: FileDescriptor, + mtu: Int, + dstFd: FileDescriptor, + extAddr: InetAddress, + natMap: PacketBridge.NatMap +) : NatPacketForwarderBase(srcFd, mtu, dstFd, extAddr, natMap) { + + /** + * Rewrite addresses, ports and fix up checksums for packets received on the internal + * interface. + * + * Outgoing packet from the internal interface which is being forwarded to the + * external interface with translated address, e.g. 192.168.1.1:5678 -> 8.8.8.8:80 + * will be translated into 8.8.8.8:1234 -> 1.2.3.4:80. + * + * The external port, e.g. 1234 in the above example, is the port number assigned by + * the forwarder when creating the mapping to identify the source address and port when + * the response is coming from the external interface. See {@link PacketBridge.NatMap} + * for detail. + */ + override fun preparePacketForForwarding(buf: ByteArray, len: Int, version: Int, proto: Int) { + val (addrPos, addrLen) = getAddressPositionAndLength(version) + + // TODO: support one external address per ip version. + val extAddrBuf = mExtAddr.address + if (addrLen != extAddrBuf.size) throw IllegalStateException("Packet IP version mismatch") + + val srcAddr = getInetAddressAt(buf, addrPos, addrLen) + + // Copy the original destination to into the source address. + for (i in 0 until addrLen) { + buf[addrPos + i] = buf[addrPos + addrLen + i] + } + + // Copy the external address into the destination address. + for (i in 0 until addrLen) { + buf[addrPos + addrLen + i] = extAddrBuf[i] + } + + // Add an entry to NAT mapping table. + val transportOffset = + if (version == 4) PacketReflector.IPV4_HEADER_LENGTH + else PacketReflector.IPV6_HEADER_LENGTH + val srcPort = getPortAt(buf, transportOffset) + val extPort = synchronized(mNatMap) { mNatMap.toExternalPort(srcAddr, srcPort, proto) } + // Copy the external port to into the source port. + setPortAt(extPort, buf, transportOffset) + + // Fix IP and Transport layer checksum. + fixPacketChecksum(buf, len, version, proto.toByte()) + } +} diff --git a/staticlibs/testutils/devicetests/com/android/testutils/NatPacketForwarderBase.java b/staticlibs/testutils/devicetests/com/android/testutils/NatPacketForwarderBase.java new file mode 100644 index 0000000000..85c649309b --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/NatPacketForwarderBase.java @@ -0,0 +1,206 @@ +/* + * 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 com.android.testutils; + +import static com.android.testutils.PacketReflector.IPPROTO_TCP; +import static com.android.testutils.PacketReflector.IPPROTO_UDP; +import static com.android.testutils.PacketReflector.IPV4_HEADER_LENGTH; +import static com.android.testutils.PacketReflector.IPV6_HEADER_LENGTH; +import static com.android.testutils.PacketReflector.IPV6_PROTO_OFFSET; +import static com.android.testutils.PacketReflector.TCP_HEADER_LENGTH; +import static com.android.testutils.PacketReflector.UDP_HEADER_LENGTH; + +import android.annotation.NonNull; +import android.net.TestNetworkInterface; +import android.system.ErrnoException; +import android.system.Os; +import android.util.Log; + +import androidx.annotation.GuardedBy; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.InetAddress; +import java.util.Objects; + +/** + * A class that forwards packets from a {@link TestNetworkInterface} to another + * {@link TestNetworkInterface} with NAT. + * + * For testing purposes, a {@link TestNetworkInterface} provides a {@link FileDescriptor} + * which allows content injection on the test network. However, this could be hard to use + * because the callers need to compose IP packets in order to inject content to the + * test network. + * + * In order to remove the need of composing the IP packets, this class forwards IP packets to + * the {@link FileDescriptor} of another {@link TestNetworkInterface} instance. Thus, + * the TCP/IP headers could be parsed/composed automatically by the protocol stack of this + * additional {@link TestNetworkInterface}, while the payload is supplied by the + * servers run on the interface. + * + * To make it work, an internal interface and an external interface are defined, where + * the client might send packets from the internal interface which are originated from + * multiple addresses to a server that listens on the external address. + * + * When forwarding the outgoing packet on the internal interface, a simple NAT mechanism + * is implemented during forwarding, which will swap the source and destination, + * but replacing the source address with the external address, + * e.g. 192.168.1.1:1234 -> 8.8.8.8:80 will be translated into 8.8.8.8:1234 -> 1.2.3.4:80. + * + * For the above example, a client who sends http request will have a hallucination that + * it is talking to a remote server at 8.8.8.8. Also, the server listens on 1.2.3.4 will + * have a different hallucination that the request is sent from a remote client at 8.8.8.8, + * to a local address 1.2.3.4. + * + * And a NAT mapping is created at the time when the outgoing packet is forwarded. + * With a different internal source port, the instance learned that when a response with the + * destination port 1234, it should forward the packet to the internal address 192.168.1.1. + * + * For the incoming packet received from external interface, for example a http response sent + * from the http server, the same mechanism is applied but in a different direction, + * where the source and destination will be swapped, and the source address will be replaced + * with the internal address, which is obtained from the NAT mapping described above. + */ +public abstract class NatPacketForwarderBase extends Thread { + private static final String TAG = "NatPacketForwarder"; + static final int DESTINATION_PORT_OFFSET = 2; + + // The source fd to read packets from. + @NonNull + final FileDescriptor mSrcFd; + // The buffer to temporarily hold the entire packet after receiving. + @NonNull + final byte[] mBuf; + // The destination fd to write packets to. + @NonNull + final FileDescriptor mDstFd; + // The NAT mapping table shared between two NatPacketForwarder instances to map from + // the source port to the associated internal address. The map can be read/write from two + // different threads on any given time whenever receiving packets on the + // {@link TestNetworkInterface}. Thus, synchronize on the object when reading/writing is needed. + @GuardedBy("mNatMap") + @NonNull + final PacketBridge.NatMap mNatMap; + // The address of the external interface. See {@link NatPacketForwarder}. + @NonNull + final InetAddress mExtAddr; + + /** + * Construct a {@link NatPacketForwarderBase}. + * + * This class reads packets from {@code srcFd} of a {@link TestNetworkInterface}, and + * forwards them to the {@code dstFd} of another {@link TestNetworkInterface} with + * NAT applied. See {@link NatPacketForwarderBase}. + * + * To apply NAT, the address of the external interface needs to be supplied through + * {@code extAddr} to identify the external interface. And a shared NAT mapping table, + * {@code natMap} is needed to be shared between these two instances. + * + * Note that this class is not useful if the instance is not managed by a + * {@link PacketBridge} to set up a two-way communication. + * + * @param srcFd {@link FileDescriptor} to read packets from. + * @param mtu MTU of the test network. + * @param dstFd {@link FileDescriptor} to write packets to. + * @param extAddr the external address, which is the address of the external interface. + * See {@link NatPacketForwarderBase}. + * @param natMap the NAT mapping table shared between two {@link NatPacketForwarderBase} + * instance. + */ + public NatPacketForwarderBase(@NonNull FileDescriptor srcFd, int mtu, + @NonNull FileDescriptor dstFd, @NonNull InetAddress extAddr, + @NonNull PacketBridge.NatMap natMap) { + super(TAG); + mSrcFd = Objects.requireNonNull(srcFd); + mBuf = new byte[mtu]; + mDstFd = Objects.requireNonNull(dstFd); + mExtAddr = Objects.requireNonNull(extAddr); + mNatMap = Objects.requireNonNull(natMap); + } + + /** + * A method to prepare forwarding packets between two instances of {@link TestNetworkInterface}, + * which includes re-write addresses, ports and fix up checksums. + * Subclasses should override this method to implement a simple NAT. + */ + abstract void preparePacketForForwarding(@NonNull byte[] buf, int len, int version, int proto); + + private void forwardPacket(@NonNull byte[] buf, int len) { + try { + Os.write(mDstFd, buf, 0, len); + } catch (ErrnoException | IOException e) { + Log.e(TAG, "Error writing packet: " + e.getMessage()); + } + } + + // Reads one packet from mSrcFd, and writes the packet to the mDstFd for supported protocols. + private void processPacket() { + final int len = PacketReflectorUtil.readPacket(mSrcFd, mBuf); + if (len < 1) { + throw new IllegalStateException("Unexpected buffer length: " + len); + } + + final int version = mBuf[0] >>> 4; + final int protoPos, ipHdrLen; + switch (version) { + case 4: + ipHdrLen = IPV4_HEADER_LENGTH; + protoPos = PacketReflector.IPV4_PROTO_OFFSET; + break; + case 6: + ipHdrLen = IPV6_HEADER_LENGTH; + protoPos = IPV6_PROTO_OFFSET; + break; + default: + throw new IllegalStateException("Unexpected version: " + version); + } + if (len < ipHdrLen) { + throw new IllegalStateException("Unexpected buffer length: " + len); + } + + final byte proto = mBuf[protoPos]; + final int transportHdrLen; + switch (proto) { + case IPPROTO_TCP: + transportHdrLen = TCP_HEADER_LENGTH; + break; + case IPPROTO_UDP: + transportHdrLen = UDP_HEADER_LENGTH; + break; + // TODO: Support ICMP. + default: + return; // Unknown protocol, ignored. + } + + if (len < ipHdrLen + transportHdrLen) { + throw new IllegalStateException("Unexpected buffer length: " + len); + } + // Re-write addresses, ports and fix up checksums. + preparePacketForForwarding(mBuf, len, version, proto); + // Send the packet to the destination fd. + forwardPacket(mBuf, len); + } + + @Override + public void run() { + Log.i(TAG, "starting fd=" + mSrcFd + " valid=" + mSrcFd.valid()); + while (!interrupted() && mSrcFd.valid()) { + processPacket(); + } + Log.i(TAG, "exiting fd=" + mSrcFd + " valid=" + mSrcFd.valid()); + } +} diff --git a/staticlibs/testutils/devicetests/com/android/testutils/PacketBridge.kt b/staticlibs/testutils/devicetests/com/android/testutils/PacketBridge.kt new file mode 100644 index 0000000000..da3508dec2 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/PacketBridge.kt @@ -0,0 +1,173 @@ +/* + * 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 com.android.testutils + +import android.content.Context +import android.net.ConnectivityManager +import android.net.LinkAddress +import android.net.LinkProperties +import android.net.Network +import android.net.NetworkCapabilities +import android.net.NetworkRequest +import android.net.TestNetworkInterface +import android.net.TestNetworkManager +import android.net.TestNetworkSpecifier +import android.os.Binder +import com.android.testutils.RecorderCallback.CallbackEntry.Available +import java.net.InetAddress +import libcore.io.IoUtils + +private const val MIN_PORT_NUMBER = 1025 +private const val MAX_PORT_NUMBER = 65535 + +/** + * A class that set up two {@link TestNetworkInterface} with NAT, and forward packets between them. + * + * See {@link NatPacketForwarder} for more detailed information. + */ +class PacketBridge( + context: Context, + internalAddr: LinkAddress, + externalAddr: LinkAddress, + dnsAddr: InetAddress +) { + private val natMap = NatMap() + private val binder = Binder() + + private val cm = context.getSystemService(ConnectivityManager::class.java) + private val tnm = context.getSystemService(TestNetworkManager::class.java) + + // Create test networks. + private val internalIface = tnm.createTunInterface(listOf(internalAddr)) + private val externalIface = tnm.createTunInterface(listOf(externalAddr)) + + // Register test networks to ConnectivityService. + private val internalNetworkCallback: TestableNetworkCallback + private val externalNetworkCallback: TestableNetworkCallback + val internalNetwork: Network + val externalNetwork: Network + init { + val (inCb, inNet) = createTestNetwork(internalIface, internalAddr, dnsAddr) + val (exCb, exNet) = createTestNetwork(externalIface, externalAddr, dnsAddr) + internalNetworkCallback = inCb + externalNetworkCallback = exCb + internalNetwork = inNet + externalNetwork = exNet + } + + // Setup the packet bridge. + private val internalFd = internalIface.fileDescriptor.fileDescriptor + private val externalFd = externalIface.fileDescriptor.fileDescriptor + + private val pr1 = NatInternalPacketForwarder( + internalFd, + 1500, + externalFd, + externalAddr.address, + natMap + ) + private val pr2 = NatExternalPacketForwarder( + externalFd, + 1500, + internalFd, + externalAddr.address, + natMap + ) + + fun start() { + IoUtils.setBlocking(internalFd, true /* blocking */) + IoUtils.setBlocking(externalFd, true /* blocking */) + pr1.start() + pr2.start() + } + + fun stop() { + pr1.interrupt() + pr2.interrupt() + cm.unregisterNetworkCallback(internalNetworkCallback) + cm.unregisterNetworkCallback(externalNetworkCallback) + } + + /** + * Creates a test network with given test TUN interface and addresses. + */ + private fun createTestNetwork( + testIface: TestNetworkInterface, + addr: LinkAddress, + dnsAddr: InetAddress + ): Pair { + // Make a network request to hold the test network + val nr = NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .setNetworkSpecifier(TestNetworkSpecifier(testIface.interfaceName)) + .build() + val testCb = TestableNetworkCallback() + cm.requestNetwork(nr, testCb) + + val lp = LinkProperties().apply { + addLinkAddress(addr) + interfaceName = testIface.interfaceName + addDnsServer(dnsAddr) + } + tnm.setupTestNetwork(lp, true /* isMetered */, binder) + + // Wait for available before return. + val network = testCb.expect().network + return testCb to network + } + + /** + * A helper class to maintain the mappings between internal addresses/ports and external + * ports. + * + * This class assigns an unused external port number if the mapping between + * srcaddress:srcport:protocol and the external port does not exist yet. + * + * Note that this class is not thread-safe. The instance of the class needs to be + * synchronized in the callers when being used in multiple threads. + */ + class NatMap { + data class AddressInfo(val address: InetAddress, val port: Int, val protocol: Int) + + private val mToExternalPort = HashMap() + private val mFromExternalPort = HashMap() + + // Skip well-known port 0~1024. + private var nextExternalPort = MIN_PORT_NUMBER + + fun toExternalPort(addr: InetAddress, port: Int, protocol: Int): Int { + val info = AddressInfo(addr, port, protocol) + val extPort: Int + if (!mToExternalPort.containsKey(info)) { + extPort = nextExternalPort++ + if (nextExternalPort > MAX_PORT_NUMBER) { + throw IllegalStateException("Available ports are exhausted") + } + mToExternalPort[info] = extPort + mFromExternalPort[extPort] = info + } else { + extPort = mToExternalPort[info]!! + } + return extPort + } + + fun fromExternalPort(port: Int): AddressInfo? { + return mFromExternalPort[port] + } + } +} diff --git a/staticlibs/testutils/devicetests/com/android/testutils/PacketReflector.java b/staticlibs/testutils/devicetests/com/android/testutils/PacketReflector.java index 96bca624d6..a59750d5e2 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/PacketReflector.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/PacketReflector.java @@ -26,40 +26,43 @@ import android.util.Log; import java.io.FileDescriptor; import java.io.IOException; +import java.util.Objects; public class PacketReflector extends Thread { - private static final int IPV4_HEADER_LENGTH = 20; - private static final int IPV6_HEADER_LENGTH = 40; + static final int IPV4_HEADER_LENGTH = 20; + static final int IPV6_HEADER_LENGTH = 40; - private static final int IPV4_ADDR_OFFSET = 12; - private static final int IPV6_ADDR_OFFSET = 8; - private static final int IPV4_ADDR_LENGTH = 4; - private static final int IPV6_ADDR_LENGTH = 16; + static final int IPV4_ADDR_OFFSET = 12; + static final int IPV6_ADDR_OFFSET = 8; + static final int IPV4_ADDR_LENGTH = 4; + static final int IPV6_ADDR_LENGTH = 16; - private static final int IPV4_PROTO_OFFSET = 9; - private static final int IPV6_PROTO_OFFSET = 6; + static final int IPV4_PROTO_OFFSET = 9; + static final int IPV6_PROTO_OFFSET = 6; - private static final byte IPPROTO_ICMP = 1; - private static final byte IPPROTO_TCP = 6; - private static final byte IPPROTO_UDP = 17; + static final byte IPPROTO_ICMP = 1; + static final byte IPPROTO_TCP = 6; + static final byte IPPROTO_UDP = 17; private static final byte IPPROTO_ICMPV6 = 58; private static final int ICMP_HEADER_LENGTH = 8; - private static final int TCP_HEADER_LENGTH = 20; - private static final int UDP_HEADER_LENGTH = 8; + static final int TCP_HEADER_LENGTH = 20; + static final int UDP_HEADER_LENGTH = 8; private static final byte ICMP_ECHO = 8; private static final byte ICMP_ECHOREPLY = 0; private static String TAG = "PacketReflector"; - @NonNull private FileDescriptor mFd; - @NonNull private byte[] mBuf; + @NonNull + private final FileDescriptor mFd; + @NonNull + private final byte[] mBuf; public PacketReflector(@NonNull FileDescriptor fd, int mtu) { super("PacketReflector"); - mFd = fd; + mFd = Objects.requireNonNull(fd); mBuf = new byte[mtu]; } @@ -140,7 +143,7 @@ public class PacketReflector extends Thread { writePacket(buf, len); // The device should have replied, and buf should now contain a ping response. - int received = readPacket(buf); + int received = PacketReflectorUtil.readPacket(mFd, buf); if (received != len) { Log.i(TAG, "Reflecting ping did not result in ping response: " + "read=" + received + " expected=" + len); @@ -190,21 +193,11 @@ public class PacketReflector extends Thread { } } - private int readPacket(@NonNull byte[] buf) { - int len; - try { - len = Os.read(mFd, buf, 0, buf.length); - } catch (ErrnoException | IOException e) { - Log.e(TAG, "Error reading packet: " + e.getMessage()); - len = -1; - } - return len; - } - // Reads one packet from our mFd, and possibly writes the packet back. private void processPacket() { - int len = readPacket(mBuf); + int len = PacketReflectorUtil.readPacket(mFd, mBuf); if (len < 1) { + // Usually happens when socket read is being interrupted, e.g. stopping PacketReflector. return; } @@ -217,11 +210,11 @@ public class PacketReflector extends Thread { hdrLen = IPV6_HEADER_LENGTH; protoPos = IPV6_PROTO_OFFSET; } else { - return; + throw new IllegalStateException("Unexpected version: " + version); } if (len < hdrLen) { - return; + throw new IllegalStateException("Unexpected buffer length: " + len); } byte proto = mBuf[protoPos]; @@ -241,10 +234,10 @@ public class PacketReflector extends Thread { } public void run() { - Log.i(TAG, "PacketReflector starting fd=" + mFd + " valid=" + mFd.valid()); + Log.i(TAG, "starting fd=" + mFd + " valid=" + mFd.valid()); while (!interrupted() && mFd.valid()) { processPacket(); } - Log.i(TAG, "PacketReflector exiting fd=" + mFd + " valid=" + mFd.valid()); + Log.i(TAG, "exiting fd=" + mFd + " valid=" + mFd.valid()); } } diff --git a/staticlibs/testutils/devicetests/com/android/testutils/PacketReflectorUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/PacketReflectorUtil.kt new file mode 100644 index 0000000000..b028045450 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/PacketReflectorUtil.kt @@ -0,0 +1,106 @@ +/* + * 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. + */ + +@file:JvmName("PacketReflectorUtil") + +package com.android.testutils + +import android.system.ErrnoException +import android.system.Os +import com.android.net.module.util.IpUtils +import com.android.testutils.PacketReflector.IPV4_HEADER_LENGTH +import com.android.testutils.PacketReflector.IPV6_HEADER_LENGTH +import java.io.FileDescriptor +import java.io.IOException +import java.net.InetAddress +import java.nio.ByteBuffer + +fun readPacket(fd: FileDescriptor, buf: ByteArray): Int { + return try { + Os.read(fd, buf, 0, buf.size) + } catch (e: ErrnoException) { + -1 + } catch (e: IOException) { + -1 + } +} + +fun getInetAddressAt(buf: ByteArray, pos: Int, len: Int): InetAddress = + InetAddress.getByAddress(buf.copyOfRange(pos, pos + len)) + +/** + * Reads a 16-bit unsigned int at pos in big endian, with no alignment requirements. + */ +fun getPortAt(buf: ByteArray, pos: Int): Int { + return (buf[pos].toInt() and 0xff shl 8) + (buf[pos + 1].toInt() and 0xff) +} + +fun setPortAt(port: Int, buf: ByteArray, pos: Int) { + buf[pos] = (port ushr 8).toByte() + buf[pos + 1] = (port and 0xff).toByte() +} + +fun getAddressPositionAndLength(version: Int) = when (version) { + 4 -> PacketReflector.IPV4_ADDR_OFFSET to PacketReflector.IPV4_ADDR_LENGTH + 6 -> PacketReflector.IPV6_ADDR_OFFSET to PacketReflector.IPV6_ADDR_LENGTH + else -> throw IllegalArgumentException("Unknown IP version $version") +} + +private const val IPV4_CHKSUM_OFFSET = 10 +private const val UDP_CHECKSUM_OFFSET = 6 +private const val TCP_CHECKSUM_OFFSET = 16 + +fun fixPacketChecksum(buf: ByteArray, len: Int, version: Int, protocol: Byte) { + // Fill Ip checksum for IPv4. IPv6 header doesn't have a checksum field. + if (version == 4) { + val checksum = IpUtils.ipChecksum(ByteBuffer.wrap(buf), 0) + // Place checksum in Big-endian order. + buf[IPV4_CHKSUM_OFFSET] = (checksum.toInt() ushr 8).toByte() + buf[IPV4_CHKSUM_OFFSET + 1] = (checksum.toInt() and 0xff).toByte() + } + + // Fill transport layer checksum. + val transportOffset = if (version == 4) IPV4_HEADER_LENGTH else IPV6_HEADER_LENGTH + when (protocol) { + PacketReflector.IPPROTO_UDP -> { + val checksumPos = transportOffset + UDP_CHECKSUM_OFFSET + // Clear before calculate. + buf[checksumPos + 1] = 0x00 + buf[checksumPos] = buf[checksumPos + 1] + val checksum = IpUtils.udpChecksum( + ByteBuffer.wrap(buf), 0, + transportOffset + ) + buf[checksumPos] = (checksum.toInt() ushr 8).toByte() + buf[checksumPos + 1] = (checksum.toInt() and 0xff).toByte() + } + PacketReflector.IPPROTO_TCP -> { + val checksumPos = transportOffset + TCP_CHECKSUM_OFFSET + // Clear before calculate. + buf[checksumPos + 1] = 0x00 + buf[checksumPos] = buf[checksumPos + 1] + val transportLen: Int = len - transportOffset + val checksum = IpUtils.tcpChecksum( + ByteBuffer.wrap(buf), 0, transportOffset, + transportLen + ) + buf[checksumPos] = (checksum.toInt() ushr 8).toByte() + buf[checksumPos + 1] = (checksum.toInt() and 0xff).toByte() + } + // TODO: Support ICMP. + else -> throw IllegalArgumentException("Unsupported protocol: $protocol") + } +} From 8fef4f726af7624f49c9220e3cd84b7a4e07741a Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 20 Mar 2023 10:17:05 +0800 Subject: [PATCH 665/777] [ST06.2] Read http body for PUT or POST http request Currently, the test http server will respond whenever http request is read, no matter how much data was declared in the Content-Length header. For tests that uses POST request to test uplink traffic this is not good enough. Invoke parseBody to read data from input stream to make sure the http body is read. Test: atest android.net.NetworkStatsIntegrationTest \ --rerun-until-failure 100 Bug: 139774492 Change-Id: I1b71f3e55747d104e4a8796611517d93f178321f --- .../com/android/testutils/TestHttpServer.kt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt index 39ce4872ae..740bf63a10 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestHttpServer.kt @@ -19,6 +19,7 @@ package com.android.testutils import android.net.Uri import com.android.net.module.util.ArrayTrackRecord import fi.iki.elonen.NanoHTTPD +import java.io.IOException /** * A minimal HTTP server running on a random available port. @@ -82,7 +83,23 @@ class TestHttpServer(host: String? = null) : NanoHTTPD(host, 0 /* auto-select th val request = Request(session.uri ?: "", session.method, session.queryParameterString ?: "") requestsRecord.add(request) + + // For PUT and POST, call parseBody to read InputStream before responding. + if (Method.PUT == session.method || Method.POST == session.method) { + try { + session.parseBody(HashMap()) + } catch (e: Exception) { + when (e) { + is IOException, is ResponseException -> e.toResponse() + else -> throw e + } + } + } + // Default response is a 404 return responses[request] ?: super.serve(session) } -} \ No newline at end of file + + fun Exception.toResponse() = + newFixedLengthResponse(Response.Status.INTERNAL_ERROR, "text/plain", this.toString()) +} From 63ff33b9e054af76c071aebf47a1dbf43d2d3569 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 23 Mar 2023 10:30:24 +0800 Subject: [PATCH 666/777] [ST07] Add more documentation for PacketReflector Test: TH Bug: 139774492 Change-Id: I778a8392a01806da313335b8103d27295b3e96e4 --- .../android/testutils/PacketReflector.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/PacketReflector.java b/staticlibs/testutils/devicetests/com/android/testutils/PacketReflector.java index a59750d5e2..69392d444e 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/PacketReflector.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/PacketReflector.java @@ -20,6 +20,7 @@ import static android.system.OsConstants.ICMP6_ECHO_REPLY; import static android.system.OsConstants.ICMP6_ECHO_REQUEST; import android.annotation.NonNull; +import android.net.TestNetworkInterface; import android.system.ErrnoException; import android.system.Os; import android.util.Log; @@ -28,6 +29,19 @@ import java.io.FileDescriptor; import java.io.IOException; import java.util.Objects; +/** + * A class that echoes packets received on a {@link TestNetworkInterface} back to itself. + * + * For testing purposes, sometimes a mocked environment to simulate a simple echo from the + * server side is needed. This is particularly useful if the test, e.g. VpnTest, is + * heavily relying on the outside world. + * + * This class reads packets from the {@link FileDescriptor} of a {@link TestNetworkInterface}, and: + * 1. For TCP and UDP packets, simply swaps the source address and the destination + * address, then send it back to the {@link FileDescriptor}. + * 2. For ICMP ping packets, composes a ping reply and sends it back to the sender. + * 3. Ignore all other packets. + */ public class PacketReflector extends Thread { static final int IPV4_HEADER_LENGTH = 20; @@ -60,6 +74,13 @@ public class PacketReflector extends Thread { @NonNull private final byte[] mBuf; + /** + * Construct a {@link PacketReflector} from the given {@code fd} of + * a {@link TestNetworkInterface}. + * + * @param fd {@link FileDescriptor} to read/write packets. + * @param mtu MTU of the test network. + */ public PacketReflector(@NonNull FileDescriptor fd, int mtu) { super("PacketReflector"); mFd = Objects.requireNonNull(fd); From 59e343367ad4d7425dca716f275bc6aaf85657ab Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 29 Mar 2023 00:12:36 +0000 Subject: [PATCH 667/777] bpf_headers: add bpf_probe_read_user_str Bug: 269407130 Test: N/A Change-Id: I735bffefd41ea3edcafd846041f8c237e860ee6c --- staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 36865f33db..0300b5ec8c 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -305,6 +305,7 @@ unsigned long long load_word(void* skb, unsigned long long off) asm("llvm.bpf.lo static int (*bpf_probe_read)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read; static int (*bpf_probe_read_str)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read_str; +static int (*bpf_probe_read_user_str)(void* dst, int size, const void* unsafe_ptr) = (void*) BPF_FUNC_probe_read_user_str; static unsigned long long (*bpf_ktime_get_ns)(void) = (void*) BPF_FUNC_ktime_get_ns; static unsigned long long (*bpf_ktime_get_boot_ns)(void) = (void*)BPF_FUNC_ktime_get_boot_ns; static int (*bpf_trace_printk)(const char* fmt, int fmt_size, ...) = (void*) BPF_FUNC_trace_printk; From b56b9f2dccb64989d81cecc899c5aead0c09efb9 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 31 Mar 2023 21:06:02 +0900 Subject: [PATCH 668/777] Add util to compare getAllAddresses Bug: 269715746 Test: New test in this patch Change-Id: I243940df693d984a8adfa5c55b49088f7d8bc5ff --- .../net/module/util/LinkPropertiesUtils.java | 18 ++++++++++++++++++ .../module/util/LinkPropertiesUtilsTest.java | 15 +++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java b/staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java index 1565f2bc2f..e271f64902 100644 --- a/staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java +++ b/staticlibs/framework/com/android/net/module/util/LinkPropertiesUtils.java @@ -146,6 +146,24 @@ public final class LinkPropertiesUtils { right != null ? right.getLinkAddresses() : null); } + /** + * Compares {@code left} {@code LinkProperties} allLinkAddresses against the {@code right}. + * + * @param left A LinkProperties or null + * @param right A LinkProperties or null + * @return {@code true} if both are identical, {@code false} otherwise. + * @see LinkProperties#getAllLinkAddresses() + */ + public static boolean isIdenticalAllLinkAddresses(@Nullable LinkProperties left, + @Nullable LinkProperties right) { + if (left == right) return true; + if (left == null || right == null) return false; + final List leftAddresses = left.getAllLinkAddresses(); + final List rightAddresses = right.getAllLinkAddresses(); + if (leftAddresses.size() != rightAddresses.size()) return false; + return leftAddresses.containsAll(rightAddresses); + } + /** * Compares {@code left} {@code LinkProperties} interface addresses against the {@code right}. * diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java index 09f0490283..80ab618532 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/LinkPropertiesUtilsTest.java @@ -94,6 +94,9 @@ public final class LinkPropertiesUtilsTest { assertTrue(LinkPropertiesUtils.isIdenticalAddresses(source, target)); assertTrue(LinkPropertiesUtils.isIdenticalAddresses(target, source)); + assertTrue(LinkPropertiesUtils.isIdenticalAllLinkAddresses(source, target)); + assertTrue(LinkPropertiesUtils.isIdenticalAllLinkAddresses(target, source)); + assertTrue(LinkPropertiesUtils.isIdenticalDnses(source, target)); assertTrue(LinkPropertiesUtils.isIdenticalDnses(target, source)); @@ -116,12 +119,17 @@ public final class LinkPropertiesUtilsTest { assertFalse(LinkPropertiesUtils.isIdenticalAddresses(source, target)); assertFalse(LinkPropertiesUtils.isIdenticalAddresses(target, source)); + assertFalse(LinkPropertiesUtils.isIdenticalAllLinkAddresses(source, target)); + assertFalse(LinkPropertiesUtils.isIdenticalAllLinkAddresses(target, source)); + // Currently, target contains V4_LINKADDR, V6_LINKADDR and testLinkAddr. // Compare addresses.size() equals but contains different address. target.removeLinkAddress(V4_LINKADDR); assertEquals(source.getAddresses().size(), target.getAddresses().size()); assertFalse(LinkPropertiesUtils.isIdenticalAddresses(source, target)); assertFalse(LinkPropertiesUtils.isIdenticalAddresses(target, source)); + assertFalse(LinkPropertiesUtils.isIdenticalAllLinkAddresses(source, target)); + assertFalse(LinkPropertiesUtils.isIdenticalAllLinkAddresses(target, source)); // Restore link address target.addLinkAddress(V4_LINKADDR); target.removeLinkAddress(testLinkAddr); @@ -169,6 +177,13 @@ public final class LinkPropertiesUtilsTest { target.setHttpProxy(null); assertFalse(LinkPropertiesUtils.isIdenticalHttpProxy(source, target)); assertFalse(LinkPropertiesUtils.isIdenticalHttpProxy(target, source)); + + final LinkProperties stacked = new LinkProperties(); + stacked.setInterfaceName("v4-" + target.getInterfaceName()); + stacked.addLinkAddress(testLinkAddr); + target.addStackedLink(stacked); + assertFalse(LinkPropertiesUtils.isIdenticalAllLinkAddresses(source, target)); + assertFalse(LinkPropertiesUtils.isIdenticalAllLinkAddresses(target, source)); } private void compareResult(List oldItems, List newItems, List expectRemoved, From 6559a91e3e13a3b5551099910d552070b2e43d74 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Sun, 2 Apr 2023 17:01:09 +0900 Subject: [PATCH 669/777] Add constants for a DHCP packet maximum length and maximum option length. Bug: 260934173 Test: m Change-Id: I484a7a04c73906b11edb70e1053ee7f3172e8ffd --- .../com/android/net/module/util/NetworkStackConstants.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 1d88d6ef86..aa2dd4c1c8 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -208,6 +208,9 @@ public final class NetworkStackConstants { */ public static final int INFINITE_LEASE = 0xffffffff; public static final int DHCP4_CLIENT_PORT = 68; + // The maximum length of a DHCP packet that can be constructed. + public static final int DHCP_MAX_LENGTH = 1500; + public static final int DHCP_MAX_OPTION_LEN = 255; /** * DHCPv6 constants. From fb914d8226d0928b3767a2cf43d5f622409eb1c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 4 Apr 2023 22:24:18 +0000 Subject: [PATCH 670/777] update comment about synchronizeKernelRCU() still working MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since it just came up again, and I just verified this still works Test: N/A Signed-off-by: Maciej Żenczykowski Change-Id: I292c94cf9af63488ed30a6ac367ac83c8912e97e --- staticlibs/native/bpf_headers/include/bpf/BpfUtils.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index 206acba921..99c7a91da9 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -63,8 +63,9 @@ static inline int synchronizeKernelRCU() { // 4.9 kernels. The kernel code of socket release on pf_key socket will // explicitly call synchronize_rcu() which is exactly what we need. // - // Linux 4.14/4.19/5.4/5.10/5.15 (and 5.18) still have this same behaviour. + // Linux 4.14/4.19/5.4/5.10/5.15/6.1 (and 6.3-rc5) still have this same behaviour. // see net/key/af_key.c: pfkey_release() -> synchronize_rcu() + // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/key/af_key.c?h=v6.3-rc5#n185 const int pfSocket = socket(AF_KEY, SOCK_RAW | SOCK_CLOEXEC, PF_KEY_V2); if (pfSocket < 0) { From f67388b0ff63d90535a0788dddde9aba3f477c9e Mon Sep 17 00:00:00 2001 From: Yuyang Huang Date: Wed, 29 Mar 2023 16:51:09 +0900 Subject: [PATCH 671/777] Add a build rule for files used by mdns mdns may be imported in other non-AOSP projects as a library, along with its dependencies from net-utils-device-common. While all of net-utils-device-common may not build against system API, this requires the files used by mdns to build against system API. Add a library to allow checking that the dependencies can still build against system API. Test: m Bug: 272392042 Change-Id: I468f53b47ef55c23137594a79599b148084f4535 --- staticlibs/Android.bp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 1fe6c2cc2b..904e8c6725 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -328,6 +328,38 @@ java_library { lint: { strict_updatability_linting: true }, } +// Limited set of utilities for use by service-connectivity-mdns-standalone-build-test, to make sure +// the mDNS code can build with only system APIs. +// The mDNS code is platform code so it should use framework-annotations-lib, contrary to apps that +// should use sdk_version: "system_current" and only androidx.annotation_annotation. But this build +// rule verifies that the mDNS code can be built into apps, if code transformations are applied to +// the annotations. +// When using "system_current", framework annotations are not available; they would appear as +// package-private as they are marked as such in the system_current stubs. So build against +// core_platform and add the stubs manually in "libs". See http://b/147773144#comment7. +java_library { + name: "net-utils-device-common-mdns-standalone-build-test", + // Build against core_platform and add the stub libraries manually in "libs", as annotations + // are already included in android_system_stubs_current but package-private, so + // "framework-annotations-lib" needs to be manually included before + // "android_system_stubs_current" (b/272392042) + sdk_version: "core_platform", + srcs: [ + "device/com/android/net/module/util/FdEventsReader.java", + "device/com/android/net/module/util/HexDump.java", + "device/com/android/net/module/util/SharedLog.java", + "framework/com/android/net/module/util/ByteUtils.java", + "framework/com/android/net/module/util/CollectionUtils.java", + "framework/com/android/net/module/util/LinkPropertiesUtils.java", + ], + libs: [ + "framework-annotations-lib", + "android_system_stubs_current", + "androidx.annotation_annotation", + ], + visibility: ["//packages/modules/Connectivity/service-t"], +} + // Use a filegroup and not a library for telephony sources, as framework-annotations cannot be // included either (some annotations would be duplicated on the bootclasspath). filegroup { From 80c53fa4fd4adbe7449654100bd1fb87373ba5d1 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Wed, 22 Feb 2023 18:37:43 +0900 Subject: [PATCH 672/777] Update StructInetDiagMsg to parse all the fields Bug: 270298713 Test: atest NetworkStaticLibTests Change-Id: I782eca50b6db6dca88ee933edb5d5d19223886dd --- .../util/netlink/StructInetDiagMsg.java | 48 +++++++++++++------ .../util/netlink/StructInetDiagSockId.java | 2 +- .../util/netlink/InetDiagSocketTest.java | 48 ++++++++++++------- 3 files changed, 66 insertions(+), 32 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagMsg.java index e7fc02f604..cbd895d66d 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagMsg.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagMsg.java @@ -43,14 +43,22 @@ import java.nio.ByteBuffer; */ public class StructInetDiagMsg { public static final int STRUCT_SIZE = 4 + StructInetDiagSockId.STRUCT_SIZE + 20; - // Offset to the id field from the beginning of inet_diag_msg struct - private static final int IDIAG_SOCK_ID_OFFSET = 4; - // Offset to the idiag_uid field from the beginning of inet_diag_msg struct - private static final int IDIAG_UID_OFFSET = - IDIAG_SOCK_ID_OFFSET + StructInetDiagSockId.STRUCT_SIZE + 12; - public int idiag_uid; + public short idiag_family; + public short idiag_state; + public short idiag_timer; + public short idiag_retrans; @NonNull public StructInetDiagSockId id; + public long idiag_expires; + public long idiag_rqueue; + public long idiag_wqueue; + // Use int for uid since other code use int for uid and uid fits to int + public int idiag_uid; + public long idiag_inode; + + private static short unsignedByte(byte b) { + return (short) (b & 0xFF); + } /** * Parse inet diag netlink message from buffer. @@ -60,26 +68,36 @@ public class StructInetDiagMsg { if (byteBuffer.remaining() < STRUCT_SIZE) { return null; } - final int baseOffset = byteBuffer.position(); StructInetDiagMsg struct = new StructInetDiagMsg(); - final byte family = byteBuffer.get(); - byteBuffer.position(baseOffset + IDIAG_SOCK_ID_OFFSET); - struct.id = StructInetDiagSockId.parse(byteBuffer, family); + struct.idiag_family = unsignedByte(byteBuffer.get()); + struct.idiag_state = unsignedByte(byteBuffer.get()); + struct.idiag_timer = unsignedByte(byteBuffer.get()); + struct.idiag_retrans = unsignedByte(byteBuffer.get()); + struct.id = StructInetDiagSockId.parse(byteBuffer, struct.idiag_family); if (struct.id == null) { return null; } - struct.idiag_uid = byteBuffer.getInt(baseOffset + IDIAG_UID_OFFSET); - - // Move position to the end of the inet_diag_msg - byteBuffer.position(baseOffset + STRUCT_SIZE); + struct.idiag_expires = Integer.toUnsignedLong(byteBuffer.getInt()); + struct.idiag_rqueue = Integer.toUnsignedLong(byteBuffer.getInt()); + struct.idiag_wqueue = Integer.toUnsignedLong(byteBuffer.getInt()); + struct.idiag_uid = byteBuffer.getInt(); + struct.idiag_inode = Integer.toUnsignedLong(byteBuffer.getInt()); return struct; } @Override public String toString() { return "StructInetDiagMsg{ " - + "idiag_uid{" + idiag_uid + "}, " + + "idiag_family{" + idiag_family + "}, " + + "idiag_state{" + idiag_state + "}, " + + "idiag_timer{" + idiag_timer + "}, " + + "idiag_retrans{" + idiag_retrans + "}, " + "id{" + id + "}, " + + "idiag_expires{" + idiag_expires + "}, " + + "idiag_rqueue{" + idiag_rqueue + "}, " + + "idiag_wqueue{" + idiag_wqueue + "}, " + + "idiag_uid{" + idiag_uid + "}, " + + "idiag_inode{" + idiag_inode + "}, " + "}"; } } diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java index 648a020188..1e728ea571 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java @@ -80,7 +80,7 @@ public class StructInetDiagSockId { * Parse inet diag socket id from buffer. */ @Nullable - public static StructInetDiagSockId parse(final ByteBuffer byteBuffer, final byte family) { + public static StructInetDiagSockId parse(final ByteBuffer byteBuffer, final short family) { if (byteBuffer.remaining() < STRUCT_SIZE) { return null; } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java index d81422fbb9..6837c83f8b 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java @@ -248,9 +248,9 @@ public class InetDiagSocketTest { "f5220000" + // pid // struct inet_diag_msg "0a" + // family = AF_INET6 - "01" + // idiag_state - "00" + // idiag_timer - "00" + // idiag_retrans + "01" + // idiag_state = 1 + "02" + // idiag_timer = 2 + "ff" + // idiag_retrans = 255 // inet_diag_sockid "a817" + // idiag_sport = 43031 "960f" + // idiag_dport = 38415 @@ -258,11 +258,11 @@ public class InetDiagSocketTest { "20010db8000000000000000000000002" + // idiag_dst = 2001:db8::2 "07000000" + // idiag_if = 7 "5800000000000000" + // idiag_cookie = 88 - "00000000" + // idiag_expires - "00000000" + // idiag_rqueue - "00000000" + // idiag_wqueue + "04000000" + // idiag_expires = 4 + "05000000" + // idiag_rqueue = 5 + "06000000" + // idiag_wqueue = 6 "a3270000" + // idiag_uid = 10147 - "A57E1900"; // idiag_inode + "a57e19f0"; // idiag_inode = 4028202661 private void assertInetDiagMsg1(final NetlinkMessage msg) { assertNotNull(msg); @@ -276,12 +276,20 @@ public class InetDiagSocketTest { 0 /* seq */, 8949 /* pid */); - assertEquals(10147, inetDiagMsg.inetDiagMsg.idiag_uid); + assertEquals(AF_INET6, inetDiagMsg.inetDiagMsg.idiag_family); + assertEquals(1, inetDiagMsg.inetDiagMsg.idiag_state); + assertEquals(2, inetDiagMsg.inetDiagMsg.idiag_timer); + assertEquals(255, inetDiagMsg.inetDiagMsg.idiag_retrans); assertInetDiagSockId(inetDiagMsg.inetDiagMsg.id, new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::1"), 43031), new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::2"), 38415), 7 /* ifIndex */, 88 /* cookie */); + assertEquals(4, inetDiagMsg.inetDiagMsg.idiag_expires); + assertEquals(5, inetDiagMsg.inetDiagMsg.idiag_rqueue); + assertEquals(6, inetDiagMsg.inetDiagMsg.idiag_wqueue); + assertEquals(10147, inetDiagMsg.inetDiagMsg.idiag_uid); + assertEquals(4028202661L, inetDiagMsg.inetDiagMsg.idiag_inode); } // Hexadecimal representation of InetDiagMessage @@ -294,9 +302,9 @@ public class InetDiagSocketTest { "f5220000" + // pid // struct inet_diag_msg "0a" + // family = AF_INET6 - "01" + // idiag_state - "00" + // idiag_timer - "00" + // idiag_retrans + "02" + // idiag_state = 2 + "10" + // idiag_timer = 16 + "20" + // idiag_retrans = 32 // inet_diag_sockid "a845" + // idiag_sport = 43077 "01bb" + // idiag_dport = 443 @@ -304,11 +312,11 @@ public class InetDiagSocketTest { "20010db8000000000000000000000004" + // idiag_dst = 2001:db8::4 "08000000" + // idiag_if = 8 "6300000000000000" + // idiag_cookie = 99 - "00000000" + // idiag_expires - "00000000" + // idiag_rqueue - "00000000" + // idiag_wqueue + "30000000" + // idiag_expires = 48 + "40000000" + // idiag_rqueue = 64 + "50000000" + // idiag_wqueue = 80 "39300000" + // idiag_uid = 12345 - "A57E1900"; // idiag_inode + "851a0000"; // idiag_inode = 6789 private void assertInetDiagMsg2(final NetlinkMessage msg) { assertNotNull(msg); @@ -322,12 +330,20 @@ public class InetDiagSocketTest { 0 /* seq */, 8949 /* pid */); - assertEquals(12345, inetDiagMsg.inetDiagMsg.idiag_uid); + assertEquals(AF_INET6, inetDiagMsg.inetDiagMsg.idiag_family); + assertEquals(2, inetDiagMsg.inetDiagMsg.idiag_state); + assertEquals(16, inetDiagMsg.inetDiagMsg.idiag_timer); + assertEquals(32, inetDiagMsg.inetDiagMsg.idiag_retrans); assertInetDiagSockId(inetDiagMsg.inetDiagMsg.id, new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::3"), 43077), new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::4"), 443), 8 /* ifIndex */, 99 /* cookie */); + assertEquals(48, inetDiagMsg.inetDiagMsg.idiag_expires); + assertEquals(64, inetDiagMsg.inetDiagMsg.idiag_rqueue); + assertEquals(80, inetDiagMsg.inetDiagMsg.idiag_wqueue); + assertEquals(12345, inetDiagMsg.inetDiagMsg.idiag_uid); + assertEquals(6789, inetDiagMsg.inetDiagMsg.idiag_inode); } private static final byte[] INET_DIAG_MSG_BYTES = From 64a711a618c7bed688977ebc0b4372d5b65f2344 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Thu, 2 Mar 2023 12:29:15 +0900 Subject: [PATCH 673/777] Fix StructInetDiagSockId parsing for v4-mapped v6 address Before this CL, StructInetDiagSockId.parse convert v4-mapped v6 address to Inet4Address that is inconsistent with the value in inet_diag_msg.idiag_family. Also, due to this behavior, input of parse and output of pack could be different. This is the issue specifically when SOCK_DESTROY request is populated based on the InetDiagMessage from the kernel. Bug: 270298713 Test: atest NetworkStaticLibTests Change-Id: I45256bb1069cfc4e01662b3a533077933f3f019a --- .../util/netlink/StructInetDiagSockId.java | 47 +++--- .../util/netlink/InetDiagSocketTest.java | 139 +++++++++++++++++- 2 files changed, 166 insertions(+), 20 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java index 1e728ea571..dd85934c28 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagSockId.java @@ -29,6 +29,7 @@ import android.util.Log; import androidx.annotation.Nullable; import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; @@ -89,43 +90,53 @@ public class StructInetDiagSockId { final int srcPort = Short.toUnsignedInt(byteBuffer.getShort()); final int dstPort = Short.toUnsignedInt(byteBuffer.getShort()); - final byte[] srcAddrByte; - final byte[] dstAddrByte; + final InetAddress srcAddr; + final InetAddress dstAddr; if (family == AF_INET) { - srcAddrByte = new byte[IPV4_ADDR_LEN]; - dstAddrByte = new byte[IPV4_ADDR_LEN]; + final byte[] srcAddrByte = new byte[IPV4_ADDR_LEN]; + final byte[] dstAddrByte = new byte[IPV4_ADDR_LEN]; byteBuffer.get(srcAddrByte); // Address always uses IPV6_ADDR_LEN in the buffer. So if the address is IPv4, position // needs to be advanced to the next field. byteBuffer.position(byteBuffer.position() + (IPV6_ADDR_LEN - IPV4_ADDR_LEN)); byteBuffer.get(dstAddrByte); byteBuffer.position(byteBuffer.position() + (IPV6_ADDR_LEN - IPV4_ADDR_LEN)); + try { + srcAddr = Inet4Address.getByAddress(srcAddrByte); + dstAddr = Inet4Address.getByAddress(dstAddrByte); + } catch (UnknownHostException e) { + Log.wtf(TAG, "Failed to parse address: " + e); + return null; + } } else if (family == AF_INET6) { - srcAddrByte = new byte[IPV6_ADDR_LEN]; - dstAddrByte = new byte[IPV6_ADDR_LEN]; + final byte[] srcAddrByte = new byte[IPV6_ADDR_LEN]; + final byte[] dstAddrByte = new byte[IPV6_ADDR_LEN]; byteBuffer.get(srcAddrByte); byteBuffer.get(dstAddrByte); + try { + // Using Inet6Address.getByAddress to be consistent with idiag_family field since + // InetAddress.getByAddress returns Inet4Address if the address is v4-mapped v6 + // address. + srcAddr = Inet6Address.getByAddress( + null /* host */, srcAddrByte, -1 /* scope_id */); + dstAddr = Inet6Address.getByAddress( + null /* host */, dstAddrByte, -1 /* scope_id */); + } catch (UnknownHostException e) { + Log.wtf(TAG, "Failed to parse address: " + e); + return null; + } } else { Log.wtf(TAG, "Invalid address family: " + family); return null; } - final InetSocketAddress srcAddr; - final InetSocketAddress dstAddr; - try { - srcAddr = new InetSocketAddress(InetAddress.getByAddress(srcAddrByte), srcPort); - dstAddr = new InetSocketAddress(InetAddress.getByAddress(dstAddrByte), dstPort); - } catch (UnknownHostException e) { - // Should not happen. UnknownHostException is thrown only if addr byte array is of - // illegal length. - Log.wtf(TAG, "Failed to parse address: " + e); - return null; - } + final InetSocketAddress srcSocketAddr = new InetSocketAddress(srcAddr, srcPort); + final InetSocketAddress dstSocketAddr = new InetSocketAddress(dstAddr, dstPort); byteBuffer.order(ByteOrder.nativeOrder()); final int ifIndex = byteBuffer.getInt(); final long cookie = byteBuffer.getLong(); - return new StructInetDiagSockId(srcAddr, dstAddr, ifIndex, cookie); + return new StructInetDiagSockId(srcSocketAddr, dstSocketAddr, ifIndex, cookie); } /** diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java index 6837c83f8b..ebc0b9503f 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java @@ -41,6 +41,7 @@ import libcore.util.HexEncoding; import org.junit.Test; import org.junit.runner.RunWith; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.ByteBuffer; @@ -49,6 +50,21 @@ import java.nio.ByteOrder; @RunWith(AndroidJUnit4.class) @SmallTest public class InetDiagSocketTest { + // ::FFFF:192.0.2.1 + private static final byte[] SRC_V4_MAPPED_V6_ADDRESS_BYTES = { + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, + }; + // ::FFFF:192.0.2.2 + private static final byte[] DST_V4_MAPPED_V6_ADDRESS_BYTES = { + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x02, + }; + // Hexadecimal representation of InetDiagReqV2 request. private static final String INET_DIAG_REQ_V2_UDP_INET4_HEX = // struct nlmsghdr @@ -221,6 +237,46 @@ public class InetDiagSocketTest { assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_BYTES, msgExt); } + // Hexadecimal representation of InetDiagReqV2 request with v4-mapped v6 address + private static final String INET_DIAG_REQ_V2_TCP_INET6_V4_MAPPED_HEX = + // struct nlmsghdr + "48000000" + // length = 72 + "1400" + // type = SOCK_DIAG_BY_FAMILY + "0100" + // flags = NLM_F_REQUEST + "00000000" + // seqno + "00000000" + // pid (0 == kernel) + // struct inet_diag_req_v2 + "0a" + // family = AF_INET6 + "06" + // protcol = IPPROTO_TCP + "00" + // idiag_ext + "00" + // pad + "ffffffff" + // idiag_states + // inet_diag_sockid + "a817" + // idiag_sport = 43031 + "960f" + // idiag_dport = 38415 + "00000000000000000000ffffc0000201" + // idiag_src = ::FFFF:192.0.2.1 + "00000000000000000000ffffc0000202" + // idiag_dst = ::FFFF:192.0.2.2 + "00000000" + // idiag_if + "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE + + private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_V4_MAPPED_BYTES = + HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_V4_MAPPED_HEX.toCharArray(), false); + + @Test + public void testInetDiagReqV2TcpInet6V4Mapped() throws Exception { + final Inet6Address srcAddr = Inet6Address.getByAddress( + null /* host */, SRC_V4_MAPPED_V6_ADDRESS_BYTES, -1 /* scope_id */); + final Inet6Address dstAddr = Inet6Address.getByAddress( + null /* host */, DST_V4_MAPPED_V6_ADDRESS_BYTES, -1 /* scope_id */); + final byte[] msg = InetDiagMessage.inetDiagReqV2( + IPPROTO_TCP, + new InetSocketAddress(srcAddr, 43031), + new InetSocketAddress(dstAddr, 38415), + AF_INET6, + NLM_F_REQUEST); + assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_V4_MAPPED_BYTES, msg); + } + private void assertNlMsgHdr(StructNlMsgHdr hdr, short type, short flags, int seq, int pid) { assertNotNull(hdr); assertEquals(type, hdr.nlmsg_type); @@ -352,7 +408,7 @@ public class InetDiagSocketTest { @Test public void testParseInetDiagResponse() throws Exception { final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES); - byteBuffer.order(ByteOrder.LITTLE_ENDIAN); + byteBuffer.order(ByteOrder.nativeOrder()); assertInetDiagMsg1(NetlinkMessage.parse(byteBuffer, NETLINK_INET_DIAG)); } @@ -363,8 +419,87 @@ public class InetDiagSocketTest { @Test public void testParseInetDiagResponseMultiple() { final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES_MULTIPLE); - byteBuffer.order(ByteOrder.LITTLE_ENDIAN); + byteBuffer.order(ByteOrder.nativeOrder()); assertInetDiagMsg1(NetlinkMessage.parse(byteBuffer, NETLINK_INET_DIAG)); assertInetDiagMsg2(NetlinkMessage.parse(byteBuffer, NETLINK_INET_DIAG)); } + + private static final String INET_DIAG_SOCK_ID_V4_MAPPED_V6_HEX = + "a845" + // idiag_sport = 43077 + "01bb" + // idiag_dport = 443 + "00000000000000000000ffffc0000201" + // idiag_src = ::FFFF:192.0.2.1 + "00000000000000000000ffffc0000202" + // idiag_dst = ::FFFF:192.0.2.2 + "08000000" + // idiag_if = 8 + "6300000000000000"; // idiag_cookie = 99 + + private static final byte[] INET_DIAG_SOCK_ID_V4_MAPPED_V6_BYTES = + HexEncoding.decode(INET_DIAG_SOCK_ID_V4_MAPPED_V6_HEX.toCharArray(), false); + + @Test + public void testParseAndPackInetDiagSockIdV4MappedV6() { + final ByteBuffer parseByteBuffer = ByteBuffer.wrap(INET_DIAG_SOCK_ID_V4_MAPPED_V6_BYTES); + parseByteBuffer.order(ByteOrder.nativeOrder()); + final StructInetDiagSockId diagSockId = + StructInetDiagSockId.parse(parseByteBuffer, (short) AF_INET6); + assertNotNull(diagSockId); + + final ByteBuffer packByteBuffer = + ByteBuffer.allocate(INET_DIAG_SOCK_ID_V4_MAPPED_V6_BYTES.length); + diagSockId.pack(packByteBuffer); + + // Move position to the head since ByteBuffer#equals compares the values from the current + // position. + parseByteBuffer.position(0); + packByteBuffer.position(0); + assertEquals(parseByteBuffer, packByteBuffer); + } + + // Hexadecimal representation of InetDiagMessage with v4-mapped v6 address + private static final String INET_DIAG_MSG_V4_MAPPED_V6_HEX = + // struct nlmsghdr + "58000000" + // length = 88 + "1400" + // type = SOCK_DIAG_BY_FAMILY + "0200" + // flags = NLM_F_MULTI + "00000000" + // seqno + "f5220000" + // pid + // struct inet_diag_msg + "0a" + // family = AF_INET6 + "01" + // idiag_state = 1 + "02" + // idiag_timer = 2 + "03" + // idiag_retrans = 3 + // inet_diag_sockid + "a817" + // idiag_sport = 43031 + "960f" + // idiag_dport = 38415 + "00000000000000000000ffffc0000201" + // idiag_src = ::FFFF:192.0.2.1 + "00000000000000000000ffffc0000202" + // idiag_dst = ::FFFF:192.0.2.2 + "07000000" + // idiag_if = 7 + "5800000000000000" + // idiag_cookie = 88 + "04000000" + // idiag_expires = 4 + "05000000" + // idiag_rqueue = 5 + "06000000" + // idiag_wqueue = 6 + "a3270000" + // idiag_uid = 10147 + "A57E1900"; // idiag_inode = 1670821 + + private static final byte[] INET_DIAG_MSG_V4_MAPPED_V6_BYTES = + HexEncoding.decode(INET_DIAG_MSG_V4_MAPPED_V6_HEX.toCharArray(), false); + + @Test + public void testParseInetDiagResponseV4MappedV6() throws Exception { + final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_V4_MAPPED_V6_BYTES); + byteBuffer.order(ByteOrder.nativeOrder()); + final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_INET_DIAG); + + assertNotNull(msg); + assertTrue(msg instanceof InetDiagMessage); + final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg; + final Inet6Address srcAddr = Inet6Address.getByAddress( + null /* host */, SRC_V4_MAPPED_V6_ADDRESS_BYTES, -1 /* scope_id */); + final Inet6Address dstAddr = Inet6Address.getByAddress( + null /* host */, DST_V4_MAPPED_V6_ADDRESS_BYTES, -1 /* scope_id */); + assertInetDiagSockId(inetDiagMsg.inetDiagMsg.id, + new InetSocketAddress(srcAddr, 43031), + new InetSocketAddress(dstAddr, 38415), + 7 /* ifIndex */, + 88 /* cookie */); + } } From 95681172a930d43343a6695613da4fc0e7002039 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Tue, 28 Feb 2023 13:10:52 +0900 Subject: [PATCH 674/777] Add InetDiagMessage.inetDiagReqV2 with different args This CL also adds SOCK_DESTROY constants. These changes will be used by upcoming CLs that implement socket destroy in ConnectivityService. Bug: 270298713 Test: atest NetworkStaticLibTests Change-Id: Ief507b3f8cc4fe23c08699e7fc8f3f62e5acfcdc --- .../module/util/netlink/InetDiagMessage.java | 47 +++++++++++++++---- .../module/util/netlink/NetlinkConstants.java | 1 + .../util/netlink/StructInetDiagReqV2.java | 19 ++------ .../util/netlink/InetDiagSocketTest.java | 45 +++++++++++++++++- 4 files changed, 85 insertions(+), 27 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java index 5a180e7b5c..0a2f50d8ac 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java @@ -58,8 +58,8 @@ public class InetDiagMessage extends NetlinkMessage { private static final int TIMEOUT_MS = 500; /** - * Construct an inet_diag_req_v2 message. This method will throw {@code NullPointerException} - * if local and remote are not both null or both non-null. + * Construct an inet_diag_req_v2 message. This method will throw + * {@link IllegalArgumentException} if local and remote are not both null or both non-null. */ public static byte[] inetDiagReqV2(int protocol, InetSocketAddress local, InetSocketAddress remote, int family, short flags) { @@ -68,16 +68,16 @@ public class InetDiagMessage extends NetlinkMessage { } /** - * Construct an inet_diag_req_v2 message. This method will throw {@code NullPointerException} - * if local and remote are not both null or both non-null. + * Construct an inet_diag_req_v2 message. This method will throw + * {@code IllegalArgumentException} if local and remote are not both null or both non-null. * * @param protocol the request protocol type. This should be set to one of IPPROTO_TCP, * IPPROTO_UDP, or IPPROTO_UDPLITE. * @param local local socket address of the target socket. This will be packed into a - * {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of + * {@link StructInetDiagSockId}. Request to diagnose for all sockets if both of * local or remote address is null. * @param remote remote socket address of the target socket. This will be packed into a - * {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of + * {@link StructInetDiagSockId}. Request to diagnose for all sockets if both of * local or remote address is null. * @param family the ip family of the request message. This should be set to either AF_INET or * AF_INET6 for IPv4 or IPv6 sockets respectively. @@ -90,18 +90,47 @@ public class InetDiagMessage extends NetlinkMessage { */ public static byte[] inetDiagReqV2(int protocol, @Nullable InetSocketAddress local, @Nullable InetSocketAddress remote, int family, short flags, int pad, int idiagExt, - int state) throws NullPointerException { + int state) throws IllegalArgumentException { + // Request for all sockets if no specific socket is requested. Specify the local and remote + // socket address information for target request socket. + if ((local == null) != (remote == null)) { + throw new IllegalArgumentException( + "Local and remote must be both null or both non-null"); + } + final StructInetDiagSockId id = ((local != null && remote != null) + ? new StructInetDiagSockId(local, remote) : null); + return inetDiagReqV2(protocol, id, family, + SOCK_DIAG_BY_FAMILY, flags, pad, idiagExt, state); + } + + /** + * Construct an inet_diag_req_v2 message. + * + * @param protocol the request protocol type. This should be set to one of IPPROTO_TCP, + * IPPROTO_UDP, or IPPROTO_UDPLITE. + * @param id inet_diag_sockid. See {@link StructInetDiagSockId} + * @param family the ip family of the request message. This should be set to either AF_INET or + * AF_INET6 for IPv4 or IPv6 sockets respectively. + * @param type message types. + * @param flags message flags. See <linux_src>/include/uapi/linux/netlink.h. + * @param pad for raw socket protocol specification. + * @param idiagExt a set of flags defining what kind of extended information to report. + * @param state a bit mask that defines a filter of socket states. + * @return bytes array representation of the message + */ + public static byte[] inetDiagReqV2(int protocol, @Nullable StructInetDiagSockId id, int family, + short type, short flags, int pad, int idiagExt, int state) { final byte[] bytes = new byte[StructNlMsgHdr.STRUCT_SIZE + StructInetDiagReqV2.STRUCT_SIZE]; final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); byteBuffer.order(ByteOrder.nativeOrder()); final StructNlMsgHdr nlMsgHdr = new StructNlMsgHdr(); nlMsgHdr.nlmsg_len = bytes.length; - nlMsgHdr.nlmsg_type = SOCK_DIAG_BY_FAMILY; + nlMsgHdr.nlmsg_type = type; nlMsgHdr.nlmsg_flags = flags; nlMsgHdr.pack(byteBuffer); final StructInetDiagReqV2 inetDiagReqV2 = - new StructInetDiagReqV2(protocol, local, remote, family, pad, idiagExt, state); + new StructInetDiagReqV2(protocol, id, family, pad, idiagExt, state); inetDiagReqV2.pack(byteBuffer); return bytes; diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java index c44a5b4839..44c51d8a8c 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkConstants.java @@ -141,6 +141,7 @@ public class NetlinkConstants { /* see include/uapi/linux/sock_diag.h */ public static final short SOCK_DIAG_BY_FAMILY = 20; + public static final short SOCK_DESTROY = 21; // Netlink groups. public static final int RTMGRP_LINK = 1; diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java index 6eef8653fe..3b47008acb 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java @@ -18,7 +18,6 @@ package com.android.net.module.util.netlink; import androidx.annotation.Nullable; -import java.net.InetSocketAddress; import java.nio.ByteBuffer; /** @@ -48,23 +47,11 @@ public class StructInetDiagReqV2 { private final int mState; public static final int INET_DIAG_REQ_V2_ALL_STATES = (int) 0xffffffff; - public StructInetDiagReqV2(int protocol, InetSocketAddress local, InetSocketAddress remote, - int family) { - this(protocol, local, remote, family, 0 /* pad */, 0 /* extension */, - INET_DIAG_REQ_V2_ALL_STATES); - } - - public StructInetDiagReqV2(int protocol, @Nullable InetSocketAddress local, - @Nullable InetSocketAddress remote, int family, int pad, int extension, int state) - throws NullPointerException { + public StructInetDiagReqV2(int protocol, @Nullable StructInetDiagSockId id, int family, int pad, + int extension, int state) { mSdiagFamily = (byte) family; mSdiagProtocol = (byte) protocol; - // Request for all sockets if no specific socket is requested. Specify the local and remote - // socket address information for target request socket. - if ((local == null) != (remote == null)) { - throw new NullPointerException("Local and remote must be both null or both non-null"); - } - mId = ((local != null && remote != null) ? new StructInetDiagSockId(local, remote) : null); + mId = id; mPad = (byte) pad; mIdiagExt = (byte) extension; mState = state; diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java index ebc0b9503f..30796d24a1 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java @@ -22,6 +22,8 @@ import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.NETLINK_INET_DIAG; +import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DESTROY; +import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK; import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; @@ -221,14 +223,14 @@ public class InetDiagSocketTest { msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, null, remote, AF_INET6, NLM_F_REQUEST); fail("Both remote and local should be null, expected UnknownHostException"); - } catch (NullPointerException e) { + } catch (IllegalArgumentException e) { } try { msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, local, null, AF_INET6, NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES); fail("Both remote and local should be null, expected UnknownHostException"); - } catch (NullPointerException e) { + } catch (IllegalArgumentException e) { } msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6, @@ -277,6 +279,45 @@ public class InetDiagSocketTest { assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_V4_MAPPED_BYTES, msg); } + // Hexadecimal representation of InetDiagReqV2 request with SOCK_DESTROY + private static final String INET_DIAG_REQ_V2_TCP_INET6_DESTROY_HEX = + // struct nlmsghdr + "48000000" + // length = 72 + "1500" + // type = SOCK_DESTROY + "0500" + // flags = NLM_F_REQUEST | NLM_F_ACK + "00000000" + // seqno + "00000000" + // pid (0 == kernel) + // struct inet_diag_req_v2 + "0a" + // family = AF_INET6 + "06" + // protcol = IPPROTO_TCP + "00" + // idiag_ext + "00" + // pad + "ffffffff" + // idiag_states = TCP_ALL_STATES + // inet_diag_sockid + "a817" + // idiag_sport = 43031 + "960f" + // idiag_dport = 38415 + "20010db8000000000000000000000001" + // idiag_src = 2001:db8::1 + "20010db8000000000000000000000002" + // idiag_dst = 2001:db8::2 + "07000000" + // idiag_if = 7 + "5800000000000000"; // idiag_cookie = 88 + + private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_DESTROY_BYTES = + HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_DESTROY_HEX.toCharArray(), false); + + @Test + public void testInetDiagReqV2TcpInet6Destroy() throws Exception { + final StructInetDiagSockId sockId = new StructInetDiagSockId( + new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::1"), 43031), + new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::2"), 38415), + 7 /* ifIndex */, + 88 /* cookie */); + final byte[] msg = InetDiagMessage.inetDiagReqV2(IPPROTO_TCP, sockId, AF_INET6, + SOCK_DESTROY, (short) (NLM_F_REQUEST | NLM_F_ACK), 0 /* pad */, 0 /* idiagExt */, + TCP_ALL_STATES); + + assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_DESTROY_BYTES, msg); + } + private void assertNlMsgHdr(StructNlMsgHdr hdr, short type, short flags, int seq, int pid) { assertNotNull(hdr); assertEquals(type, hdr.nlmsg_type); From d7a1d968cfb0ba510c044bc7549cdb80344a561f Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Wed, 22 Mar 2023 16:39:31 +0900 Subject: [PATCH 675/777] Split netlink ack check code to individual function Upcoming CL uses this function Bug: 270298713 Test: atest NetworkStaticLibTests Change-Id: I4b969024206b3bc58965e44849e426cc91344425 --- .../net/module/util/netlink/NetlinkUtils.java | 75 ++++++++++++------- 1 file changed, 50 insertions(+), 25 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java index ae16cf8d19..d4bf14a479 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java @@ -36,6 +36,7 @@ import android.system.StructTimeval; import android.util.Log; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.io.FileDescriptor; import java.io.IOException; @@ -80,6 +81,54 @@ public class NetlinkUtils { return bytes.remaining() >= StructNlMsgHdr.STRUCT_SIZE; } + /** + * Parse netlink error message + * + * @param bytes byteBuffer to parse netlink error message + * @return NetlinkErrorMessage if bytes contains valid NetlinkErrorMessage, else {@code null} + */ + @Nullable + private static NetlinkErrorMessage parseNetlinkErrorMessage(ByteBuffer bytes) { + final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(bytes); + if (nlmsghdr == null || nlmsghdr.nlmsg_type != NetlinkConstants.NLMSG_ERROR) { + return null; + } + return NetlinkErrorMessage.parse(nlmsghdr, bytes); + } + + /** + * Receive netlink ack message and check error + * + * @param fd fd to read netlink message + */ + public static void receiveNetlinkAck(final FileDescriptor fd) + throws InterruptedIOException, ErrnoException { + final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT_MS); + // recvMessage() guaranteed to not return null if it did not throw. + final NetlinkErrorMessage response = parseNetlinkErrorMessage(bytes); + if (response != null && response.getNlMsgError() != null) { + final int errno = response.getNlMsgError().error; + if (errno != 0) { + // TODO: consider ignoring EINVAL (-22), which appears to be + // normal when probing a neighbor for which the kernel does + // not already have / no longer has a link layer address. + Log.e(TAG, "receiveNetlinkAck, errmsg=" + response.toString()); + // Note: convert kernel errnos (negative) into userspace errnos (positive). + throw new ErrnoException(response.toString(), Math.abs(errno)); + } + } else { + final String errmsg; + if (response == null) { + bytes.position(0); + errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes); + } else { + errmsg = response.toString(); + } + Log.e(TAG, "receiveNetlinkAck, errmsg=" + errmsg); + throw new ErrnoException(errmsg, EPROTO); + } + } + /** * Send one netlink message to kernel via netlink socket. * @@ -93,31 +142,7 @@ public class NetlinkUtils { try { connectSocketToNetlink(fd); sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT_MS); - final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT_MS); - // recvMessage() guaranteed to not return null if it did not throw. - final NetlinkMessage response = NetlinkMessage.parse(bytes, nlProto); - if (response != null && response instanceof NetlinkErrorMessage - && (((NetlinkErrorMessage) response).getNlMsgError() != null)) { - final int errno = ((NetlinkErrorMessage) response).getNlMsgError().error; - if (errno != 0) { - // TODO: consider ignoring EINVAL (-22), which appears to be - // normal when probing a neighbor for which the kernel does - // not already have / no longer has a link layer address. - Log.e(TAG, errPrefix + ", errmsg=" + response.toString()); - // Note: convert kernel errnos (negative) into userspace errnos (positive). - throw new ErrnoException(response.toString(), Math.abs(errno)); - } - } else { - final String errmsg; - if (response == null) { - bytes.position(0); - errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes); - } else { - errmsg = response.toString(); - } - Log.e(TAG, errPrefix + ", errmsg=" + errmsg); - throw new ErrnoException(errmsg, EPROTO); - } + receiveNetlinkAck(fd); } catch (InterruptedIOException e) { Log.e(TAG, errPrefix, e); throw new ErrnoException(errPrefix, ETIMEDOUT, e); From 3f2ca45688ba25f87fe8188227595eaf4fbbc40f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sun, 25 Dec 2022 09:21:46 +0000 Subject: [PATCH 676/777] add key/value Size to fdCache key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I44fab9d485cb6516c0a03324809e02ad511c6f77 --- staticlibs/device/com/android/net/module/util/BpfMap.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java index 9042085952..9df2b035e3 100644 --- a/staticlibs/device/com/android/net/module/util/BpfMap.java +++ b/staticlibs/device/com/android/net/module/util/BpfMap.java @@ -70,8 +70,11 @@ public class BpfMap implements IBpfMap private static ParcelFileDescriptor cachedBpfFdGet(String path, int mode, int keySize, int valueSize) throws ErrnoException, NullPointerException { - // TODO: key should include keySize & valueSize, but really we should match specific types - Pair key = Pair.create(path, mode); + // Supports up to 1023 byte key and 65535 byte values + // Creating a BpfMap with larger keys/values seems like a bad idea any way... + keySize &= 1023; // 10-bits + valueSize &= 65535; // 16-bits + var key = Pair.create(path, (mode << 26) ^ (keySize << 16) ^ valueSize); // unlocked fetch is safe: map is concurrent read capable, and only inserted into ParcelFileDescriptor fd = sFdCache.get(key); if (fd != null) return fd; From a4b2b56a334600056beabd9f85118d29533ce9ac Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 11 Apr 2023 11:36:35 +0800 Subject: [PATCH 677/777] Move checkAnyPermissionOf to PermissionUtils This is also needed in other classes in subsequent CLs, move to a common place to prevent from code duplication. Test: TH Bug: 275532605 Change-Id: Id460cd231bbc520ebdcfe988a7507c6959500ac4 --- .../android/net/module/util/PermissionUtils.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java index be5b0cde75..8315b8f6f5 100644 --- a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java @@ -53,6 +53,20 @@ public final class PermissionUtils { return false; } + /** + * Return true if the context has one of give permission that is allowed + * for a particular process and user ID running in the system. + */ + public static boolean checkAnyPermissionOf(@NonNull Context context, + int pid, int uid, @NonNull String... permissions) { + for (String permission : permissions) { + if (context.checkPermission(permission, pid, uid) == PERMISSION_GRANTED) { + return true; + } + } + return false; + } + /** * Enforce permission check on the context that should have one of given permission. */ From 2632888a107a15e7ef92208e080d0a9200175730 Mon Sep 17 00:00:00 2001 From: Gopal Krishna Shukla Date: Fri, 14 Apr 2023 23:21:22 +0530 Subject: [PATCH 678/777] bpf_headers: add bpf_probe_read_user Change-Id: I2b106cf8e34ec97f1efa2dd735b70aab8e4e1b4e --- staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 0300b5ec8c..4939483a32 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -305,6 +305,7 @@ unsigned long long load_word(void* skb, unsigned long long off) asm("llvm.bpf.lo static int (*bpf_probe_read)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read; static int (*bpf_probe_read_str)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read_str; +static int (*bpf_probe_read_user)(void* dst, int size, const void* unsafe_ptr) = (void*)BPF_FUNC_probe_read_user; static int (*bpf_probe_read_user_str)(void* dst, int size, const void* unsafe_ptr) = (void*) BPF_FUNC_probe_read_user_str; static unsigned long long (*bpf_ktime_get_ns)(void) = (void*) BPF_FUNC_ktime_get_ns; static unsigned long long (*bpf_ktime_get_boot_ns)(void) = (void*)BPF_FUNC_ktime_get_boot_ns; From 810be2b4565798ece7a9bebbbd60d199cac48238 Mon Sep 17 00:00:00 2001 From: Igor Chernyshev Date: Thu, 6 Apr 2023 15:52:26 -0700 Subject: [PATCH 679/777] Add async BufferedFile and StreamingPacketFile impls Bug: 245971639 Change-Id: Ief1719262c2cb68819f6feb955e97793f3638ec0 --- staticlibs/Android.bp | 25 ++ .../net/module/util/async/BufferedFile.java | 292 ++++++++++++++ .../module/util/wear/NetPacketHelpers.java | 41 ++ .../net/module/util/wear/PacketFile.java | 85 ++++ .../module/util/wear/StreamingPacketFile.java | 221 ++++++++++ staticlibs/tests/unit/Android.bp | 1 + .../module/util/async/BufferedFileTest.java | 376 ++++++++++++++++++ .../util/wear/NetPacketHelpersTest.java | 60 +++ .../util/wear/StreamingPacketFileTest.java | 291 ++++++++++++++ staticlibs/testutils/Android.bp | 1 + .../android/testutils/async/FakeOsAccess.java | 2 +- .../android/testutils/async/RateLimiter.java | 2 +- .../testutils/async/ReadableDataAnswer.java | 76 ++++ 13 files changed, 1471 insertions(+), 2 deletions(-) create mode 100644 staticlibs/device/com/android/net/module/util/async/BufferedFile.java create mode 100644 staticlibs/device/com/android/net/module/util/wear/NetPacketHelpers.java create mode 100644 staticlibs/device/com/android/net/module/util/wear/PacketFile.java create mode 100644 staticlibs/device/com/android/net/module/util/wear/StreamingPacketFile.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/async/BufferedFileTest.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/wear/NetPacketHelpersTest.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/wear/StreamingPacketFileTest.java create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/async/ReadableDataAnswer.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 904e8c6725..b1c653d8c9 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -328,6 +328,31 @@ java_library { lint: { strict_updatability_linting: true }, } +java_library { + name: "net-utils-device-common-wear", + srcs: [ + "device/com/android/net/module/util/wear/*.java", + ], + sdk_version: "module_current", + min_sdk_version: "29", + visibility: [ + "//frameworks/libs/net/common/tests:__subpackages__", + "//frameworks/libs/net/common/testutils:__subpackages__", + "//packages/modules/Connectivity:__subpackages__", + ], + libs: [ + "framework-annotations-lib", + ], + static_libs: [ + "net-utils-device-common-async", + ], + apex_available: [ + "com.android.tethering", + "//apex_available:platform", + ], + lint: { strict_updatability_linting: true }, +} + // Limited set of utilities for use by service-connectivity-mdns-standalone-build-test, to make sure // the mDNS code can build with only system APIs. // The mDNS code is platform code so it should use framework-annotations-lib, contrary to apps that diff --git a/staticlibs/device/com/android/net/module/util/async/BufferedFile.java b/staticlibs/device/com/android/net/module/util/async/BufferedFile.java new file mode 100644 index 0000000000..bb5736b0e0 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/async/BufferedFile.java @@ -0,0 +1,292 @@ +/* + * 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 com.android.net.module.util.async; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicLong; + +/** + * Buffers inbound and outbound file data within given strict limits. + * + * Automatically manages all readability and writeability events in EventManager: + * - When read buffer has more space - asks EventManager to notify on more data + * - When write buffer has more space - asks the user to provide more data + * - When underlying file cannot accept more data - registers EventManager callback + * + * @hide + */ +public final class BufferedFile implements AsyncFile.Listener { + /** + * Receives notifications when new data or output space is available. + * @hide + */ + public interface Listener { + /** Invoked after the underlying file has been closed. */ + void onBufferedFileClosed(); + + /** Invoked when there's new data in the inbound buffer. */ + void onBufferedFileInboundData(int readByteCount); + + /** Notifies on data being flushed from output buffer. */ + void onBufferedFileOutboundSpace(); + + /** Notifies on unrecoverable error in file access. */ + void onBufferedFileIoError(String message); + } + + private final Listener mListener; + private final EventManager mEventManager; + private AsyncFile mFile; + + private final CircularByteBuffer mInboundBuffer; + private final AtomicLong mTotalBytesRead = new AtomicLong(); + private boolean mIsReadingShutdown; + + private final CircularByteBuffer mOutboundBuffer; + private final AtomicLong mTotalBytesWritten = new AtomicLong(); + + /** Creates BufferedFile based on the given file descriptor. */ + public static BufferedFile create( + EventManager eventManager, + FileHandle fileHandle, + Listener listener, + int inboundBufferSize, + int outboundBufferSize) throws IOException { + if (fileHandle == null) { + throw new NullPointerException(); + } + BufferedFile file = new BufferedFile( + eventManager, listener, inboundBufferSize, outboundBufferSize); + file.mFile = eventManager.registerFile(fileHandle, file); + return file; + } + + private BufferedFile( + EventManager eventManager, + Listener listener, + int inboundBufferSize, + int outboundBufferSize) { + if (eventManager == null || listener == null) { + throw new NullPointerException(); + } + mEventManager = eventManager; + mListener = listener; + + mInboundBuffer = new CircularByteBuffer(inboundBufferSize); + mOutboundBuffer = new CircularByteBuffer(outboundBufferSize); + } + + /** Requests this file to be closed. */ + public void close() { + mFile.close(); + } + + @Override + public void onClosed(AsyncFile file) { + mListener.onBufferedFileClosed(); + } + + /////////////////////////////////////////////////////////////////////////// + // READ PATH + /////////////////////////////////////////////////////////////////////////// + + /** Returns buffer that is automatically filled with inbound data. */ + public ReadableByteBuffer getInboundBuffer() { + return mInboundBuffer; + } + + public int getInboundBufferFreeSizeForTest() { + return mInboundBuffer.freeSize(); + } + + /** Permanently disables reading of this file, and clears all buffered data. */ + public void shutdownReading() { + mIsReadingShutdown = true; + mInboundBuffer.clear(); + mFile.enableReadEvents(false); + } + + /** Returns true after shutdownReading() has been called. */ + public boolean isReadingShutdown() { + return mIsReadingShutdown; + } + + /** Starts or resumes async read operations on this file. */ + public void continueReading() { + if (!mIsReadingShutdown && mInboundBuffer.freeSize() > 0) { + mFile.enableReadEvents(true); + } + } + + @Override + public void onReadReady(AsyncFile file) { + if (mIsReadingShutdown) { + return; + } + + int readByteCount; + try { + readByteCount = bufferInputData(); + } catch (IOException e) { + mListener.onBufferedFileIoError("IOException while reading: " + e.toString()); + return; + } + + if (readByteCount > 0) { + mListener.onBufferedFileInboundData(readByteCount); + } + + continueReading(); + } + + private int bufferInputData() throws IOException { + int totalReadCount = 0; + while (true) { + final int maxReadCount = mInboundBuffer.getDirectWriteSize(); + if (maxReadCount == 0) { + mFile.enableReadEvents(false); + break; + } + + final int bufferOffset = mInboundBuffer.getDirectWritePos(); + final byte[] buffer = mInboundBuffer.getDirectWriteBuffer(); + + final int readCount = mFile.read(buffer, bufferOffset, maxReadCount); + if (readCount <= 0) { + break; + } + + mInboundBuffer.accountForDirectWrite(readCount); + totalReadCount += readCount; + } + + mTotalBytesRead.addAndGet(totalReadCount); + return totalReadCount; + } + + /////////////////////////////////////////////////////////////////////////// + // WRITE PATH + /////////////////////////////////////////////////////////////////////////// + + /** Returns the number of bytes currently buffered for output. */ + public int getOutboundBufferSize() { + return mOutboundBuffer.size(); + } + + /** Returns the number of bytes currently available for buffering for output. */ + public int getOutboundBufferFreeSize() { + return mOutboundBuffer.freeSize(); + } + + /** + * Queues the given data for output. + * Throws runtime exception if there is not enough space. + */ + public boolean enqueueOutboundData(byte[] data, int pos, int len) { + return enqueueOutboundData(data, pos, len, null, 0, 0); + } + + /** + * Queues data1, then data2 for output. + * Throws runtime exception if there is not enough space. + */ + public boolean enqueueOutboundData( + byte[] data1, int pos1, int len1, + byte[] buffer2, int pos2, int len2) { + Assertions.throwsIfOutOfBounds(data1, pos1, len1); + Assertions.throwsIfOutOfBounds(buffer2, pos2, len2); + + final int totalLen = len1 + len2; + + if (totalLen > mOutboundBuffer.freeSize()) { + flushOutboundBuffer(); + + if (totalLen > mOutboundBuffer.freeSize()) { + return false; + } + } + + mOutboundBuffer.writeBytes(data1, pos1, len1); + + if (buffer2 != null) { + mOutboundBuffer.writeBytes(buffer2, pos2, len2); + } + + flushOutboundBuffer(); + + return true; + } + + private void flushOutboundBuffer() { + try { + while (mOutboundBuffer.getDirectReadSize() > 0) { + final int maxReadSize = mOutboundBuffer.getDirectReadSize(); + final int writeCount = mFile.write( + mOutboundBuffer.getDirectReadBuffer(), + mOutboundBuffer.getDirectReadPos(), + maxReadSize); + + if (writeCount == 0) { + mFile.enableWriteEvents(true); + break; + } + + if (writeCount > maxReadSize) { + throw new IllegalArgumentException( + "Write count " + writeCount + " above max " + maxReadSize); + } + + mOutboundBuffer.accountForDirectRead(writeCount); + } + } catch (IOException e) { + scheduleOnIoError("IOException while writing: " + e.toString()); + } + } + + private void scheduleOnIoError(String message) { + mEventManager.execute(() -> { + mListener.onBufferedFileIoError(message); + }); + } + + @Override + public void onWriteReady(AsyncFile file) { + mFile.enableWriteEvents(false); + flushOutboundBuffer(); + mListener.onBufferedFileOutboundSpace(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("file={"); + sb.append(mFile); + sb.append("}"); + if (mIsReadingShutdown) { + sb.append(", readingShutdown"); + } + sb.append("}, inboundBuffer={"); + sb.append(mInboundBuffer); + sb.append("}, outboundBuffer={"); + sb.append(mOutboundBuffer); + sb.append("}, totalBytesRead="); + sb.append(mTotalBytesRead); + sb.append(", totalBytesWritten="); + sb.append(mTotalBytesWritten); + return sb.toString(); + } +} diff --git a/staticlibs/device/com/android/net/module/util/wear/NetPacketHelpers.java b/staticlibs/device/com/android/net/module/util/wear/NetPacketHelpers.java new file mode 100644 index 0000000000..341c44be59 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/wear/NetPacketHelpers.java @@ -0,0 +1,41 @@ +/* + * 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 com.android.net.module.util.wear; + +import com.android.net.module.util.async.ReadableByteBuffer; + +/** + * Implements utilities for decoding parts of TCP/UDP/IP headers. + * + * @hide + */ +final class NetPacketHelpers { + static void encodeNetworkUnsignedInt16(int value, byte[] dst, final int dstPos) { + dst[dstPos] = (byte) ((value >> 8) & 0xFF); + dst[dstPos + 1] = (byte) (value & 0xFF); + } + + static int decodeNetworkUnsignedInt16(byte[] data, final int pos) { + return ((data[pos] & 0xFF) << 8) | (data[pos + 1] & 0xFF); + } + + static int decodeNetworkUnsignedInt16(ReadableByteBuffer data, final int pos) { + return ((data.peek(pos) & 0xFF) << 8) | (data.peek(pos + 1) & 0xFF); + } + + private NetPacketHelpers() {} +} diff --git a/staticlibs/device/com/android/net/module/util/wear/PacketFile.java b/staticlibs/device/com/android/net/module/util/wear/PacketFile.java new file mode 100644 index 0000000000..7f5ed785b2 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/wear/PacketFile.java @@ -0,0 +1,85 @@ +/* + * 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 com.android.net.module.util.wear; + +/** + * Defines bidirectional file where all transmissions are made as complete packets. + * + * Automatically manages all readability and writeability events in EventManager: + * - When read buffer has more space - asks EventManager to notify on more data + * - When write buffer has more space - asks the user to provide more data + * - When underlying file cannot accept more data - registers EventManager callback + * + * @hide + */ +public interface PacketFile { + /** @hide */ + public enum ErrorCode { + UNEXPECTED_ERROR, + IO_ERROR, + INBOUND_PACKET_TOO_LARGE, + OUTBOUND_PACKET_TOO_LARGE, + } + + /** + * Receives notifications when new data or output space is available. + * + * @hide + */ + public interface Listener { + /** + * Handles the initial part of the stream, which on some systems provides lower-level + * configuration data. + * + * Returns the number of bytes consumed, or zero if the preamble has been fully read. + */ + int onPreambleData(byte[] data, int pos, int len); + + /** Handles one extracted packet. */ + void onInboundPacket(byte[] data, int pos, int len); + + /** Notifies on new data being added to the buffer. */ + void onInboundBuffered(int newByteCount, int totalBufferedSize); + + /** Notifies on data being flushed from output buffer. */ + void onOutboundPacketSpace(); + + /** Notifies on unrecoverable error in the packet processing. */ + void onPacketFileError(ErrorCode error, String message); + } + + /** Requests this file to be closed. */ + void close(); + + /** Permanently disables reading of this file, and clears all buffered data. */ + void shutdownReading(); + + /** Starts or resumes async read operations on this file. */ + void continueReading(); + + /** Returns the number of bytes currently buffered as input. */ + int getInboundBufferSize(); + + /** Returns the number of bytes currently available for buffering for output. */ + int getOutboundFreeSize(); + + /** + * Queues the given data for output. + * Throws runtime exception if there is not enough space. + */ + boolean enqueueOutboundPacket(byte[] data, int pos, int len); +} diff --git a/staticlibs/device/com/android/net/module/util/wear/StreamingPacketFile.java b/staticlibs/device/com/android/net/module/util/wear/StreamingPacketFile.java new file mode 100644 index 0000000000..52dbee47d7 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/wear/StreamingPacketFile.java @@ -0,0 +1,221 @@ +/* + * 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 com.android.net.module.util.wear; + +import com.android.net.module.util.async.BufferedFile; +import com.android.net.module.util.async.EventManager; +import com.android.net.module.util.async.FileHandle; +import com.android.net.module.util.async.Assertions; +import com.android.net.module.util.async.ReadableByteBuffer; + +import java.io.IOException; + +/** + * Implements PacketFile based on a streaming file descriptor. + * + * Packets are delineated using network-order 2-byte length indicators. + * + * @hide + */ +public final class StreamingPacketFile implements PacketFile, BufferedFile.Listener { + private static final int HEADER_SIZE = 2; + + private final EventManager mEventManager; + private final Listener mListener; + private final BufferedFile mFile; + private final int mMaxPacketSize; + private final ReadableByteBuffer mInboundBuffer; + private boolean mIsInPreamble = true; + + private final byte[] mTempPacketReadBuffer; + private final byte[] mTempHeaderWriteBuffer; + + public StreamingPacketFile( + EventManager eventManager, + FileHandle fileHandle, + Listener listener, + int maxPacketSize, + int maxBufferedInboundPackets, + int maxBufferedOutboundPackets) throws IOException { + if (eventManager == null || fileHandle == null || listener == null) { + throw new NullPointerException(); + } + + mEventManager = eventManager; + mListener = listener; + mMaxPacketSize = maxPacketSize; + + final int maxTotalLength = HEADER_SIZE + maxPacketSize; + + mFile = BufferedFile.create(eventManager, fileHandle, this, + maxTotalLength * maxBufferedInboundPackets, + maxTotalLength * maxBufferedOutboundPackets); + mInboundBuffer = mFile.getInboundBuffer(); + + mTempPacketReadBuffer = new byte[maxTotalLength]; + mTempHeaderWriteBuffer = new byte[HEADER_SIZE]; + } + + @Override + public void close() { + mFile.close(); + } + + public BufferedFile getUnderlyingFileForTest() { + return mFile; + } + + @Override + public void shutdownReading() { + mFile.shutdownReading(); + } + + @Override + public void continueReading() { + mFile.continueReading(); + } + + @Override + public int getInboundBufferSize() { + return mInboundBuffer.size(); + } + + @Override + public void onBufferedFileClosed() { + } + + @Override + public void onBufferedFileInboundData(int readByteCount) { + if (mFile.isReadingShutdown()) { + return; + } + + if (readByteCount > 0) { + mListener.onInboundBuffered(readByteCount, mInboundBuffer.size()); + } + + if (extractOnePacket() && !mFile.isReadingShutdown()) { + // There could be more packets already buffered, continue parsing next + // packet even before another read event comes + mEventManager.execute(() -> { + onBufferedFileInboundData(0); + }); + } else { + continueReading(); + } + } + + private boolean extractOnePacket() { + while (mIsInPreamble) { + final int directReadSize = Math.min( + mInboundBuffer.getDirectReadSize(), mTempPacketReadBuffer.length); + if (directReadSize == 0) { + return false; + } + + // Copy for safety, so higher-level callback cannot modify the data. + System.arraycopy(mInboundBuffer.getDirectReadBuffer(), + mInboundBuffer.getDirectReadPos(), mTempPacketReadBuffer, 0, directReadSize); + + final int preambleConsumedBytes = mListener.onPreambleData( + mTempPacketReadBuffer, 0, directReadSize); + if (mFile.isReadingShutdown()) { + return false; // The callback has called shutdownReading(). + } + + if (preambleConsumedBytes == 0) { + mIsInPreamble = false; + break; + } + + mInboundBuffer.accountForDirectRead(preambleConsumedBytes); + } + + final int bufferedSize = mInboundBuffer.size(); + if (bufferedSize < HEADER_SIZE) { + return false; + } + + final int dataLength = NetPacketHelpers.decodeNetworkUnsignedInt16(mInboundBuffer, 0); + if (dataLength > mMaxPacketSize) { + mListener.onPacketFileError( + PacketFile.ErrorCode.INBOUND_PACKET_TOO_LARGE, + "Inbound packet length: " + dataLength); + return false; + } + + final int totalLength = HEADER_SIZE + dataLength; + if (bufferedSize < totalLength) { + return false; + } + + mInboundBuffer.readBytes(mTempPacketReadBuffer, 0, totalLength); + + mListener.onInboundPacket(mTempPacketReadBuffer, HEADER_SIZE, dataLength); + return true; + } + + @Override + public int getOutboundFreeSize() { + final int freeSize = mFile.getOutboundBufferFreeSize(); + return (freeSize > HEADER_SIZE ? freeSize - HEADER_SIZE : 0); + } + + @Override + public boolean enqueueOutboundPacket(byte[] buffer, int pos, int len) { + Assertions.throwsIfOutOfBounds(buffer, pos, len); + + if (len == 0) { + return true; + } + + if (len > mMaxPacketSize) { + mListener.onPacketFileError( + PacketFile.ErrorCode.OUTBOUND_PACKET_TOO_LARGE, + "Outbound packet length: " + len); + return false; + } + + NetPacketHelpers.encodeNetworkUnsignedInt16(len, mTempHeaderWriteBuffer, 0); + + mFile.enqueueOutboundData( + mTempHeaderWriteBuffer, 0, mTempHeaderWriteBuffer.length, + buffer, pos, len); + return true; + } + + @Override + public void onBufferedFileOutboundSpace() { + mListener.onOutboundPacketSpace(); + } + + @Override + public void onBufferedFileIoError(String message) { + mListener.onPacketFileError(PacketFile.ErrorCode.IO_ERROR, message); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("maxPacket="); + sb.append(mMaxPacketSize); + sb.append(", file={"); + sb.append(mFile); + sb.append("}"); + return sb.toString(); + } +} diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index 6e223bd4e0..40371e63b2 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -21,6 +21,7 @@ android_library { "net-utils-device-common-async", "net-utils-device-common-bpf", "net-utils-device-common-ip", + "net-utils-device-common-wear", ], libs: [ "android.test.runner", diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/async/BufferedFileTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/async/BufferedFileTest.java new file mode 100644 index 0000000000..11a74f2c2e --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/async/BufferedFileTest.java @@ -0,0 +1,376 @@ +/* + * 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 com.android.net.module.util.async; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.ignoreStubs; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import android.os.ParcelFileDescriptor; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.async.ReadableDataAnswer; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class BufferedFileTest { + @Mock EventManager mockEventManager; + @Mock BufferedFile.Listener mockFileListener; + @Mock AsyncFile mockAsyncFile; + @Mock ParcelFileDescriptor mockParcelFileDescriptor; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + } + + @After + public void tearDown() throws Exception { + verifyNoMoreInteractions(ignoreStubs(mockFileListener, mockAsyncFile, mockEventManager)); + } + + @Test + public void onClosed() throws Exception { + final int inboundBufferSize = 1024; + final int outboundBufferSize = 768; + + final BufferedFile file = createFile(inboundBufferSize, outboundBufferSize); + + file.onClosed(mockAsyncFile); + + verify(mockFileListener).onBufferedFileClosed(); + } + + @Test + public void continueReadingAndClose() throws Exception { + final int inboundBufferSize = 1024; + final int outboundBufferSize = 768; + + final BufferedFile file = createFile(inboundBufferSize, outboundBufferSize); + + assertEquals(inboundBufferSize, file.getInboundBufferFreeSizeForTest()); + assertEquals(outboundBufferSize, file.getOutboundBufferFreeSize()); + + file.continueReading(); + verify(mockAsyncFile).enableReadEvents(true); + + file.close(); + verify(mockAsyncFile).close(); + } + + @Test + public void enqueueOutboundData() throws Exception { + final int inboundBufferSize = 10; + final int outboundBufferSize = 250; + + final BufferedFile file = createFile(inboundBufferSize, outboundBufferSize); + + final byte[] data1 = new byte[101]; + final byte[] data2 = new byte[102]; + data1[0] = (byte) 1; + data2[0] = (byte) 2; + + assertEquals(0, file.getOutboundBufferSize()); + + final int totalLen = data1.length + data2.length; + + when(mockAsyncFile.write(any(), anyInt(), anyInt())).thenReturn(0); + assertTrue(file.enqueueOutboundData(data1, 0, data1.length, null, 0, 0)); + verify(mockAsyncFile).enableWriteEvents(true); + + assertEquals(data1.length, file.getOutboundBufferSize()); + + checkAndResetMocks(); + + final ArgumentCaptor arrayCaptor = ArgumentCaptor.forClass(byte[].class); + final ArgumentCaptor posCaptor = ArgumentCaptor.forClass(Integer.class); + final ArgumentCaptor lenCaptor = ArgumentCaptor.forClass(Integer.class); + when(mockAsyncFile.write( + arrayCaptor.capture(), posCaptor.capture(), lenCaptor.capture())).thenReturn(totalLen); + + assertTrue(file.enqueueOutboundData(data2, 0, data2.length, null, 0, 0)); + + assertEquals(0, file.getInboundBuffer().size()); + assertEquals(0, file.getOutboundBufferSize()); + + assertEquals(0, posCaptor.getValue().intValue()); + assertEquals(totalLen, lenCaptor.getValue().intValue()); + assertEquals(data1[0], arrayCaptor.getValue()[0]); + assertEquals(data2[0], arrayCaptor.getValue()[data1.length]); + } + + @Test + public void enqueueOutboundData_combined() throws Exception { + final int inboundBufferSize = 10; + final int outboundBufferSize = 250; + + final BufferedFile file = createFile(inboundBufferSize, outboundBufferSize); + + final byte[] data1 = new byte[101]; + final byte[] data2 = new byte[102]; + data1[0] = (byte) 1; + data2[0] = (byte) 2; + + assertEquals(0, file.getOutboundBufferSize()); + + final int totalLen = data1.length + data2.length; + + final ArgumentCaptor arrayCaptor = ArgumentCaptor.forClass(byte[].class); + final ArgumentCaptor posCaptor = ArgumentCaptor.forClass(Integer.class); + final ArgumentCaptor lenCaptor = ArgumentCaptor.forClass(Integer.class); + when(mockAsyncFile.write( + arrayCaptor.capture(), posCaptor.capture(), lenCaptor.capture())).thenReturn(totalLen); + + assertTrue(file.enqueueOutboundData(data1, 0, data1.length, data2, 0, data2.length)); + + assertEquals(0, file.getInboundBuffer().size()); + assertEquals(0, file.getOutboundBufferSize()); + + assertEquals(0, posCaptor.getValue().intValue()); + assertEquals(totalLen, lenCaptor.getValue().intValue()); + assertEquals(data1[0], arrayCaptor.getValue()[0]); + assertEquals(data2[0], arrayCaptor.getValue()[data1.length]); + } + + @Test + public void enableWriteEvents() throws Exception { + final int inboundBufferSize = 10; + final int outboundBufferSize = 250; + + final BufferedFile file = createFile(inboundBufferSize, outboundBufferSize); + + final byte[] data1 = new byte[101]; + final byte[] data2 = new byte[102]; + final byte[] data3 = new byte[103]; + data1[0] = (byte) 1; + data2[0] = (byte) 2; + data3[0] = (byte) 3; + + assertEquals(0, file.getOutboundBufferSize()); + + // Write first 2 buffers, but fail to flush them, causing async write request. + final int data1And2Len = data1.length + data2.length; + when(mockAsyncFile.write(any(), eq(0), eq(data1And2Len))).thenReturn(0); + assertTrue(file.enqueueOutboundData(data1, 0, data1.length, data2, 0, data2.length)); + assertEquals(0, file.getInboundBuffer().size()); + assertEquals(data1And2Len, file.getOutboundBufferSize()); + verify(mockAsyncFile).enableWriteEvents(true); + + // Try to write 3rd buffers, which won't fit, then fail to flush. + when(mockAsyncFile.write(any(), eq(0), eq(data1And2Len))).thenReturn(0); + assertFalse(file.enqueueOutboundData(data3, 0, data3.length, null, 0, 0)); + assertEquals(0, file.getInboundBuffer().size()); + assertEquals(data1And2Len, file.getOutboundBufferSize()); + verify(mockAsyncFile, times(2)).enableWriteEvents(true); + + checkAndResetMocks(); + + // Simulate writeability event, and successfully flush. + final ArgumentCaptor arrayCaptor = ArgumentCaptor.forClass(byte[].class); + final ArgumentCaptor posCaptor = ArgumentCaptor.forClass(Integer.class); + final ArgumentCaptor lenCaptor = ArgumentCaptor.forClass(Integer.class); + when(mockAsyncFile.write(arrayCaptor.capture(), + posCaptor.capture(), lenCaptor.capture())).thenReturn(data1And2Len); + file.onWriteReady(mockAsyncFile); + verify(mockAsyncFile).enableWriteEvents(false); + verify(mockFileListener).onBufferedFileOutboundSpace(); + assertEquals(0, file.getOutboundBufferSize()); + + assertEquals(0, posCaptor.getValue().intValue()); + assertEquals(data1And2Len, lenCaptor.getValue().intValue()); + assertEquals(data1[0], arrayCaptor.getValue()[0]); + assertEquals(data2[0], arrayCaptor.getValue()[data1.length]); + + checkAndResetMocks(); + + // Now write, but fail to flush the third buffer. + when(mockAsyncFile.write(arrayCaptor.capture(), + posCaptor.capture(), lenCaptor.capture())).thenReturn(0); + assertTrue(file.enqueueOutboundData(data3, 0, data3.length, null, 0, 0)); + verify(mockAsyncFile).enableWriteEvents(true); + assertEquals(data3.length, file.getOutboundBufferSize()); + + assertEquals(data1And2Len, posCaptor.getValue().intValue()); + assertEquals(outboundBufferSize - data1And2Len, lenCaptor.getValue().intValue()); + assertEquals(data3[0], arrayCaptor.getValue()[data1And2Len]); + } + + @Test + public void read() throws Exception { + final int inboundBufferSize = 250; + final int outboundBufferSize = 10; + + final BufferedFile file = createFile(inboundBufferSize, outboundBufferSize); + + final byte[] data1 = new byte[101]; + final byte[] data2 = new byte[102]; + data1[0] = (byte) 1; + data2[0] = (byte) 2; + + final ReadableDataAnswer dataAnswer = new ReadableDataAnswer(data1, data2); + final ReadableByteBuffer inboundBuffer = file.getInboundBuffer(); + + when(mockAsyncFile.read(any(), anyInt(), anyInt())).thenAnswer(dataAnswer); + file.onReadReady(mockAsyncFile); + verify(mockAsyncFile).enableReadEvents(true); + verify(mockFileListener).onBufferedFileInboundData(eq(data1.length + data2.length)); + + assertEquals(0, file.getOutboundBufferSize()); + assertEquals(data1.length + data2.length, inboundBuffer.size()); + assertEquals((byte) 1, inboundBuffer.peek(0)); + assertEquals((byte) 2, inboundBuffer.peek(data1.length)); + } + + @Test + public void enableReadEvents() throws Exception { + final int inboundBufferSize = 250; + final int outboundBufferSize = 10; + + final BufferedFile file = createFile(inboundBufferSize, outboundBufferSize); + + final byte[] data1 = new byte[101]; + final byte[] data2 = new byte[102]; + final byte[] data3 = new byte[103]; + data1[0] = (byte) 1; + data2[0] = (byte) 2; + data3[0] = (byte) 3; + + final ReadableDataAnswer dataAnswer = new ReadableDataAnswer(data1, data2, data3); + final ReadableByteBuffer inboundBuffer = file.getInboundBuffer(); + + when(mockAsyncFile.read(any(), anyInt(), anyInt())).thenAnswer(dataAnswer); + file.onReadReady(mockAsyncFile); + verify(mockAsyncFile).enableReadEvents(false); + verify(mockFileListener).onBufferedFileInboundData(eq(inboundBufferSize)); + + assertEquals(0, file.getOutboundBufferSize()); + assertEquals(inboundBufferSize, inboundBuffer.size()); + assertEquals((byte) 1, inboundBuffer.peek(0)); + assertEquals((byte) 2, inboundBuffer.peek(data1.length)); + assertEquals((byte) 3, inboundBuffer.peek(data1.length + data2.length)); + + checkAndResetMocks(); + + // Cannot enable read events since the buffer is full. + file.continueReading(); + + checkAndResetMocks(); + + final byte[] tmp = new byte[inboundBufferSize]; + inboundBuffer.readBytes(tmp, 0, data1.length); + assertEquals(inboundBufferSize - data1.length, inboundBuffer.size()); + + file.continueReading(); + + inboundBuffer.readBytes(tmp, 0, data2.length); + assertEquals(inboundBufferSize - data1.length - data2.length, inboundBuffer.size()); + + when(mockAsyncFile.read(any(), anyInt(), anyInt())).thenAnswer(dataAnswer); + file.onReadReady(mockAsyncFile); + verify(mockAsyncFile, times(2)).enableReadEvents(true); + verify(mockFileListener).onBufferedFileInboundData( + eq(data1.length + data2.length + data3.length - inboundBufferSize)); + + assertEquals(data3.length, inboundBuffer.size()); + assertEquals((byte) 3, inboundBuffer.peek(0)); + } + + @Test + public void shutdownReading() throws Exception { + final int inboundBufferSize = 250; + final int outboundBufferSize = 10; + + final BufferedFile file = createFile(inboundBufferSize, outboundBufferSize); + + final byte[] data = new byte[100]; + final ReadableDataAnswer dataAnswer = new ReadableDataAnswer(data); + when(mockAsyncFile.read(any(), anyInt(), anyInt())).thenAnswer(dataAnswer); + + file.shutdownReading(); + file.onReadReady(mockAsyncFile); + + verify(mockAsyncFile).enableReadEvents(false); + + assertEquals(0, file.getInboundBuffer().size()); + assertEquals(data.length, dataAnswer.getRemainingSize()); + } + + @Test + public void shutdownReading_inCallback() throws Exception { + final int inboundBufferSize = 250; + final int outboundBufferSize = 10; + + final BufferedFile file = createFile(inboundBufferSize, outboundBufferSize); + + final byte[] data = new byte[100]; + final ReadableDataAnswer dataAnswer = new ReadableDataAnswer(data); + when(mockAsyncFile.read(any(), anyInt(), anyInt())).thenAnswer(dataAnswer); + + doAnswer(new Answer() { + @Override public Object answer(InvocationOnMock invocation) { + file.shutdownReading(); + return null; + }}).when(mockFileListener).onBufferedFileInboundData(anyInt()); + + file.onReadReady(mockAsyncFile); + + verify(mockAsyncFile).enableReadEvents(false); + + assertEquals(0, file.getInboundBuffer().size()); + assertEquals(0, dataAnswer.getRemainingSize()); + } + + private void checkAndResetMocks() { + verifyNoMoreInteractions(ignoreStubs(mockFileListener, mockAsyncFile, mockEventManager, + mockParcelFileDescriptor)); + reset(mockFileListener, mockAsyncFile, mockEventManager); + } + + private BufferedFile createFile( + int inboundBufferSize, int outboundBufferSize) throws Exception { + when(mockEventManager.registerFile(any(), any())).thenReturn(mockAsyncFile); + return BufferedFile.create( + mockEventManager, + FileHandle.fromFileDescriptor(mockParcelFileDescriptor), + mockFileListener, + inboundBufferSize, + outboundBufferSize); + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/wear/NetPacketHelpersTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/wear/NetPacketHelpersTest.java new file mode 100644 index 0000000000..23e7b15e03 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/wear/NetPacketHelpersTest.java @@ -0,0 +1,60 @@ +/* + * 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 com.android.net.module.util.wear; + +import static org.junit.Assert.assertEquals; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.android.net.module.util.async.CircularByteBuffer; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class NetPacketHelpersTest { + @Test + public void decodeNetworkUnsignedInt16() { + final byte[] data = new byte[4]; + data[0] = (byte) 0xFF; + data[1] = (byte) 1; + data[2] = (byte) 2; + data[3] = (byte) 0xFF; + + assertEquals(0x0102, NetPacketHelpers.decodeNetworkUnsignedInt16(data, 1)); + + CircularByteBuffer buffer = new CircularByteBuffer(100); + buffer.writeBytes(data, 0, data.length); + + assertEquals(0x0102, NetPacketHelpers.decodeNetworkUnsignedInt16(buffer, 1)); + } + + @Test + public void encodeNetworkUnsignedInt16() { + final byte[] data = new byte[4]; + data[0] = (byte) 0xFF; + data[3] = (byte) 0xFF; + NetPacketHelpers.encodeNetworkUnsignedInt16(0x0102, data, 1); + + assertEquals((byte) 0xFF, data[0]); + assertEquals((byte) 1, data[1]); + assertEquals((byte) 2, data[2]); + assertEquals((byte) 0xFF, data[3]); + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/wear/StreamingPacketFileTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/wear/StreamingPacketFileTest.java new file mode 100644 index 0000000000..1fcca70445 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/wear/StreamingPacketFileTest.java @@ -0,0 +1,291 @@ +/* + * 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 com.android.net.module.util.wear; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.ignoreStubs; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import android.os.ParcelFileDescriptor; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.net.module.util.async.AsyncFile; +import com.android.net.module.util.async.BufferedFile; +import com.android.net.module.util.async.EventManager; +import com.android.net.module.util.async.FileHandle; +import com.android.net.module.util.async.ReadableByteBuffer; +import com.android.testutils.async.ReadableDataAnswer; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class StreamingPacketFileTest { + private static final int MAX_PACKET_SIZE = 100; + + @Mock EventManager mockEventManager; + @Mock PacketFile.Listener mockFileListener; + @Mock AsyncFile mockAsyncFile; + @Mock ParcelFileDescriptor mockParcelFileDescriptor; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + } + + @After + public void tearDown() throws Exception { + verifyNoMoreInteractions(ignoreStubs(mockFileListener, mockAsyncFile, mockEventManager)); + } + + @Test + public void continueReadingAndClose() throws Exception { + final int maxBufferedInboundPackets = 3; + final int maxBufferedOutboundPackets = 5; + + final StreamingPacketFile file = + createFile(maxBufferedInboundPackets, maxBufferedOutboundPackets); + final BufferedFile bufferedFile = file.getUnderlyingFileForTest(); + + assertEquals(maxBufferedInboundPackets * (MAX_PACKET_SIZE + 2), + bufferedFile.getInboundBufferFreeSizeForTest()); + assertEquals(maxBufferedOutboundPackets * (MAX_PACKET_SIZE + 2), + bufferedFile.getOutboundBufferFreeSize()); + assertEquals(bufferedFile.getOutboundBufferFreeSize() - 2, + file.getOutboundFreeSize()); + + file.continueReading(); + verify(mockAsyncFile).enableReadEvents(true); + + file.close(); + verify(mockAsyncFile).close(); + } + + @Test + public void enqueueOutboundPacket() throws Exception { + final int maxBufferedInboundPackets = 10; + final int maxBufferedOutboundPackets = 20; + + final StreamingPacketFile file = + createFile(maxBufferedInboundPackets, maxBufferedOutboundPackets); + final BufferedFile bufferedFile = file.getUnderlyingFileForTest(); + + final byte[] packet1 = new byte[11]; + final byte[] packet2 = new byte[12]; + packet1[0] = (byte) 1; + packet2[0] = (byte) 2; + + assertEquals(0, bufferedFile.getOutboundBufferSize()); + + when(mockAsyncFile.write(any(), anyInt(), anyInt())).thenReturn(0); + assertTrue(file.enqueueOutboundPacket(packet1, 0, packet1.length)); + verify(mockAsyncFile).enableWriteEvents(true); + + assertEquals(packet1.length + 2, bufferedFile.getOutboundBufferSize()); + + checkAndResetMocks(); + + final int totalLen = packet1.length + packet2.length + 4; + + final ArgumentCaptor arrayCaptor = ArgumentCaptor.forClass(byte[].class); + final ArgumentCaptor posCaptor = ArgumentCaptor.forClass(Integer.class); + final ArgumentCaptor lenCaptor = ArgumentCaptor.forClass(Integer.class); + when(mockAsyncFile.write( + arrayCaptor.capture(), posCaptor.capture(), lenCaptor.capture())).thenReturn(totalLen); + + assertTrue(file.enqueueOutboundPacket(packet2, 0, packet2.length)); + + assertEquals(0, bufferedFile.getInboundBuffer().size()); + assertEquals(0, bufferedFile.getOutboundBufferSize()); + + assertEquals(0, posCaptor.getValue().intValue()); + assertEquals(totalLen, lenCaptor.getValue().intValue()); + + final byte[] capturedData = arrayCaptor.getValue(); + assertEquals(packet1.length, NetPacketHelpers.decodeNetworkUnsignedInt16(capturedData, 0)); + assertEquals(packet2.length, + NetPacketHelpers.decodeNetworkUnsignedInt16(capturedData, packet1.length + 2)); + assertEquals(packet1[0], capturedData[2]); + assertEquals(packet2[0], capturedData[packet1.length + 4]); + } + + @Test + public void onInboundPacket() throws Exception { + final int maxBufferedInboundPackets = 10; + final int maxBufferedOutboundPackets = 20; + + final StreamingPacketFile file = + createFile(maxBufferedInboundPackets, maxBufferedOutboundPackets); + final BufferedFile bufferedFile = file.getUnderlyingFileForTest(); + final ReadableByteBuffer inboundBuffer = bufferedFile.getInboundBuffer(); + + final int len1 = 11; + final int len2 = 12; + final byte[] data = new byte[len1 + len2 + 4]; + NetPacketHelpers.encodeNetworkUnsignedInt16(len1, data, 0); + NetPacketHelpers.encodeNetworkUnsignedInt16(len2, data, 11 + 2); + data[2] = (byte) 1; + data[len1 + 4] = (byte) 2; + + final ReadableDataAnswer dataAnswer = new ReadableDataAnswer(data); + + final ArgumentCaptor arrayCaptor = ArgumentCaptor.forClass(byte[].class); + final ArgumentCaptor posCaptor = ArgumentCaptor.forClass(Integer.class); + final ArgumentCaptor lenCaptor = ArgumentCaptor.forClass(Integer.class); + + when(mockAsyncFile.read(any(), anyInt(), anyInt())).thenAnswer(dataAnswer); + when(mockFileListener.onPreambleData(any(), eq(0), eq(data.length))).thenReturn(0); + bufferedFile.onReadReady(mockAsyncFile); + verify(mockAsyncFile).enableReadEvents(true); + verify(mockFileListener).onInboundBuffered(data.length, data.length); + verify(mockFileListener).onInboundPacket( + arrayCaptor.capture(), posCaptor.capture(), lenCaptor.capture()); + verify(mockEventManager).execute(any()); + + byte[] capturedData = arrayCaptor.getValue(); + assertEquals(2, posCaptor.getValue().intValue()); + assertEquals(len1, lenCaptor.getValue().intValue()); + assertEquals((byte) 1, capturedData[2]); + + checkAndResetMocks(); + + when(mockAsyncFile.read(any(), anyInt(), anyInt())).thenAnswer(dataAnswer); + file.onBufferedFileInboundData(0); + verify(mockFileListener).onInboundPacket( + arrayCaptor.capture(), posCaptor.capture(), lenCaptor.capture()); + verify(mockEventManager).execute(any()); + + capturedData = arrayCaptor.getValue(); + assertEquals(2, posCaptor.getValue().intValue()); + assertEquals(len2, lenCaptor.getValue().intValue()); + assertEquals((byte) 2, capturedData[2]); + + assertEquals(0, bufferedFile.getOutboundBufferSize()); + assertEquals(0, inboundBuffer.size()); + } + + @Test + public void onReadReady_preambleData() throws Exception { + final int maxBufferedInboundPackets = 10; + final int maxBufferedOutboundPackets = 20; + + final StreamingPacketFile file = + createFile(maxBufferedInboundPackets, maxBufferedOutboundPackets); + final BufferedFile bufferedFile = file.getUnderlyingFileForTest(); + final ReadableByteBuffer inboundBuffer = bufferedFile.getInboundBuffer(); + + final int preambleLen = 23; + final int len1 = 11; + final byte[] data = new byte[preambleLen + 2 + len1]; + NetPacketHelpers.encodeNetworkUnsignedInt16(len1, data, preambleLen); + data[preambleLen + 2] = (byte) 1; + + final ReadableDataAnswer dataAnswer = new ReadableDataAnswer(data); + + when(mockAsyncFile.read(any(), anyInt(), anyInt())).thenAnswer(dataAnswer); + when(mockFileListener.onPreambleData(any(), eq(0), eq(data.length))).thenReturn(5); + when(mockFileListener.onPreambleData( + any(), eq(0), eq(data.length - 5))).thenReturn(preambleLen - 5); + when(mockFileListener.onPreambleData( + any(), eq(0), eq(data.length - preambleLen))).thenReturn(0); + + bufferedFile.onReadReady(mockAsyncFile); + + final ArgumentCaptor arrayCaptor = ArgumentCaptor.forClass(byte[].class); + final ArgumentCaptor posCaptor = ArgumentCaptor.forClass(Integer.class); + final ArgumentCaptor lenCaptor = ArgumentCaptor.forClass(Integer.class); + + verify(mockFileListener).onInboundBuffered(data.length, data.length); + verify(mockFileListener).onInboundPacket( + arrayCaptor.capture(), posCaptor.capture(), lenCaptor.capture()); + verify(mockEventManager).execute(any()); + verify(mockAsyncFile).enableReadEvents(true); + + final byte[] capturedData = arrayCaptor.getValue(); + assertEquals(2, posCaptor.getValue().intValue()); + assertEquals(len1, lenCaptor.getValue().intValue()); + assertEquals((byte) 1, capturedData[2]); + + assertEquals(0, bufferedFile.getOutboundBufferSize()); + assertEquals(0, inboundBuffer.size()); + } + + @Test + public void shutdownReading() throws Exception { + final int maxBufferedInboundPackets = 10; + final int maxBufferedOutboundPackets = 20; + + final StreamingPacketFile file = + createFile(maxBufferedInboundPackets, maxBufferedOutboundPackets); + final BufferedFile bufferedFile = file.getUnderlyingFileForTest(); + + final byte[] data = new byte[100]; + final ReadableDataAnswer dataAnswer = new ReadableDataAnswer(data); + when(mockAsyncFile.read(any(), anyInt(), anyInt())).thenAnswer(dataAnswer); + + doAnswer(new Answer() { + @Override public Object answer(InvocationOnMock invocation) { + file.shutdownReading(); + return Integer.valueOf(-1); + }}).when(mockFileListener).onPreambleData(any(), anyInt(), anyInt()); + + bufferedFile.onReadReady(mockAsyncFile); + + verify(mockFileListener).onInboundBuffered(data.length, data.length); + verify(mockAsyncFile).enableReadEvents(false); + + assertEquals(0, bufferedFile.getInboundBuffer().size()); + } + + private void checkAndResetMocks() { + verifyNoMoreInteractions(ignoreStubs(mockFileListener, mockAsyncFile, mockEventManager, + mockParcelFileDescriptor)); + reset(mockFileListener, mockAsyncFile, mockEventManager); + } + + private StreamingPacketFile createFile( + int maxBufferedInboundPackets, int maxBufferedOutboundPackets) throws Exception { + when(mockEventManager.registerFile(any(), any())).thenReturn(mockAsyncFile); + return new StreamingPacketFile( + mockEventManager, + FileHandle.fromFileDescriptor(mockParcelFileDescriptor), + mockFileListener, + MAX_PACKET_SIZE, + maxBufferedInboundPackets, + maxBufferedOutboundPackets); + } +} diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index bcf89b3417..33821564d7 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -38,6 +38,7 @@ java_library { "net-utils-device-common", "net-utils-device-common-async", "net-utils-device-common-netlink", + "net-utils-device-common-wear", "modules-utils-build_system", ], lint: { strict_updatability_linting: true }, diff --git a/staticlibs/testutils/devicetests/com/android/testutils/async/FakeOsAccess.java b/staticlibs/testutils/devicetests/com/android/testutils/async/FakeOsAccess.java index 1b8e26b30f..48b57d70be 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/async/FakeOsAccess.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/async/FakeOsAccess.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.testutils; +package com.android.testutils.async; import android.os.ParcelFileDescriptor; import android.system.StructPollfd; diff --git a/staticlibs/testutils/devicetests/com/android/testutils/async/RateLimiter.java b/staticlibs/testutils/devicetests/com/android/testutils/async/RateLimiter.java index 137873dbab..d5cca0a4cd 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/async/RateLimiter.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/async/RateLimiter.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.testutils; +package com.android.testutils.async; import com.android.net.module.util.async.OsAccess; diff --git a/staticlibs/testutils/devicetests/com/android/testutils/async/ReadableDataAnswer.java b/staticlibs/testutils/devicetests/com/android/testutils/async/ReadableDataAnswer.java new file mode 100644 index 0000000000..4bf5527055 --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/async/ReadableDataAnswer.java @@ -0,0 +1,76 @@ +/* + * 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 com.android.testutils.async; + +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.util.ArrayList; + +public class ReadableDataAnswer implements Answer { + private final ArrayList mBuffers = new ArrayList<>(); + private int mBufferPos; + + public ReadableDataAnswer(byte[] ... buffers) { + for (byte[] buffer : buffers) { + addBuffer(buffer); + } + } + + public void addBuffer(byte[] buffer) { + if (buffer.length != 0) { + mBuffers.add(buffer); + } + } + + public int getRemainingSize() { + int totalSize = 0; + for (byte[] buffer : mBuffers) { + totalSize += buffer.length; + } + return totalSize - mBufferPos; + } + + private void cleanupBuffers() { + if (!mBuffers.isEmpty() && mBufferPos == mBuffers.get(0).length) { + mBuffers.remove(0); + mBufferPos = 0; + } + } + + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + cleanupBuffers(); + + if (mBuffers.isEmpty()) { + return Integer.valueOf(0); + } + + byte[] src = mBuffers.get(0); + + byte[] dst = invocation.getArgument(0); + int dstPos = invocation.getArgument(1); + int dstLen = invocation.getArgument(2); + + int copyLen = Math.min(dstLen, src.length - mBufferPos); + System.arraycopy(src, mBufferPos, dst, dstPos, copyLen); + mBufferPos += copyLen; + + cleanupBuffers(); + return Integer.valueOf(copyLen); + } +} From 5f95a67eef006f9cef5369ff4dd334fd4efaa3b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Mon, 17 Apr 2023 09:10:14 +0000 Subject: [PATCH 680/777] IpUtils - make checksum work with empty/zero buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit also: - document buffer endianness assumption - simplify fold logic - it cannot overflow Test: TreeHugger, atest NetworkStaticLibTests Signed-off-by: Maciej Żenczykowski Change-Id: I521a7377d1310c0e9c46a5dff95dca451e5f889e --- .../com/android/net/module/util/IpUtils.java | 16 +++++++++------- .../com/android/net/module/util/IpUtilsTest.java | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/IpUtils.java b/staticlibs/framework/com/android/net/module/util/IpUtils.java index 569733edad..18d96f30a0 100644 --- a/staticlibs/framework/com/android/net/module/util/IpUtils.java +++ b/staticlibs/framework/com/android/net/module/util/IpUtils.java @@ -16,6 +16,8 @@ package com.android.net.module.util; +import com.android.internal.annotations.VisibleForTesting; + import static android.system.OsConstants.IPPROTO_ICMPV6; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; @@ -42,8 +44,9 @@ public class IpUtils { * payload) or ICMP checksum on the specified portion of a ByteBuffer. The seed * allows the checksum to commence with a specified value. */ - private static int checksum(ByteBuffer buf, int seed, int start, int end) { - int sum = seed; + @VisibleForTesting + public static int checksum(ByteBuffer buf, int seed, int start, int end) { + int sum = seed + 0xFFFF; // to make things work with empty / zero-filled buffer final int bufPosition = buf.position(); // set position of original ByteBuffer, so that the ShortBuffer @@ -69,13 +72,12 @@ public class IpUtils { b += 256; } - sum += b * 256; + sum += b * 256; // assumes bytebuffer is network order (ie. big endian) } - sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF); - sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF); - int negated = ~sum; - return intAbs((short) negated); + sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF); // max sum is 0x1FFFE + sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF); // max sum is 0xFFFF + return sum ^ 0xFFFF; // u16 bitwise negation } private static int pseudoChecksumIPv4( diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/IpUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/IpUtilsTest.java index 20555b353b..d57023caf1 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/IpUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/IpUtilsTest.java @@ -73,6 +73,20 @@ public class IpUtilsTest { // "hello") // print JavaPacketDefinition(str(packet)) + @Test + public void testEmptyAndZeroBufferChecksum() throws Exception { + ByteBuffer packet = ByteBuffer.wrap(new byte[] { (byte) 0x00, (byte) 0x00, }); + // the following should *not* return 0xFFFF + assertEquals(0, IpUtils.checksum(packet, 0, 0, 0)); + assertEquals(0, IpUtils.checksum(packet, 0, 0, 1)); + assertEquals(0, IpUtils.checksum(packet, 0, 0, 2)); + assertEquals(0, IpUtils.checksum(packet, 0, 1, 2)); + assertEquals(0, IpUtils.checksum(packet, 0xFFFF, 0, 0)); + assertEquals(0, IpUtils.checksum(packet, 0xFFFF, 0, 1)); + assertEquals(0, IpUtils.checksum(packet, 0xFFFF, 0, 2)); + assertEquals(0, IpUtils.checksum(packet, 0xFFFF, 1, 2)); + } + @Test public void testIpv6TcpChecksum() throws Exception { // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80) / From 99d78d81b04ed8fcf6d21738a9e3cec5542780e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 21 Apr 2023 01:28:40 -0700 Subject: [PATCH 681/777] NetlinkUtilsTest: add an assumption to testGetNeighborsQuery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit after: com.android.net.moduletests.util.netlink.NetlinkUtilsTest#testGetNeighborsQuery: ASSUMPTION_FAILED Bug: 200221182 Test: TreeHugger, atest NetworkStaticLibTests Signed-off-by: Maciej Żenczykowski Change-Id: I556a3a52339e5e2343b02d2b2b67b486cb9b2033 --- .../android/net/module/util/netlink/NetlinkUtilsTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java index 7a1639aeb5..dbd31ea4c1 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertEquals; 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 android.content.Context; import android.system.ErrnoException; @@ -51,6 +52,8 @@ import org.junit.runner.RunWith; import java.io.FileDescriptor; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.nio.file.Files; +import java.nio.file.Paths; @RunWith(AndroidJUnit4.class) @SmallTest @@ -82,6 +85,8 @@ public class NetlinkUtilsTest { // Apps targeting an SDK version > S are not allowed to send RTM_GETNEIGH{TBL} messages if (SdkLevel.isAtLeastT() && targetSdk > 31) { + var ctxt = new String(Files.readAllBytes(Paths.get("/proc/thread-self/attr/current"))); + assumeFalse("must not be platform app", ctxt.startsWith("u:r:platform_app:s0:")); try { NetlinkUtils.sendMessage(fd, req, 0, req.length, TEST_TIMEOUT_MS); fail("RTM_GETNEIGH is not allowed for apps targeting SDK > 31 on T+ platforms," From 2689f8fcb12d4e296899fa5cea5cfd7f37275e81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 21 Apr 2023 10:28:37 +0000 Subject: [PATCH 682/777] fix typo in NetlinkUtilsTest TAG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I2776eda17f4998129056a432029f6040365662f8 --- .../com/android/net/module/util/netlink/NetlinkUtilsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java index 7a1639aeb5..91c47d548e 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java @@ -55,7 +55,7 @@ import java.nio.ByteOrder; @RunWith(AndroidJUnit4.class) @SmallTest public class NetlinkUtilsTest { - private static final String TAG = "NetlinkUitlsTest"; + private static final String TAG = "NetlinkUtilsTest"; private static final int TEST_SEQNO = 5; private static final int TEST_TIMEOUT_MS = 500; From ba2e01d0670e045dd7382e22505446c774de6eff Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Fri, 3 Mar 2023 20:43:30 +0900 Subject: [PATCH 683/777] Add InetDiagMessage.destroyLiveTcpSocket Implement NetdNativeService::socketDestroy in Java Bug: 270298713 Test: atest NetworkStaticLibTests Change-Id: I514abed84655cbdbf708cac159a6325eefb8d06b --- .../module/util/netlink/InetDiagMessage.java | 214 +++++++++++++++++- .../net/module/util/netlink/NetlinkUtils.java | 2 +- .../util/netlink/InetDiagSocketTest.java | 146 ++++++++++++ 3 files changed, 352 insertions(+), 10 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java index 0a2f50d8ac..d462c53a68 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java @@ -19,32 +19,48 @@ package com.android.net.module.util.netlink; import static android.os.Process.INVALID_UID; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.ENOENT; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.NETLINK_INET_DIAG; +import static com.android.net.module.util.netlink.NetlinkConstants.NLMSG_DONE; +import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DESTROY; import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY; +import static com.android.net.module.util.netlink.NetlinkConstants.hexify; +import static com.android.net.module.util.netlink.NetlinkConstants.stringForAddressFamily; +import static com.android.net.module.util.netlink.NetlinkConstants.stringForProtocol; import static com.android.net.module.util.netlink.NetlinkUtils.DEFAULT_RECV_BUFSIZE; +import static com.android.net.module.util.netlink.NetlinkUtils.IO_TIMEOUT_MS; +import static com.android.net.module.util.netlink.NetlinkUtils.TCP_ALIVE_STATE_FILTER; +import static com.android.net.module.util.netlink.NetlinkUtils.connectSocketToNetlink; import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; import android.net.util.SocketUtils; +import android.os.Process; import android.system.ErrnoException; import android.util.Log; +import android.util.Range; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import java.io.FileDescriptor; import java.io.IOException; import java.io.InterruptedIOException; import java.net.Inet4Address; import java.net.Inet6Address; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; /** * A NetlinkMessage subclass for netlink inet_diag messages. @@ -138,7 +154,8 @@ public class InetDiagMessage extends NetlinkMessage { public StructInetDiagMsg inetDiagMsg; - private InetDiagMessage(@NonNull StructNlMsgHdr header) { + @VisibleForTesting + public InetDiagMessage(@NonNull StructNlMsgHdr header) { super(header); inetDiagMsg = new StructInetDiagMsg(); } @@ -157,6 +174,13 @@ public class InetDiagMessage extends NetlinkMessage { return msg; } + private static void closeSocketQuietly(final FileDescriptor fd) { + try { + SocketUtils.closeSocket(fd); + } catch (IOException ignored) { + } + } + private static int lookupUidByFamily(int protocol, InetSocketAddress local, InetSocketAddress remote, int family, short flags, FileDescriptor fd) @@ -247,13 +271,7 @@ public class InetDiagMessage extends NetlinkMessage { | InterruptedIOException e) { Log.e(TAG, e.toString()); } finally { - if (fd != null) { - try { - SocketUtils.closeSocket(fd); - } catch (IOException e) { - Log.e(TAG, e.toString()); - } - } + closeSocketQuietly(fd); } return uid; } @@ -269,7 +287,185 @@ public class InetDiagMessage extends NetlinkMessage { (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_DUMP) /* flag */, 0 /* pad */, 1 << NetlinkConstants.INET_DIAG_MEMINFO /* idiagExt */, - NetlinkUtils.TCP_MONITOR_STATE_FILTER); + TCP_ALIVE_STATE_FILTER); + } + + private static void sendNetlinkDestroyRequest(FileDescriptor fd, int proto, + InetDiagMessage diagMsg) throws InterruptedIOException, ErrnoException { + final byte[] destroyMsg = InetDiagMessage.inetDiagReqV2( + proto, + diagMsg.inetDiagMsg.id, + diagMsg.inetDiagMsg.idiag_family, + SOCK_DESTROY, + (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_ACK), + 0 /* pad */, + 0 /* idiagExt */, + 1 << diagMsg.inetDiagMsg.idiag_state + ); + NetlinkUtils.sendMessage(fd, destroyMsg, 0, destroyMsg.length, IO_TIMEOUT_MS); + NetlinkUtils.receiveNetlinkAck(fd); + } + + private static void sendNetlinkDumpRequest(FileDescriptor fd, int proto, int states, int family) + throws InterruptedIOException, ErrnoException { + final byte[] dumpMsg = InetDiagMessage.inetDiagReqV2( + proto, + null /* id */, + family, + SOCK_DIAG_BY_FAMILY, + (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_DUMP), + 0 /* pad */, + 0 /* idiagExt */, + states); + NetlinkUtils.sendMessage(fd, dumpMsg, 0, dumpMsg.length, IO_TIMEOUT_MS); + } + + private static int processNetlinkDumpAndDestroySockets(FileDescriptor dumpFd, + FileDescriptor destroyFd, int proto, Predicate filter) + throws InterruptedIOException, ErrnoException { + int destroyedSockets = 0; + + while (true) { + final ByteBuffer buf = NetlinkUtils.recvMessage( + dumpFd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT_MS); + + while (buf.remaining() > 0) { + final int position = buf.position(); + final NetlinkMessage nlMsg = NetlinkMessage.parse(buf, NETLINK_INET_DIAG); + if (nlMsg == null) { + // Move to the position where parse started for error log. + buf.position(position); + Log.e(TAG, "Failed to parse netlink message: " + hexify(buf)); + break; + } + + if (nlMsg.getHeader().nlmsg_type == NLMSG_DONE) { + return destroyedSockets; + } + + if (!(nlMsg instanceof InetDiagMessage)) { + Log.wtf(TAG, "Received unexpected netlink message: " + nlMsg); + continue; + } + + final InetDiagMessage diagMsg = (InetDiagMessage) nlMsg; + if (filter.test(diagMsg)) { + try { + sendNetlinkDestroyRequest(destroyFd, proto, diagMsg); + destroyedSockets++; + } catch (InterruptedIOException | ErrnoException e) { + if (!(e instanceof ErrnoException + && ((ErrnoException) e).errno == ENOENT)) { + Log.e(TAG, "Failed to destroy socket: diagMsg=" + diagMsg + ", " + e); + } + } + } + } + } + } + + /** + * Returns whether the InetDiagMessage is for adb socket or not + */ + @VisibleForTesting + public static boolean isAdbSocket(final InetDiagMessage msg) { + // This is inaccurate since adb could run with ROOT_UID or other services can run with + // SHELL_UID. But this check covers most cases and enough. + // Note that getting service.adb.tcp.port system property is prohibited by sepolicy + // TODO: skip the socket only if there is a listen socket owned by SHELL_UID with the same + // source port as this socket + return msg.inetDiagMsg.idiag_uid == Process.SHELL_UID; + } + + /** + * Returns whether the range contains the uid in the InetDiagMessage or not + */ + @VisibleForTesting + public static boolean containsUid(InetDiagMessage msg, Set> ranges) { + for (final Range range: ranges) { + if (range.contains(msg.inetDiagMsg.idiag_uid)) { + return true; + } + } + return false; + } + + private static boolean isLoopbackAddress(InetAddress addr) { + if (addr.isLoopbackAddress()) return true; + if (!(addr instanceof Inet6Address)) return false; + + // Following check is for v4-mapped v6 address. StructInetDiagSockId contains v4-mapped v6 + // address as Inet6Address, See StructInetDiagSockId#parse + final byte[] addrBytes = addr.getAddress(); + for (int i = 0; i < 10; i++) { + if (addrBytes[i] != 0) return false; + } + return addrBytes[10] == (byte) 0xff + && addrBytes[11] == (byte) 0xff + && addrBytes[12] == 127; + } + + /** + * Returns whether the socket address in the InetDiagMessage is loopback or not + */ + @VisibleForTesting + public static boolean isLoopback(InetDiagMessage msg) { + final InetAddress srcAddr = msg.inetDiagMsg.id.locSocketAddress.getAddress(); + final InetAddress dstAddr = msg.inetDiagMsg.id.remSocketAddress.getAddress(); + return isLoopbackAddress(srcAddr) + || isLoopbackAddress(dstAddr) + || srcAddr.equals(dstAddr); + } + + private static void destroySockets(int proto, int states, Predicate filter) + throws ErrnoException, SocketException, InterruptedIOException { + FileDescriptor dumpFd = null; + FileDescriptor destroyFd = null; + + try { + dumpFd = NetlinkUtils.createNetLinkInetDiagSocket(); + destroyFd = NetlinkUtils.createNetLinkInetDiagSocket(); + connectSocketToNetlink(dumpFd); + connectSocketToNetlink(destroyFd); + + for (int family : List.of(AF_INET, AF_INET6)) { + try { + sendNetlinkDumpRequest(dumpFd, proto, states, family); + } catch (InterruptedIOException | ErrnoException e) { + Log.e(TAG, "Failed to send netlink dump request: " + e); + continue; + } + final int destroyedSockets = processNetlinkDumpAndDestroySockets( + dumpFd, destroyFd, proto, filter); + Log.d(TAG, "Destroyed " + destroyedSockets + " sockets" + + ", proto=" + stringForProtocol(proto) + + ", family=" + stringForAddressFamily(family) + + ", states=" + states); + } + } finally { + closeSocketQuietly(dumpFd); + closeSocketQuietly(destroyFd); + } + } + + /** + * Close tcp sockets that match the following condition + * 1. TCP status is one of TCP_ESTABLISHED, TCP_SYN_SENT, and TCP_SYN_RECV + * 2. Owner uid of socket is not in the exemptUids + * 3. Owner uid of socket is in the ranges + * 4. Socket is not loopback + * 5. Socket is not adb socket + * + * @param ranges target uid ranges + * @param exemptUids uids to skip close socket + */ + public static void destroyLiveTcpSockets(Set> ranges, Set exemptUids) + throws SocketException, InterruptedIOException, ErrnoException { + destroySockets(IPPROTO_TCP, TCP_ALIVE_STATE_FILTER, + (diagMsg) -> !exemptUids.contains(diagMsg.inetDiagMsg.idiag_uid) + && containsUid(diagMsg, ranges) + && !isLoopback(diagMsg) + && !isAdbSocket(diagMsg)); } @Override diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java index d4bf14a479..308ea240ef 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java @@ -56,7 +56,7 @@ public class NetlinkUtils { private static final int TCP_SYN_SENT = 2; private static final int TCP_SYN_RECV = 3; - public static final int TCP_MONITOR_STATE_FILTER = + public static final int TCP_ALIVE_STATE_FILTER = (1 << TCP_ESTABLISHED) | (1 << TCP_SYN_SENT) | (1 << TCP_SYN_RECV); public static final int UNKNOWN_MARK = 0xffffffff; diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java index 30796d24a1..65e99f8296 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java @@ -16,6 +16,8 @@ package com.android.net.module.util.netlink; +import static android.os.Process.ROOT_UID; +import static android.os.Process.SHELL_UID; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.IPPROTO_TCP; @@ -34,6 +36,8 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.net.InetAddresses; +import android.util.ArraySet; +import android.util.Range; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -46,8 +50,11 @@ import org.junit.runner.RunWith; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.List; +import java.util.Set; @RunWith(AndroidJUnit4.class) @SmallTest @@ -543,4 +550,143 @@ public class InetDiagSocketTest { 7 /* ifIndex */, 88 /* cookie */); } + + private void doTestIsLoopback(InetAddress srcAddr, InetAddress dstAddr, boolean expected) { + final InetDiagMessage inetDiagMsg = new InetDiagMessage(new StructNlMsgHdr()); + inetDiagMsg.inetDiagMsg.id = new StructInetDiagSockId( + new InetSocketAddress(srcAddr, 43031), + new InetSocketAddress(dstAddr, 38415) + ); + + assertEquals(expected, InetDiagMessage.isLoopback(inetDiagMsg)); + } + + @Test + public void testIsLoopback() { + doTestIsLoopback( + InetAddresses.parseNumericAddress("127.0.0.1"), + InetAddresses.parseNumericAddress("192.0.2.1"), + true + ); + doTestIsLoopback( + InetAddresses.parseNumericAddress("192.0.2.1"), + InetAddresses.parseNumericAddress("127.7.7.7"), + true + ); + doTestIsLoopback( + InetAddresses.parseNumericAddress("::1"), + InetAddresses.parseNumericAddress("::1"), + true + ); + doTestIsLoopback( + InetAddresses.parseNumericAddress("::1"), + InetAddresses.parseNumericAddress("2001:db8::1"), + true + ); + } + + @Test + public void testIsLoopbackSameSrcDstAddress() { + doTestIsLoopback( + InetAddresses.parseNumericAddress("192.0.2.1"), + InetAddresses.parseNumericAddress("192.0.2.1"), + true + ); + doTestIsLoopback( + InetAddresses.parseNumericAddress("2001:db8::1"), + InetAddresses.parseNumericAddress("2001:db8::1"), + true + ); + } + + @Test + public void testIsLoopbackNonLoopbackSocket() { + doTestIsLoopback( + InetAddresses.parseNumericAddress("192.0.2.1"), + InetAddresses.parseNumericAddress("192.0.2.2"), + false + ); + doTestIsLoopback( + InetAddresses.parseNumericAddress("2001:db8::1"), + InetAddresses.parseNumericAddress("2001:db8::2"), + false + ); + } + + @Test + public void testIsLoopbackV4MappedV6() throws UnknownHostException { + // ::FFFF:127.1.2.3 + final byte[] addrLoopbackByte = { + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, + (byte) 0x7f, (byte) 0x01, (byte) 0x02, (byte) 0x03, + }; + // ::FFFF:192.0.2.1 + final byte[] addrNonLoopbackByte1 = { + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01, + }; + // ::FFFF:192.0.2.2 + final byte[] addrNonLoopbackByte2 = { + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, + (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x02, + }; + + final Inet6Address addrLoopback = Inet6Address.getByAddress(null, addrLoopbackByte, -1); + final Inet6Address addrNonLoopback1 = + Inet6Address.getByAddress(null, addrNonLoopbackByte1, -1); + final Inet6Address addrNonLoopback2 = + Inet6Address.getByAddress(null, addrNonLoopbackByte2, -1); + + doTestIsLoopback(addrLoopback, addrNonLoopback1, true); + doTestIsLoopback(addrNonLoopback1, addrNonLoopback2, false); + doTestIsLoopback(addrNonLoopback1, addrNonLoopback1, true); + } + + private void doTestContainsUid(final int uid, final Set> ranges, + final boolean expected) { + final InetDiagMessage inetDiagMsg = new InetDiagMessage(new StructNlMsgHdr()); + inetDiagMsg.inetDiagMsg.idiag_uid = uid; + assertEquals(expected, InetDiagMessage.containsUid(inetDiagMsg, ranges)); + } + + @Test + public void testContainsUid() { + doTestContainsUid(77 /* uid */, + new ArraySet<>(List.of(new Range<>(0, 100))), + true /* expected */); + doTestContainsUid(77 /* uid */, + new ArraySet<>(List.of(new Range<>(77, 77), new Range<>(100, 200))), + true /* expected */); + + doTestContainsUid(77 /* uid */, + new ArraySet<>(List.of(new Range<>(100, 200))), + false /* expected */); + doTestContainsUid(77 /* uid */, + new ArraySet<>(List.of(new Range<>(0, 76), new Range<>(78, 100))), + false /* expected */); + } + + private void doTestIsAdbSocket(final int uid, final boolean expected) { + final InetDiagMessage inetDiagMsg = new InetDiagMessage(new StructNlMsgHdr()); + inetDiagMsg.inetDiagMsg.idiag_uid = uid; + inetDiagMsg.inetDiagMsg.id = new StructInetDiagSockId( + new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::1"), 38417), + new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::2"), 38415) + ); + assertEquals(expected, InetDiagMessage.isAdbSocket(inetDiagMsg)); + } + + @Test + public void testIsAdbSocket() { + final int appUid = 10108; + doTestIsAdbSocket(SHELL_UID, true /* expected */); + doTestIsAdbSocket(ROOT_UID, false /* expected */); + doTestIsAdbSocket(appUid, false /* expected */); + } } From 1e697e55140baa980443ccb5ac8a33479dc1808a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 26 Apr 2023 23:04:59 +0000 Subject: [PATCH 684/777] Added a new #define for U BpfLoader version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See http://cs/h/googleplex-android/platform/superproject/+/udc-dev:system/bpf/libbpf_android/Loader.cpp?l=40 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: If0d75a30f8432f62a1c56aef12efba644fb458d6 --- staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 4939483a32..af7ecd7874 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -43,6 +43,9 @@ // Bpfloader v0.33+ supports {map,prog}.ignore_on_{eng,user,userdebug} #define BPFLOADER_IGNORED_ON_VERSION 33u +// Android U / 14 (api level 34) - various new program types added +#define BPFLOADER_U_VERSION 37u + /* For mainline module use, you can #define BPFLOADER_{MIN/MAX}_VER * before #include "bpf_helpers.h" to change which bpfloaders will * process the resulting .o file. From 59934d185ae5e627001ffd49dde4d5ce97d73394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 26 Apr 2023 23:10:08 +0000 Subject: [PATCH 685/777] Bump the default bpfloader version for platform code. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the default for BPFLOADER_MIN_VER if not otherwise specified. This does not affect mainline code, see: cs/p:aosp-master file:packages/modules/Connectivity/bpf_progs define.*BPFLOADER_MIN_VER Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ice5b14c3b580653f8889a5292abaa89cf8434da1 --- staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h index d286eba001..65540e0117 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h @@ -48,9 +48,8 @@ #define DEFAULT_SIZEOF_BPF_MAP_DEF 32 // v0.0 struct: enum (uint sized) + 7 uint #define DEFAULT_SIZEOF_BPF_PROG_DEF 20 // v0.0 struct: 4 uint + bool + 3 byte alignment pad -// By default, unless otherwise specified, allow the use of features only supported by v0.28, -// which first added working support for map uid != root -#define COMPILE_FOR_BPFLOADER_VERSION 28u +// By default, unless otherwise specified, allow the use of features only supported by v0.37. +#define COMPILE_FOR_BPFLOADER_VERSION 37u /* * The bpf_{map,prog}_def structures are compiled for different architectures. From 9ee26f72eb8d0e81a15a17a56c23ba177e053da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 26 Apr 2023 23:16:49 +0000 Subject: [PATCH 686/777] Remove mentions of bploader versions between S and T MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (they're only of historical interest at this point) Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I0e52efda62626091c3023c5fd3622ffcdcd00ee1 --- staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 4939483a32..eaa39946bd 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -27,13 +27,6 @@ // Android S / 12 (api level 31) - added 'tethering' mainline eBPF support #define BPFLOADER_S_VERSION 2u -// Android T / 13 Beta 3 (api level 33) - added support for 'netd_shared' -#define BPFLOADER_T_BETA3_VERSION 13u - -// v0.18 added support for shared and pindir, but still ignores selinux_content -// v0.19 added support for selinux_content along with the required selinux changes -// and should be available starting with Android T Beta 4 -// // Android T / 13 (api level 33) - support for shared/selinux_context/pindir #define BPFLOADER_T_VERSION 19u @@ -225,7 +218,7 @@ static void (*bpf_ringbuf_submit_unsafe)(const void* data, __u64 flags) = (void* #ifdef THIS_BPF_PROGRAM_IS_FOR_TEST_PURPOSES_ONLY #define BPF_MAP_ASSERT_OK(type, entries, mode) -#elif BPFLOADER_MIN_VER >= BPFLOADER_T_BETA3_VERSION +#elif BPFLOADER_MIN_VER >= BPFLOADER_T_VERSION #define BPF_MAP_ASSERT_OK(type, entries, mode) #else #define BPF_MAP_ASSERT_OK(type, entries, mode) \ From 58546f4046612cb6c7dec8f0b505ef403498bb46 Mon Sep 17 00:00:00 2001 From: Yuyang Huang Date: Mon, 24 Apr 2023 13:33:46 +0900 Subject: [PATCH 687/777] Refactors common scope id setup code into utility function Bug: 279691947 Test: atest NetworkStackIntegrationTests NetworkStackRootTests Test: atest CtsNetTestCases:android.net.cts.NsdManagerTest Change-Id: I81ab8d53a9c3b2641915a3cbfaf182c0962a3d55 --- .../net/module/util/InetAddressUtils.java | 22 ++++++++++++++++ .../net/module/util/InetAddressUtilsTest.java | 25 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java b/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java index 31d0729709..40fc59fb6d 100644 --- a/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java +++ b/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java @@ -16,7 +16,10 @@ package com.android.net.module.util; +import android.annotation.NonNull; import android.os.Parcel; +import android.util.Log; + import java.net.Inet6Address; import java.net.InetAddress; @@ -28,6 +31,7 @@ import java.net.UnknownHostException; */ public class InetAddressUtils { + private static final String TAG = InetAddressUtils.class.getSimpleName(); private static final int INET6_ADDR_LENGTH = 16; /** @@ -71,5 +75,23 @@ public class InetAddressUtils { } } + /** + * Create a Inet6Address with scope id if it is a link local address. Otherwise, returns the + * original address. + */ + public static Inet6Address withScopeId(@NonNull final Inet6Address addr, int scopeid) { + if (!addr.isLinkLocalAddress()) { + return addr; + } + try { + return Inet6Address.getByAddress(null /* host */, addr.getAddress(), + scopeid); + } catch (UnknownHostException impossible) { + Log.wtf(TAG, "Cannot construct scoped Inet6Address with Inet6Address.getAddress(" + + addr.getHostAddress() + "): ", impossible); + return null; + } + } + private InetAddressUtils() {} } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/InetAddressUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/InetAddressUtilsTest.java index 2736c53ce8..bb2b9332a4 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/InetAddressUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/InetAddressUtilsTest.java @@ -18,6 +18,10 @@ package com.android.net.module.util; import static junit.framework.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.net.InetAddresses; import android.os.Parcel; import androidx.test.filters.SmallTest; @@ -67,4 +71,25 @@ public class InetAddressUtilsTest { assertEquals(ipv6, out); assertEquals(42, out.getScopeId()); } + + @Test + public void testWithScopeId() { + final int scopeId = 999; + + final String globalAddrStr = "2401:fa00:49c:484:dc41:e6ff:fefd:f180"; + final Inet6Address globalAddr = (Inet6Address) InetAddresses + .parseNumericAddress(globalAddrStr); + final Inet6Address updatedGlobalAddr = InetAddressUtils.withScopeId(globalAddr, scopeId); + assertFalse(updatedGlobalAddr.isLinkLocalAddress()); + assertEquals(globalAddrStr, updatedGlobalAddr.getHostAddress()); + assertEquals(0, updatedGlobalAddr.getScopeId()); + + final String localAddrStr = "fe80::4735:9628:d038:2087"; + final Inet6Address localAddr = (Inet6Address) InetAddresses + .parseNumericAddress(localAddrStr); + final Inet6Address updatedLocalAddr = InetAddressUtils.withScopeId(localAddr, scopeId); + assertTrue(updatedLocalAddr.isLinkLocalAddress()); + assertEquals(localAddrStr + "%" + scopeId, updatedLocalAddr.getHostAddress()); + assertEquals(scopeId, updatedLocalAddr.getScopeId()); + } } From 873548b3f8f07985bec02282fc653367362299cf Mon Sep 17 00:00:00 2001 From: chiachangwang Date: Thu, 27 Apr 2023 15:09:31 +0000 Subject: [PATCH 688/777] Add ICMP header length constant Bug: 277376698 Test: m Change-Id: I7edcf0f809bb9d5fa72e2c70110efabbaa349adf --- .../com/android/net/module/util/NetworkStackConstants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index aa2dd4c1c8..96f6aaceec 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -135,7 +135,7 @@ public final class NetworkStackConstants { * - https://tools.ietf.org/html/rfc792 */ public static final int ICMP_CHECKSUM_OFFSET = 2; - + public static final int ICMP_HEADER_LEN = 8; /** * ICMPv6 constants. * From 8c4fd4bf0bd80d2536c465a8546d01d537c63d25 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 9 Feb 2023 19:32:00 +0900 Subject: [PATCH 689/777] Allow using isFeatureEnabled on APEX module init isFeatureEnabled is not usable in APEX module service initialization, as it relies on PackageManager.getModuleInfo, which is only available once the module controller is initialized. Also, there is no module metadata in base AOSP. Avoid this by guessing the tethering module name based on its APK-in-APEX packages, which can be queried at that time. ConnectivityServiceResources will indicate the package prefix used on the device. If querying with prefix + "tethering" fails, retry querying with prefix + "go.tethering" for Go devices. This should allow using isFeatureEnabled in services (like ConnectivityService) constructors, and allows removing the FIXED_PACKAGE_VERSION hack when Tethering is not considered a module. getConnectivityResourcesPackageName is implemented based on existing code in ConnectivityResources.java. aosp/2446026 updates ConnectivityResources to use getConnectivityResourcesPackageName. Bug: 279108992 Test: atest Change-Id: I277f4583e92ba41d53bd19666f1e8e29f68dfcd1 --- .../net/module/util/DeviceConfigUtils.java | 104 ++++++++++++------ .../module/util/DeviceConfigUtilsTest.java | 88 ++++++++++----- 2 files changed, 127 insertions(+), 65 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index f8f250d745..dae4eb913f 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -16,9 +16,12 @@ package com.android.net.module.util; +import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; + import android.content.Context; -import android.content.pm.ModuleInfo; +import android.content.Intent; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.provider.DeviceConfig; import android.util.Log; @@ -28,6 +31,9 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import java.util.ArrayList; +import java.util.List; + /** * Utilities for modules to query {@link DeviceConfig} and flags. */ @@ -42,6 +48,11 @@ public final class DeviceConfigUtils { */ public static final String TETHERING_MODULE_NAME = "com.android.tethering"; + @VisibleForTesting + public static final String RESOURCES_APK_INTENT = + "com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK"; + private static final String CONNECTIVITY_RES_PKG_DIR = "/apex/" + TETHERING_MODULE_NAME + "/"; + @VisibleForTesting public static void resetPackageVersionCacheForTest() { sPackageVersion = -1; @@ -189,8 +200,13 @@ public final class DeviceConfigUtils { */ public static boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, @NonNull String name, @NonNull String moduleName, boolean defaultEnabled) { + // TODO: migrate callers to a non-generic isTetheringFeatureEnabled method. + if (!TETHERING_MODULE_NAME.equals(moduleName)) { + throw new IllegalArgumentException( + "This method is only usable by the tethering module"); + } try { - final long packageVersion = getModuleVersion(context, moduleName); + final long packageVersion = getTetheringModuleVersion(context); return isFeatureEnabled(context, packageVersion, namespace, name, defaultEnabled); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Could not find the module name", e); @@ -198,14 +214,6 @@ public final class DeviceConfigUtils { } } - private static boolean maybeUseFixedPackageVersion(@NonNull Context context) { - final String packageName = context.getPackageName(); - if (packageName == null) return false; - - return packageName.equals("com.android.networkstack.tethering") - || packageName.equals("com.android.networkstack.tethering.inprocess"); - } - private static boolean isFeatureEnabled(@NonNull Context context, long packageVersion, @NonNull String namespace, String name, boolean defaultEnabled) throws PackageManager.NameNotFoundException { @@ -215,36 +223,40 @@ public final class DeviceConfigUtils { || (propertyVersion != 0 && packageVersion >= (long) propertyVersion); } + // Guess the tethering module name based on the package prefix of the connectivity resources + // Take the resource package name, cut it before "connectivity" and append "tethering". + // Then resolve that package version number with packageManager. + // If that fails retry by appending "go.tethering" instead + private static long resolveTetheringModuleVersion(@NonNull Context context) + throws PackageManager.NameNotFoundException { + final String connResourcesPackage = getConnectivityResourcesPackageName(context); + final int pkgPrefixLen = connResourcesPackage.indexOf("connectivity"); + if (pkgPrefixLen < 0) { + throw new IllegalStateException( + "Invalid connectivity resources package: " + connResourcesPackage); + } + + final String pkgPrefix = connResourcesPackage.substring(0, pkgPrefixLen); + final PackageManager packageManager = context.getPackageManager(); + try { + return packageManager.getPackageInfo(pkgPrefix + "tethering", + PackageManager.MATCH_APEX).getLongVersionCode(); + } catch (PackageManager.NameNotFoundException e) { + Log.d(TAG, "Device is using go modules"); + // fall through + } + + return packageManager.getPackageInfo(pkgPrefix + "go.tethering", + PackageManager.MATCH_APEX).getLongVersionCode(); + } + private static volatile long sModuleVersion = -1; - @VisibleForTesting public static long FIXED_PACKAGE_VERSION = 10; - private static long getModuleVersion(@NonNull Context context, @NonNull String moduleName) + private static long getTetheringModuleVersion(@NonNull Context context) throws PackageManager.NameNotFoundException { if (sModuleVersion >= 0) return sModuleVersion; - final PackageManager packageManager = context.getPackageManager(); - ModuleInfo module; - try { - module = packageManager.getModuleInfo( - moduleName, PackageManager.MODULE_APEX_NAME); - } catch (PackageManager.NameNotFoundException e) { - // The error may happen if mainline module meta data is not installed e.g. there are - // no meta data configuration in AOSP build. To be able to enable a feature in AOSP - // by setting a flag via ADB for example. set a small non-zero fixed number for - // comparing. - if (maybeUseFixedPackageVersion(context)) { - sModuleVersion = FIXED_PACKAGE_VERSION; - return FIXED_PACKAGE_VERSION; - } else { - throw e; - } - } - String modulePackageName = module.getPackageName(); - if (modulePackageName == null) throw new PackageManager.NameNotFoundException(moduleName); - final long version = packageManager.getPackageInfo(modulePackageName, - PackageManager.MATCH_APEX).getLongVersionCode(); - sModuleVersion = version; - - return version; + sModuleVersion = resolveTetheringModuleVersion(context); + return sModuleVersion; } /** @@ -272,4 +284,24 @@ public final class DeviceConfigUtils { return defaultValue; } } + + /** + * Get the package name of the ServiceConnectivityResources package, used to provide resources + * for service-connectivity. + */ + @NonNull + public static String getConnectivityResourcesPackageName(@NonNull Context context) { + final List pkgs = new ArrayList<>(context.getPackageManager() + .queryIntentActivities(new Intent(RESOURCES_APK_INTENT), MATCH_SYSTEM_ONLY)); + pkgs.removeIf(pkg -> !pkg.activityInfo.applicationInfo.sourceDir.startsWith( + CONNECTIVITY_RES_PKG_DIR)); + if (pkgs.size() > 1) { + Log.wtf(TAG, "More than one connectivity resources package found: " + pkgs); + } + if (pkgs.isEmpty()) { + throw new IllegalStateException("No connectivity resource package found"); + } + + return pkgs.get(0).activityInfo.applicationInfo.packageName; + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java index a8e7993ae9..b75939b9b4 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -16,25 +16,30 @@ package com.android.net.module.util; +import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; + import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; -import static com.android.net.module.util.DeviceConfigUtils.FIXED_PACKAGE_VERSION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; -import android.content.pm.ModuleInfo; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.provider.DeviceConfig; @@ -49,6 +54,8 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.MockitoSession; +import java.util.Arrays; + /** * Tests for DeviceConfigUtils. @@ -66,14 +73,23 @@ public class DeviceConfigUtilsTest { private static final int TEST_MIN_FLAG_VALUE = 100; private static final long TEST_PACKAGE_VERSION = 290000000; private static final String TEST_PACKAGE_NAME = "test.package.name"; - private static final String TETHERING_AOSP_PACKAGE_NAME = "com.android.networkstack.tethering"; - private static final String TEST_APEX_NAME = "test.apex.name"; + // The APEX name is the name of the APEX module, as in android.content.pm.ModuleInfo, and is + // used for its mount point in /apex. APEX packages are actually APKs with a different + // file extension, so they have an AndroidManifest: the APEX package name is the package name in + // that manifest, and is reflected in android.content.pm.ApplicationInfo. Contrary to the APEX + // (module) name, different package names are typically used to identify the organization that + // built and signed the APEX modules. + private static final String TEST_APEX_NAME = "com.android.tethering"; + private static final String TEST_APEX_PACKAGE_NAME = "com.prefix.android.tethering"; + private static final String TEST_GO_APEX_PACKAGE_NAME = "com.prefix.android.go.tethering"; + private static final String TEST_CONNRES_PACKAGE_NAME = + "com.prefix.android.connectivity.resources"; + private final PackageInfo mPackageInfo = new PackageInfo(); + private final PackageInfo mApexPackageInfo = new PackageInfo(); private MockitoSession mSession; @Mock private Context mContext; @Mock private PackageManager mPm; - @Mock private ModuleInfo mMi; - @Mock private PackageInfo mPi; @Mock private Resources mResources; @Before @@ -81,15 +97,26 @@ public class DeviceConfigUtilsTest { MockitoAnnotations.initMocks(this); mSession = mockitoSession().spyStatic(DeviceConfig.class).startMocking(); - final PackageInfo pi = new PackageInfo(); - pi.setLongVersionCode(TEST_PACKAGE_VERSION); + mPackageInfo.setLongVersionCode(TEST_PACKAGE_VERSION); + mApexPackageInfo.setLongVersionCode(TEST_PACKAGE_VERSION); doReturn(mPm).when(mContext).getPackageManager(); doReturn(TEST_PACKAGE_NAME).when(mContext).getPackageName(); - doReturn(mMi).when(mPm).getModuleInfo(eq(TEST_APEX_NAME), anyInt()); - doReturn(TEST_PACKAGE_NAME).when(mMi).getPackageName(); - doReturn(pi).when(mPm).getPackageInfo(anyString(), anyInt()); + doThrow(NameNotFoundException.class).when(mPm).getPackageInfo(anyString(), anyInt()); + doReturn(mPackageInfo).when(mPm).getPackageInfo(eq(TEST_PACKAGE_NAME), anyInt()); + doReturn(mApexPackageInfo).when(mPm).getPackageInfo(eq(TEST_APEX_PACKAGE_NAME), anyInt()); + doReturn(mResources).when(mContext).getResources(); + + final ResolveInfo ri = new ResolveInfo(); + ri.activityInfo = new ActivityInfo(); + ri.activityInfo.applicationInfo = new ApplicationInfo(); + ri.activityInfo.applicationInfo.packageName = TEST_CONNRES_PACKAGE_NAME; + ri.activityInfo.applicationInfo.sourceDir = + "/apex/com.android.tethering/priv-app/ServiceConnectivityResources@version"; + doReturn(Arrays.asList(ri)).when(mPm).queryIntentActivities(argThat( + intent -> intent.getAction().equals(DeviceConfigUtils.RESOURCES_APK_INTENT)), + eq(MATCH_SYSTEM_ONLY)); } @After @@ -223,35 +250,32 @@ public class DeviceConfigUtilsTest { TEST_EXPERIMENT_FLAG)); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); - doThrow(NameNotFoundException.class).when(mPm).getModuleInfo(anyString(), anyInt()); - assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); } - @Test - public void testFeatureIsEnabledUsingFixedVersion() throws Exception { - doReturn(TETHERING_AOSP_PACKAGE_NAME).when(mContext).getPackageName(); - doThrow(NameNotFoundException.class).when(mPm).getModuleInfo(anyString(), anyInt()); - - doReturn(Long.toString(FIXED_PACKAGE_VERSION)).when(() -> DeviceConfig.getProperty( + public void testFeatureIsEnabledOnGo() throws Exception { + doThrow(NameNotFoundException.class).when(mPm).getPackageInfo( + eq(TEST_APEX_PACKAGE_NAME), anyInt()); + doReturn(mApexPackageInfo).when(mPm).getPackageInfo( + eq(TEST_GO_APEX_PACKAGE_NAME), anyInt()); + doReturn("0").when(() -> DeviceConfig.getProperty( eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); - doReturn(Long.toString(FIXED_PACKAGE_VERSION + 1)).when(() -> DeviceConfig.getProperty( - eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); + assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG)); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, true /* defaultEnabled */)); - doReturn(Long.toString(FIXED_PACKAGE_VERSION - 1)).when(() -> DeviceConfig.getProperty( - eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); + doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), + eq(TEST_EXPERIMENT_FLAG))); assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); } @Test - public void testFeatureIsEnabledCaching() throws Exception { + public void testFeatureIsEnabledCaching_APK() throws Exception { doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, @@ -263,14 +287,20 @@ public class DeviceConfigUtilsTest { verify(mContext, times(1)).getPackageManager(); verify(mContext, times(1)).getPackageName(); verify(mPm, times(1)).getPackageInfo(anyString(), anyInt()); + } + @Test + public void testFeatureIsEnabledCaching_APEX() throws Exception { + doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), + eq(TEST_EXPERIMENT_FLAG))); assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); - // Module info is only queried once - verify(mPm, times(1)).getModuleInfo(anyString(), anyInt()); + // Package info is only queried once + verify(mPm, times(1)).getPackageInfo(anyString(), anyInt()); + verify(mContext, never()).getPackageName(); } @Test From e4eb87ae3af1adfa7700fff6da3d09a339cfbedb Mon Sep 17 00:00:00 2001 From: Yuyang Huang Date: Tue, 2 May 2023 18:44:51 +0900 Subject: [PATCH 690/777] Move Hexdump.java to framework/ Move Hexdump.java to framework/ to make it accessible from other framework class. Test: m Change-Id: If92b7f0e09edc65071152197c3894d4a652c1853 --- staticlibs/Android.bp | 6 ++---- .../com/android/net/module/util/HexDump.java | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) rename staticlibs/{device => framework}/com/android/net/module/util/HexDump.java (99%) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index b1c653d8c9..dad60f9c0a 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -36,7 +36,6 @@ java_library { srcs: [ "device/com/android/net/module/util/DeviceConfigUtils.java", "device/com/android/net/module/util/FdEventsReader.java", - "device/com/android/net/module/util/HexDump.java", "device/com/android/net/module/util/NetworkMonitorUtils.java", "device/com/android/net/module/util/PacketReader.java", "device/com/android/net/module/util/SharedLog.java", @@ -121,11 +120,11 @@ java_library { "device/com/android/net/module/util/BpfDump.java", "device/com/android/net/module/util/BpfMap.java", "device/com/android/net/module/util/BpfUtils.java", - "device/com/android/net/module/util/HexDump.java", "device/com/android/net/module/util/IBpfMap.java", "device/com/android/net/module/util/JniUtil.java", "device/com/android/net/module/util/Struct.java", "device/com/android/net/module/util/TcUtils.java", + "framework/com/android/net/module/util/HexDump.java", ], sdk_version: "module_current", min_sdk_version: "29", @@ -149,7 +148,6 @@ java_library { java_library { name: "net-utils-device-common-struct", srcs: [ - "device/com/android/net/module/util/HexDump.java", "device/com/android/net/module/util/Ipv6Utils.java", "device/com/android/net/module/util/PacketBuilder.java", "device/com/android/net/module/util/Struct.java", @@ -371,10 +369,10 @@ java_library { sdk_version: "core_platform", srcs: [ "device/com/android/net/module/util/FdEventsReader.java", - "device/com/android/net/module/util/HexDump.java", "device/com/android/net/module/util/SharedLog.java", "framework/com/android/net/module/util/ByteUtils.java", "framework/com/android/net/module/util/CollectionUtils.java", + "framework/com/android/net/module/util/HexDump.java", "framework/com/android/net/module/util/LinkPropertiesUtils.java", ], libs: [ diff --git a/staticlibs/device/com/android/net/module/util/HexDump.java b/staticlibs/framework/com/android/net/module/util/HexDump.java similarity index 99% rename from staticlibs/device/com/android/net/module/util/HexDump.java rename to staticlibs/framework/com/android/net/module/util/HexDump.java index a27c0a3c95..a22c258d0a 100644 --- a/staticlibs/device/com/android/net/module/util/HexDump.java +++ b/staticlibs/framework/com/android/net/module/util/HexDump.java @@ -20,6 +20,8 @@ import androidx.annotation.Nullable; /** * Hex utility functions. + * + * @hide */ public class HexDump { private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', From 783a3b82ae2384a944aea9961710bb731bff07aa Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 24 Apr 2023 17:15:22 +0800 Subject: [PATCH 691/777] Allow BpfMap to be accessed from NetworkStack When loading BpfMap class, JNI part is needed for native methods. Allow the static lib can be compiled with NetworkStack JNI library. Test: atest FrameworksNetTests:android.net.connectivity.com.android.server.BpfNetMapsTest Bug: 276230058 Change-Id: I72ebe801dacd02de6711558d2058c1b756cf3080 --- staticlibs/native/bpfmapjni/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/native/bpfmapjni/Android.bp b/staticlibs/native/bpfmapjni/Android.bp index 8babcce3f7..43d61fc7fb 100644 --- a/staticlibs/native/bpfmapjni/Android.bp +++ b/staticlibs/native/bpfmapjni/Android.bp @@ -46,6 +46,7 @@ cc_library_static { ], visibility: [ "//packages/modules/Connectivity:__subpackages__", + "//packages/modules/NetworkStack:__subpackages__", // TODO: remove after NetworkStatsService moves to the module. "//frameworks/base/packages/ConnectivityT/service", ], From 8d47d844dee4f590514c1828b7251f73018d8a34 Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Fri, 31 Mar 2023 14:59:49 +0800 Subject: [PATCH 692/777] Enable error-prone checking in the net-utils-framework-common Enable error-prone checking in the net-utils-framework-common to catch NullablePrimitive errors during build time. Also fix any NullablePrimitive errors that are found in the library classes. Bug: 256991804 Test: Enable error-prone checking and check if the build fails with any NullablePrimitive errors. If it does, fix the errors and build again. Change-Id: I7e1508d166f258f5232ff39388ac984fbdc6169e --- staticlibs/Android.bp | 8 ++++++++ .../com/android/net/module/util/CollectionUtils.java | 1 - 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index dad60f9c0a..ff65228aa4 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -265,6 +265,14 @@ java_library { "//packages/apps/Settings", ], lint: { strict_updatability_linting: true }, + errorprone: { + enabled: true, + // Error-prone checking only warns of problems when building. To make the build fail with + // these errors, list the specific error-prone problems below. + javacflags: [ + "-Xep:NullablePrimitive:ERROR", + ], + }, } java_library { diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java index f08880cbec..39e7ce9456 100644 --- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java @@ -101,7 +101,6 @@ public final class CollectionUtils { /** * @return The index of the first element that matches the predicate, or -1 if none. */ - @Nullable public static int indexOf(@NonNull final Collection elem, @NonNull final Predicate predicate) { int idx = 0; From 80c797a9457185243b200901edfb942f4cd9ea7a Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 3 May 2023 17:39:48 +0800 Subject: [PATCH 693/777] Define DNS-over-TLS port in static lib The DNS-over-TLS port is a commonly used port number that is typically set to 853 and is unlikely to be changed. To prevent from code duplication in various modules, it would be beneficial to include the port number definition in a static library. Test: TH Bug: 276230058 Change-Id: I7e6d0056ba15c932d9b4c3dd8760924278bde8fe --- .../android/net/module/util/NetworkStackConstants.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 96f6aaceec..8138b584be 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -226,6 +226,14 @@ public final class NetworkStackConstants { public static final int DHCP6_OPTION_IA_PD = 25; public static final int DHCP6_OPTION_IAPREFIX = 26; + /** + * DNS constants. + * + * See also: + * - https://datatracker.ietf.org/doc/html/rfc7858#section-3.1 + */ + public static final short DNS_OVER_TLS_PORT = 853; + /** * IEEE802.11 standard constants. * From 6b8144a07cb6e47ed4162e30e9449b8e4f7452f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 4 May 2023 10:18:34 +0000 Subject: [PATCH 694/777] Revert "Allow BpfMap to be accessed from NetworkStack" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit fbe95d914c707c34d2c9d150a467d51c73414fcd. Reason for revert: I've reconsidered. This is a bad idea. (and there are not yet any users) The NetworkStack is an apk, not an apex, and as such it cannot ship any bpf .o files (since that requires apex disk image format instead of apk/jar zip file format). There's no support for this (NetworkStack shipping bpf) in the current tip-of-tree bpfloader. As such there's no chance of this happening before V. And even in V+ it is *super* unlikely, because... apk... (We'd have to add apk zip traversal into the bpfloader...) As such NetworkStack cannot possibly own any bpf programs/maps, and could only potentially access platform/system bpf maps or bpf maps owned by another module (ie. the Tethering apex). Using any bpf maps from the system is not viable, as these are owned by the platform, and as such may be modified by vendors/oems. Ie. their number, names, key/value layout, etc... cannot be guaranteed. As such using them from mainline code is simply not safe. Furthermore none of the platform bpfs are network related (and indeed bpfloader enforces this). As such this the only potential use of this would be for NetworkStack to use Tethering apex bpf maps/programs. However, this is also unsafe. On older devices (pre-S) we don't even have support for tethering apex shipped programs/maps. On pre-T only the offload program is shipped, while roughly equivalent netd.o maps/programs for the other stuff are still provided by the platform. (but the format of these cannot be relied upon) As such use would have to be limited to T+. (because the offload bpf map isn't interesting to the network stack) But on T+ we run into a cross-module versioning problem: the source (and thus bpf map name/format/struct definitions) used to build the NetworkStack apk and Tethering apex may differ. Even modules shipped in tandem are build from separate release branches. Additionally there's potential for only one module to update, while the other remains older. Thus making this work cross-module would require freezing the map name & format. ie. they would need to become cross-module API. This is not something I'm willing to do. Basically, this can be summarized as: there is no *safe* way for NetworkStack apk to use bpf maps. Test: TreeHugger Bug: 276230058 Signed-off-by: Maciej Żenczykowski Change-Id: I65ecf6ffca6ae88a1b72f6f4c8a5739991d78fe3 --- staticlibs/native/bpfmapjni/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/staticlibs/native/bpfmapjni/Android.bp b/staticlibs/native/bpfmapjni/Android.bp index 43d61fc7fb..8babcce3f7 100644 --- a/staticlibs/native/bpfmapjni/Android.bp +++ b/staticlibs/native/bpfmapjni/Android.bp @@ -46,7 +46,6 @@ cc_library_static { ], visibility: [ "//packages/modules/Connectivity:__subpackages__", - "//packages/modules/NetworkStack:__subpackages__", // TODO: remove after NetworkStatsService moves to the module. "//frameworks/base/packages/ConnectivityT/service", ], From f5847ba9f28df0d13736723eb17a4cf8f411d3e1 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 5 May 2023 17:56:00 +0800 Subject: [PATCH 695/777] Change IaPrefixOption prefix length type to byte. Given the maximum prefix length of IPv6 address is 128 and it should not be assigned via IA prefix option to client, so S8 is enough to represent the prefix-length field. Bug: 260934173 Test: m Change-Id: Ia7fc52f7495775f3a29141d75adffafd84c38a02 --- .../android/net/module/util/structs/IaPrefixOption.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java b/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java index cd974e6f08..060d4915c3 100644 --- a/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java +++ b/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java @@ -62,13 +62,13 @@ public class IaPrefixOption extends Struct { public final long preferred; @Field(order = 3, type = Type.U32) public final long valid; - @Field(order = 4, type = Type.U8) - public final short prefixLen; + @Field(order = 4, type = Type.S8) + public final byte prefixLen; @Field(order = 5, type = Type.ByteArray, arraysize = 16) public final byte[] prefix; IaPrefixOption(final short code, final short length, final long preferred, - final long valid, final short prefixLen, final byte[] prefix) { + final long valid, final byte prefixLen, final byte[] prefix) { this.code = code; this.length = length; this.preferred = preferred; @@ -81,7 +81,7 @@ public class IaPrefixOption extends Struct { * Build an IA_PD prefix option with given specific parameters. */ public static ByteBuffer build(final short length, final long preferred, final long valid, - final short prefixLen, final byte[] prefix) { + final byte prefixLen, final byte[] prefix) { final IaPrefixOption option = new IaPrefixOption((byte) DHCP6_OPTION_IAPREFIX, length /* 25 + IAPrefix options length */, preferred, valid, prefixLen, prefix); return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN)); From 2686cea965f153e9ca2bb0a65531aed603f15fea Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Wed, 29 Mar 2023 15:20:56 +0900 Subject: [PATCH 696/777] Close sockets from ConnectivityService#setFirewallChainEnabled And replace netd.socketDestroy by Java implementation Bug: 270298713 Test: atest FrameworksNetTests CtsNetTestCases Change-Id: I744b98ac1be04a1aede9d96787305e5a1a9d9ae6 --- .../module/util/netlink/InetDiagMessage.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java index d462c53a68..e69a844c61 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java @@ -468,6 +468,23 @@ public class InetDiagMessage extends NetlinkMessage { && !isAdbSocket(diagMsg)); } + /** + * Close tcp sockets that match the following condition + * 1. TCP status is one of TCP_ESTABLISHED, TCP_SYN_SENT, and TCP_SYN_RECV + * 2. Owner uid of socket is in the targetUids + * 3. Socket is not loopback + * 4. Socket is not adb socket + * + * @param ownerUids target uids to close sockets + */ + public static void destroyLiveTcpSocketsByOwnerUids(Set ownerUids) + throws SocketException, InterruptedIOException, ErrnoException { + destroySockets(IPPROTO_TCP, TCP_ALIVE_STATE_FILTER, + (diagMsg) -> ownerUids.contains(diagMsg.inetDiagMsg.idiag_uid) + && !isLoopback(diagMsg) + && !isAdbSocket(diagMsg)); + } + @Override public String toString() { return "InetDiagMessage{ " From 2976065935bb56551132859b7f020b98f481bc6d Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Wed, 10 May 2023 17:47:28 +0900 Subject: [PATCH 697/777] Add message length check in parseNetlinkErrorMessage Address review comment on aosp/2501578 Bug: 280553055 Test: TH, atest CtsNetTestCases Change-Id: I945afc3dcc33dc85de6b00742fcf54e9c1901585 --- .../android/net/module/util/netlink/NetlinkUtils.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java index 308ea240ef..b512a9598b 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java @@ -93,6 +93,15 @@ public class NetlinkUtils { if (nlmsghdr == null || nlmsghdr.nlmsg_type != NetlinkConstants.NLMSG_ERROR) { return null; } + + final int messageLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len); + final int payloadLength = messageLength - StructNlMsgHdr.STRUCT_SIZE; + if (payloadLength < 0 || payloadLength > bytes.remaining()) { + // Malformed message or runt buffer. Pretend the buffer was consumed. + bytes.position(bytes.limit()); + return null; + } + return NetlinkErrorMessage.parse(nlmsghdr, bytes); } From e16a000e826f3bacd21ae5d57e81f6cc104e0f1b Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 21 Apr 2023 14:46:43 +0900 Subject: [PATCH 698/777] Allow subclass of FdEventsReader to process the zero-length packet. Bug: 269692093 Test: atest TetheringIntegrationTests Change-Id: I3afa5791d23e21a5bc3191cdd7bb61f6a4c494f8 --- .../com/android/net/module/util/FdEventsReader.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/staticlibs/device/com/android/net/module/util/FdEventsReader.java b/staticlibs/device/com/android/net/module/util/FdEventsReader.java index 4825992f39..f88883bf22 100644 --- a/staticlibs/device/com/android/net/module/util/FdEventsReader.java +++ b/staticlibs/device/com/android/net/module/util/FdEventsReader.java @@ -179,6 +179,17 @@ public abstract class FdEventsReader { return true; // by default, stop reading on any error. } + /** + * Called by the subclasses of FdEventsReader, decide whether it should stop reading from the + * socket or process the packet and continue to read upon receiving a zero-length packet. + * + * @return {@code true} if this FdEventsReader should process the zero-length packet. + * {@code false} if it should stop reading from the socket. + */ + protected boolean shouldProcessZeroLengthPacket() { + return false; // by default, stop reading upon receiving zero-length packet. + } + /** * Called by the main loop to log errors. In some cases |e| may be null. */ @@ -235,7 +246,7 @@ public abstract class FdEventsReader { try { bytesRead = readPacket(mFd, mBuffer); - if (bytesRead < 1) { + if (bytesRead == 0 && !shouldProcessZeroLengthPacket()) { if (isRunning()) logError("Socket closed, exiting", null); break; } From e2b5213774beb3e6007731cae2e2b09a233a455f Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 25 Apr 2023 15:49:10 +0900 Subject: [PATCH 699/777] Make ConnectivityCheckTargetPreparer more generic Rename ConnectivityCheckTargetPreparer to ConnectivityTestTargetPreparer, and the ConnectivityChecker app to ConnectivityTestPreparer, and remove the assumption that the app only does connectivity checks. This will allow overriding the app with versions that have more specific setup steps in downstream branches. Bug: 263665773 Bug: 267413275 Test: tests using this preparer Merged-In: Icb9b1eb8eb1c75f89cb751e0ca696ea96359e6d0 Change-Id: Icb9b1eb8eb1c75f89cb751e0ca696ea96359e6d0 --- staticlibs/testutils/Android.bp | 2 +- .../app/connectivitychecker/Android.bp | 2 +- .../connectivitychecker/AndroidManifest.xml | 6 +-- .../ConnectivityCheckTest.kt | 9 +++-- ...r.kt => ConnectivityTestTargetPreparer.kt} | 39 +++++++++++++------ 5 files changed, 38 insertions(+), 20 deletions(-) rename staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/{connectivitychecker => connectivitypreparer}/ConnectivityCheckTest.kt (92%) rename staticlibs/testutils/host/com/android/testutils/{ConnectivityCheckTargetPreparer.kt => ConnectivityTestTargetPreparer.kt} (69%) diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index 33821564d7..be4ccfed03 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -83,5 +83,5 @@ java_test_host { ], libs: ["tradefed"], test_suites: ["ats", "device-tests", "general-tests", "cts", "mts-networking"], - data: [":ConnectivityChecker"], + data: [":ConnectivityTestPreparer"], } diff --git a/staticlibs/testutils/app/connectivitychecker/Android.bp b/staticlibs/testutils/app/connectivitychecker/Android.bp index 58f22db7c5..f7118cfaa0 100644 --- a/staticlibs/testutils/app/connectivitychecker/Android.bp +++ b/staticlibs/testutils/app/connectivitychecker/Android.bp @@ -17,7 +17,7 @@ package { } android_test_helper_app { - name: "ConnectivityChecker", + name: "ConnectivityTestPreparer", srcs: ["src/**/*.kt"], sdk_version: "system_current", // Allow running the test on any device with SDK Q+, even when built from a branch that uses diff --git a/staticlibs/testutils/app/connectivitychecker/AndroidManifest.xml b/staticlibs/testutils/app/connectivitychecker/AndroidManifest.xml index 8e5958c316..015b41f9ba 100644 --- a/staticlibs/testutils/app/connectivitychecker/AndroidManifest.xml +++ b/staticlibs/testutils/app/connectivitychecker/AndroidManifest.xml @@ -15,7 +15,7 @@ ~ limitations under the License. --> + package="com.android.testutils.connectivitypreparer"> @@ -27,6 +27,6 @@ + android:targetPackage="com.android.testutils.connectivitypreparer" + android:label="Connectivity test target preparer" /> diff --git a/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitychecker/ConnectivityCheckTest.kt b/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitypreparer/ConnectivityCheckTest.kt similarity index 92% rename from staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitychecker/ConnectivityCheckTest.kt rename to staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitypreparer/ConnectivityCheckTest.kt index f72938d945..6bcb8fc182 100644 --- a/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitychecker/ConnectivityCheckTest.kt +++ b/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitypreparer/ConnectivityCheckTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.testutils.connectivitychecker +package com.android.testutils.connectivitypreparer import android.content.pm.PackageManager.FEATURE_TELEPHONY import android.content.pm.PackageManager.FEATURE_WIFI @@ -40,7 +40,7 @@ class ConnectivityCheckTest { val pm by lazy { context.packageManager } @Test - fun testCheckDeviceSetup() { + fun testCheckConnectivity() { checkWifiSetup() checkTelephonySetup() } @@ -57,10 +57,11 @@ class ConnectivityCheckTest { val commonError = "Check the test bench. To run the tests anyway for quick & dirty local " + "testing, you can use atest X -- " + - "--test-arg com.android.testutils.ConnectivityCheckTargetPreparer:disable:true" + "--test-arg com.android.testutils.ConnectivityTestTargetPreparer" + + ":ignore-connectivity-check:true" // Do not use assertEquals: it outputs "expected X, was Y", which looks like a test failure if (tm.simState == TelephonyManager.SIM_STATE_ABSENT) { - fail("The device has no SIM card inserted. " + commonError) + fail("The device has no SIM card inserted. $commonError") } else if (tm.simState != TelephonyManager.SIM_STATE_READY) { fail("The device is not setup with a usable SIM card. Sim state was ${tm.simState}. " + commonError) diff --git a/staticlibs/testutils/host/com/android/testutils/ConnectivityCheckTargetPreparer.kt b/staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt similarity index 69% rename from staticlibs/testutils/host/com/android/testutils/ConnectivityCheckTargetPreparer.kt rename to staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt index ccc40641a2..fd837aa1a0 100644 --- a/staticlibs/testutils/host/com/android/testutils/ConnectivityCheckTargetPreparer.kt +++ b/staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt @@ -17,6 +17,7 @@ package com.android.testutils import com.android.ddmlib.testrunner.TestResult +import com.android.tradefed.config.Option import com.android.tradefed.invoker.TestInformation import com.android.tradefed.result.CollectingTestListener import com.android.tradefed.result.ddmlib.DefaultRemoteAndroidTestRunner @@ -24,19 +25,26 @@ import com.android.tradefed.targetprep.BaseTargetPreparer import com.android.tradefed.targetprep.TargetSetupError import com.android.tradefed.targetprep.suite.SuiteApkInstaller -private const val CONNECTIVITY_CHECKER_APK = "ConnectivityChecker.apk" -private const val CONNECTIVITY_PKG_NAME = "com.android.testutils.connectivitychecker" +private const val CONNECTIVITY_CHECKER_APK = "ConnectivityTestPreparer.apk" +private const val CONNECTIVITY_PKG_NAME = "com.android.testutils.connectivitypreparer" +private const val CONNECTIVITY_CHECK_CLASS = "$CONNECTIVITY_PKG_NAME.ConnectivityCheckTest" // As per the defined in the checker manifest private const val CONNECTIVITY_CHECK_RUNNER_NAME = "androidx.test.runner.AndroidJUnitRunner" +private const val IGNORE_CONN_CHECK_OPTION = "ignore-connectivity-check" /** - * A target preparer that verifies that the device was setup correctly for connectivity tests. + * A target preparer that sets up and verifies a device for connectivity tests. * - * For quick and dirty local testing, can be disabled by running tests with - * "atest -- --test-arg com.android.testutils.ConnectivityCheckTargetPreparer:disable:true". + * For quick and dirty local testing, the connectivity check can be disabled by running tests with + * "atest -- \ + * --test-arg com.android.testutils.ConnectivityTestTargetPreparer:ignore-connectivity-check:true". */ -class ConnectivityCheckTargetPreparer : BaseTargetPreparer() { - val installer = SuiteApkInstaller() +open class ConnectivityTestTargetPreparer : BaseTargetPreparer() { + private val installer = SuiteApkInstaller() + + @Option(name = IGNORE_CONN_CHECK_OPTION, + description = "Disables the check for mobile data and wifi") + private var ignoreConnectivityCheck = false override fun setUp(testInformation: TestInformation) { if (isDisabled) return @@ -63,11 +71,20 @@ class ConnectivityCheckTargetPreparer : BaseTargetPreparer() { runResult.runFailureMessage, testInformation.device.deviceDescriptor) } - if (!runResult.hasFailedTests()) return + val ignoredTestClasses = mutableSetOf() + if (ignoreConnectivityCheck) { + ignoredTestClasses.add(CONNECTIVITY_CHECK_CLASS) + } + val errorMsg = runResult.testResults.mapNotNull { (testDescription, testResult) -> - if (TestResult.TestStatus.FAILURE != testResult.status) null - else "$testDescription: ${testResult.stackTrace}" + if (TestResult.TestStatus.FAILURE != testResult.status || + ignoredTestClasses.contains(testDescription.className)) { + null + } else { + "$testDescription: ${testResult.stackTrace}" + } }.joinToString("\n") + if (errorMsg.isBlank()) return throw TargetSetupError("Device setup checks failed. Check the test bench: \n$errorMsg", testInformation.device.deviceDescriptor) @@ -77,4 +94,4 @@ class ConnectivityCheckTargetPreparer : BaseTargetPreparer() { if (isTearDownDisabled) return installer.tearDown(testInformation, e) } -} \ No newline at end of file +} From 90edff826aa7ea6f08421c429aa4a160defcd75e Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 9 May 2023 16:15:29 +0900 Subject: [PATCH 700/777] Disable Play auto-update during tests For devices using Play services, disable auto-update during tests, as it may interfere with them. For example, Webview may be killed if it is opened while the update is applied. Bug: 263665773 Test: atest Change-Id: I9613d739ad0763c882a1971879aa743f4541a75c --- .../ConnectivityTestTargetPreparer.kt | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt b/staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt index fd837aa1a0..3fc74aa1a4 100644 --- a/staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt +++ b/staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt @@ -48,6 +48,11 @@ open class ConnectivityTestTargetPreparer : BaseTargetPreparer() { override fun setUp(testInformation: TestInformation) { if (isDisabled) return + disableGmsUpdate(testInformation) + runPreparerApk(testInformation) + } + + private fun runPreparerApk(testInformation: TestInformation) { installer.setCleanApk(true) installer.addTestFileName(CONNECTIVITY_CHECKER_APK) installer.setShouldGrantPermission(true) @@ -90,8 +95,22 @@ open class ConnectivityTestTargetPreparer : BaseTargetPreparer() { testInformation.device.deviceDescriptor) } - override fun tearDown(testInformation: TestInformation?, e: Throwable?) { + private fun disableGmsUpdate(testInformation: TestInformation) { + // This will be a no-op on devices without root (su) or not using gservices, but that's OK. + testInformation.device.executeShellCommand("su 0 am broadcast " + + "-a com.google.gservices.intent.action.GSERVICES_OVERRIDE " + + "-e finsky.play_services_auto_update_enabled false") + } + + private fun clearGmsUpdateOverride(testInformation: TestInformation) { + testInformation.device.executeShellCommand("su 0 am broadcast " + + "-a com.google.gservices.intent.action.GSERVICES_OVERRIDE " + + "--esn finsky.play_services_auto_update_enabled") + } + + override fun tearDown(testInformation: TestInformation, e: Throwable?) { if (isTearDownDisabled) return installer.tearDown(testInformation, e) + clearGmsUpdateOverride(testInformation) } } From 66452f566b54a4c5243892332b3e02de62f373e5 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 17 May 2023 11:35:08 -0700 Subject: [PATCH 701/777] bpf_headers: rename KernelVersion.h to KernelUtils.h Test: TH Change-Id: Ifacc159c19a8fcb64b571295b945fb9fca82496a --- staticlibs/native/bpf_headers/include/bpf/BpfUtils.h | 2 +- .../bpf_headers/include/bpf/{KernelVersion.h => KernelUtils.h} | 0 .../native/bpfmapjni/com_android_net_module_util_BpfMap.cpp | 2 +- staticlibs/native/tcutils/tcutils.cpp | 2 +- staticlibs/native/tcutils/tests/tcutils_test.cpp | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename staticlibs/native/bpf_headers/include/bpf/{KernelVersion.h => KernelUtils.h} (100%) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h index 99c7a91da9..9dd5822a46 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfUtils.h @@ -28,7 +28,7 @@ #include -#include "KernelVersion.h" +#include "KernelUtils.h" namespace android { namespace bpf { diff --git a/staticlibs/native/bpf_headers/include/bpf/KernelVersion.h b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h similarity index 100% rename from staticlibs/native/bpf_headers/include/bpf/KernelVersion.h rename to staticlibs/native/bpf_headers/include/bpf/KernelUtils.h diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp index 2146d17c7f..f93d6e1757 100644 --- a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp +++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp @@ -25,7 +25,7 @@ #define BPF_FD_JUST_USE_INT #include "BpfSyscallWrappers.h" -#include "bpf/KernelVersion.h" +#include "bpf/KernelUtils.h" namespace android { diff --git a/staticlibs/native/tcutils/tcutils.cpp b/staticlibs/native/tcutils/tcutils.cpp index 37a7ec85b4..c82390fae5 100644 --- a/staticlibs/native/tcutils/tcutils.cpp +++ b/staticlibs/native/tcutils/tcutils.cpp @@ -19,7 +19,7 @@ #include "tcutils/tcutils.h" #include "logging.h" -#include "bpf/KernelVersion.h" +#include "bpf/KernelUtils.h" #include "scopeguard.h" #include diff --git a/staticlibs/native/tcutils/tests/tcutils_test.cpp b/staticlibs/native/tcutils/tests/tcutils_test.cpp index 53835d7d88..77322479b2 100644 --- a/staticlibs/native/tcutils/tests/tcutils_test.cpp +++ b/staticlibs/native/tcutils/tests/tcutils_test.cpp @@ -18,7 +18,7 @@ #include -#include "bpf/KernelVersion.h" +#include "bpf/KernelUtils.h" #include #include From 432291a3344db891dc776994995dd16c95582b62 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 17 May 2023 11:59:10 -0700 Subject: [PATCH 702/777] bpf_headers: add kernel bitness utility functions to KernelUtils These were copied from system/core/libsysutils/src/NetlinkEvent.cpp and the following changes were applied: - Mark isUserspace64bit as constexpr. - Added __unused annotations - Fixed a typo (s/meaningul/meaningful) Test: TH Change-Id: Ia0b8e6e02daca7e9b69f337a494d88eb1beffc22 --- .../bpf_headers/include/bpf/KernelUtils.h | 58 ++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h index 29a36e6377..3f82deb317 100644 --- a/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h @@ -17,6 +17,8 @@ #pragma once #include +#include +#include #include namespace android { @@ -40,9 +42,63 @@ static inline unsigned kernelVersion() { return kver; } -static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) { +static inline __unused bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) { return kernelVersion() >= KVER(major, minor, sub); } +// Figure out the bitness of userspace. +// Trivial and known at compile time. +static constexpr bool isUserspace64bit() { + return sizeof(long) == 8; +} + +// Figure out the bitness of the kernel. +static inline __unused bool isKernel64Bit() { + // a 64-bit userspace requires a 64-bit kernel + if (isUserspace64bit()) return true; + + static bool init = false; + static bool cache = false; + if (init) return cache; + + // Retrieve current personality - on Linux this system call *cannot* fail. + int p = personality(0xffffffff); + // But if it does just assume kernel and userspace (which is 32-bit) match... + if (p == -1) return false; + + // This will effectively mask out the bottom 8 bits, and switch to 'native' + // personality, and then return the previous personality of this thread + // (likely PER_LINUX or PER_LINUX32) with any extra options unmodified. + int q = personality((p & ~PER_MASK) | PER_LINUX); + // Per man page this theoretically could error out with EINVAL, + // but kernel code analysis suggests setting PER_LINUX cannot fail. + // Either way, assume kernel and userspace (which is 32-bit) match... + if (q != p) return false; + + struct utsname u; + (void)uname(&u); // only possible failure is EFAULT, but u is on stack. + + // Switch back to previous personality. + // Theoretically could fail with EINVAL on arm64 with no 32-bit support, + // but then we wouldn't have fetched 'p' from the kernel in the first place. + // Either way there's nothing meaningful we can do in case of error. + // Since PER_LINUX32 vs PER_LINUX only affects uname.machine it doesn't + // really hurt us either. We're really just switching back to be 'clean'. + (void)personality(p); + + // Possible values of utsname.machine observed on x86_64 desktop (arm via qemu): + // x86_64 i686 aarch64 armv7l + // additionally observed on arm device: + // armv8l + // presumably also might just be possible: + // i386 i486 i586 + // and there might be other weird arm32 cases. + // We note that the 64 is present in both 64-bit archs, + // and in general is likely to be present in only 64-bit archs. + cache = !!strstr(u.machine, "64"); + init = true; + return cache; +} + } // namespace bpf } // namespace android From 2f5c1159ccce004c5b0ad8d8119b209327cdb270 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 10 May 2023 21:48:23 +0000 Subject: [PATCH 703/777] bpf: Copy comment about bpffs labelling into bpf_helpers.h I found this comment in aosp/2103424 helpful in figuring out the correct selinux domain for a newly added map. Test: documentation only change Change-Id: I96c06ff33605c8ed3f2ae6e8810bbcdc8e66b51b --- .../bpf_headers/include/bpf/bpf_helpers.h | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 70c0f899da..65c0b72d60 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -99,6 +99,30 @@ #define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c)) #define KVER_INF 0xFFFFFFFFu +/* + * BPFFS (ie. /sys/fs/bpf) labelling is as follows: + * subdirectory selinux context mainline usecase / usable by + * / fs_bpf no [*] core operating system (ie. platform) + * /loader fs_bpf_loader no, U+ (as yet unused) + * /net_private fs_bpf_net_private yes, T+ network_stack + * /net_shared fs_bpf_net_shared yes, T+ network_stack & system_server + * /netd_readonly fs_bpf_netd_readonly yes, T+ network_stack & system_server & r/o to netd + * /netd_shared fs_bpf_netd_shared yes, T+ network_stack & system_server & netd [**] + * /tethering fs_bpf_tethering yes, S+ network_stack + * /vendor fs_bpf_vendor no, T+ vendor + * + * [*] initial support for bpf was added back in P, + * but things worked differently back then with no bpfloader, + * and instead netd doing stuff by hand, + * bpfloader with pinning into /sys/fs/bpf was (I believe) added in Q + * (and was definitely there in R). + * + * [**] additionally bpf programs are accessible to netutils_wrapper + * for use by iptables xt_bpf extensions. + * + * See cs/p:aosp-master%20-file:prebuilts/%20file:genfs_contexts%20"genfscon%20bpf" + */ + /* generic functions */ /* From 311f8b325e31cfcb54e30678b54c60d303cfec39 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Mon, 15 May 2023 19:58:49 -0700 Subject: [PATCH 704/777] BpfRingbuf: support 32 bit userspace Both consumer and producer position are wrapped in an std::atomic and extended to uint64_t to enforce atomic access. See resulting assembly instructions for aosp_cf_x86_phone-userdebug: frameworks/libs/net/common/native/bpf_headers/include/bpf/BpfRingbuf.h:212 2d: 8b 41 18 mov 0x18(%ecx),%eax external/libcxx/include/atomic:926 (discriminator 4) 30: f3 0f 7e 00 movq (%eax),%xmm0 This will not work on a 32 bit kernel (so we might want to explicitly check for that in the test). Test: atest BpfRingbufTest Change-Id: I7fec435cbe49d392363d05f7e702d82ecacb9e91 --- .../native/bpf_headers/BpfRingbufTest.cpp | 5 +- .../bpf_headers/include/bpf/BpfRingbuf.h | 70 +++++++++---------- 2 files changed, 35 insertions(+), 40 deletions(-) diff --git a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp index d23afaeeeb..f348333241 100644 --- a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp +++ b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp @@ -25,6 +25,7 @@ #include "BpfSyscallWrappers.h" #include "bpf/BpfRingbuf.h" #include "bpf/BpfUtils.h" +#include "bpf/KernelUtils.h" #define TEST_RINGBUF_MAGIC_NUM 12345 @@ -49,8 +50,8 @@ class BpfRingbufTest : public ::testing::Test { GTEST_SKIP() << "BPF ring buffers not supported below 5.8"; } - if (sizeof(unsigned long) != 8) { - GTEST_SKIP() << "BPF ring buffers not supported on 32 bit arch"; + if (!isKernel64Bit()) { + GTEST_SKIP() << "BPF ring buffers not supported on 32 bit kernel"; } errno = 0; diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h index cac1e43076..a4ba860bd9 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h @@ -23,6 +23,9 @@ #include #include "bpf/BpfUtils.h" +#include "bpf/KernelUtils.h" + +#include namespace android { namespace bpf { @@ -80,8 +83,22 @@ class BpfRingbufBase { android::base::unique_fd mRingFd; void* mDataPos = nullptr; - unsigned long* mConsumerPos = nullptr; - unsigned long* mProducerPos = nullptr; + std::atomic_uint64_t* mConsumerPos = nullptr; + std::atomic_uint64_t* mProducerPos = nullptr; + + // The kernel uses an "unsigned long" type for both consumer and producer position. Unsigned long + // is a 4 byte value on a 32 bit kernel, and an 8 byte value on a 64 bit kernel. While 32 bit + // kernels are slowly going away (and therefore will not be supported), we *must* still support 32 + // bit userspace on a 64 bit kernel. + // In order to guarantee atomic access in a 32 bit userspace environment, atomic_uint64_t is used + // in addition to std::atomic::is_always_lock_free that guarantees that read / write operations + // are indeed atomic. + // Since std::atomic does not support wrapping preallocated memory, an additional static assert on + // the size of the atomic and the underlying type is added to ensure a reinterpret_cast from type + // to its atomic version is safe (is_always_lock_free being true should provide additional + // confidence). + static_assert(std::atomic_uint64_t::is_always_lock_free); + static_assert(sizeof(std::atomic_uint64_t) == sizeof(uint64_t)); }; // This is a class wrapper for eBPF ring buffers. An eBPF ring buffer is a @@ -121,33 +138,11 @@ class BpfRingbuf : public BpfRingbufBase { BpfRingbuf() : BpfRingbufBase(sizeof(Value)) {} }; -#define ACCESS_ONCE(x) (*(volatile typeof(x)*)&(x)) - -#if defined(__i386__) || defined(__x86_64__) -#define smp_sync() asm volatile("" ::: "memory") -#elif defined(__aarch64__) -#define smp_sync() asm volatile("dmb ish" ::: "memory") -#else -#define smp_sync() __sync_synchronize() -#endif - -#define smp_store_release(p, v) \ - do { \ - smp_sync(); \ - ACCESS_ONCE(*(p)) = (v); \ - } while (0) - -#define smp_load_acquire(p) \ - ({ \ - auto ___p = ACCESS_ONCE(*(p)); \ - smp_sync(); \ - ___p; \ - }) inline base::Result BpfRingbufBase::Init(const char* path) { - if (sizeof(unsigned long) != 8) { + if (!isKernel64Bit()) { return android::base::Error() - << "BpfRingbuf does not support 32 bit architectures"; + << "BpfRingbuf does not support 32 bit kernels."; } mRingFd.reset(mapRetrieveRW(path)); if (!mRingFd.ok()) { @@ -184,7 +179,7 @@ inline base::Result BpfRingbufBase::Init(const char* path) { return android::base::ErrnoError() << "failed to mmap ringbuf consumer pages"; } - mConsumerPos = reinterpret_cast(ptr); + mConsumerPos = reinterpret_cast(ptr); } { @@ -194,7 +189,7 @@ inline base::Result BpfRingbufBase::Init(const char* path) { return android::base::ErrnoError() << "failed to mmap ringbuf producer page"; } - mProducerPos = reinterpret_cast(ptr); + mProducerPos = reinterpret_cast(ptr); } mDataPos = pointerAddBytes(mProducerPos, getpagesize()); @@ -204,14 +199,18 @@ inline base::Result BpfRingbufBase::Init(const char* path) { inline base::Result BpfRingbufBase::ConsumeAll( const std::function& callback) { int64_t count = 0; - unsigned long cons_pos = smp_load_acquire(mConsumerPos); - unsigned long prod_pos = smp_load_acquire(mProducerPos); + auto cons_pos = mConsumerPos->load(std::memory_order_acquire); + auto prod_pos = mProducerPos->load(std::memory_order_acquire); while (cons_pos < prod_pos) { // Find the start of the entry for this read (wrapping is done here). void* start_ptr = pointerAddBytes(mDataPos, cons_pos & mPosMask); // The entry has an 8 byte header containing the sample length. - uint32_t length = smp_load_acquire(reinterpret_cast(start_ptr)); + // struct bpf_ringbuf_hdr { + // u32 len; + // u32 pg_off; + // }; + uint32_t length = *reinterpret_cast(start_ptr); // If the sample isn't committed, we're caught up with the producer. if (length & BPF_RINGBUF_BUSY_BIT) return count; @@ -220,7 +219,7 @@ inline base::Result BpfRingbufBase::ConsumeAll( if ((length & BPF_RINGBUF_DISCARD_BIT) == 0) { if (length != mValueSize) { - smp_store_release(mConsumerPos, cons_pos); + mConsumerPos->store(cons_pos, std::memory_order_release); errno = EMSGSIZE; return android::base::ErrnoError() << "BPF ring buffer message has unexpected size (want " @@ -230,7 +229,7 @@ inline base::Result BpfRingbufBase::ConsumeAll( count++; } - smp_store_release(mConsumerPos, cons_pos); + mConsumerPos->store(cons_pos, std::memory_order_release); } return count; @@ -252,10 +251,5 @@ inline base::Result BpfRingbuf::ConsumeAll( }); } -#undef ACCESS_ONCE -#undef smp_sync -#undef smp_store_release -#undef smp_load_acquire - } // namespace bpf } // namespace android From 5b2bcc508ab6efd6171a8afffe9033d45da1d306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 18 May 2023 06:31:37 +0000 Subject: [PATCH 705/777] KernelUtils.h - add arch query helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit see bionic/docs/defines.md: http://cs/h/android/platform/superproject/+/master:bionic/docs/defines.md?l=57 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I818da16ad4dd1837ef3cdcc552557119eafaf6af --- .../bpf_headers/include/bpf/KernelUtils.h | 52 +++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h index 3f82deb317..865f856bc5 100644 --- a/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h @@ -48,12 +48,26 @@ static inline __unused bool isAtLeastKernelVersion(unsigned major, unsigned mino // Figure out the bitness of userspace. // Trivial and known at compile time. -static constexpr bool isUserspace64bit() { - return sizeof(long) == 8; +static constexpr bool isUserspace32bit() { + return sizeof(void*) == 4; } +static constexpr bool isUserspace64bit() { + return sizeof(void*) == 8; +} + +#if defined(__LP64__) +static_assert(isUserspace64bit(), "huh?"); +#elif defined(__ILP32__) +static_assert(isUserspace32bit(), "huh?"); +#else +#error "huh?" +#endif + +static_assert(isUserspace32bit() || isUserspace64bit(), "must be either 32 or 64 bit"); + // Figure out the bitness of the kernel. -static inline __unused bool isKernel64Bit() { +static inline bool isKernel64Bit() { // a 64-bit userspace requires a 64-bit kernel if (isUserspace64bit()) return true; @@ -100,5 +114,37 @@ static inline __unused bool isKernel64Bit() { return cache; } +static inline __unused bool isKernel32Bit() { + return !isKernel64Bit(); +} + +static __unused constexpr bool isArm() { +#if defined(__arm__) || defined(__aarch64__) + return true; +#else + return false; +#endif +} + +static __unused constexpr bool isX86() { +#if defined(__i386__) || defined(__x86_64__) + return true; +#else + return false; +#endif +} + +static __unused constexpr bool isRiscV() { +#if defined(__riscv) + static_assert(isUserspace64bit(), "riscv must be 64 bit"); + return true; +#else + return false; +#endif +} + +static_assert(isArm() || isX86() || isRiscV(), "Unknown architecture"); + + } // namespace bpf } // namespace android From 52954ff5050c83af36f6de76f6834c2068825699 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 17 May 2023 16:22:05 -0700 Subject: [PATCH 706/777] BpfRingbuf: Add support for 32 bit kernels This change adds support for 32 bit kernels by capping mProducerPos to 4 bytes. mConsumerPos (which is written to by userspace) continues to use 8 bytes. (This can be done because an entire page is allocated for mConsumerPos to control access permissions). In a 32 bit kernel, that means that the top order bits are just ignored. In addition, comparisons in userspace only use the bottom 4 bytes to be bitness agnostic. Test: atest BpfRingbufTest Change-Id: I7fe6d9000a151512785f1aa2a53fa97d31967d19 --- .../native/bpf_headers/BpfRingbufTest.cpp | 4 --- .../bpf_headers/include/bpf/BpfRingbuf.h | 27 ++++++++++--------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp index f348333241..6c0841c614 100644 --- a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp +++ b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp @@ -50,10 +50,6 @@ class BpfRingbufTest : public ::testing::Test { GTEST_SKIP() << "BPF ring buffers not supported below 5.8"; } - if (!isKernel64Bit()) { - GTEST_SKIP() << "BPF ring buffers not supported on 32 bit kernel"; - } - errno = 0; mProgram.reset(retrieveProgram(mProgPath.c_str())); EXPECT_EQ(errno, 0); diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h index a4ba860bd9..e320c77605 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h @@ -23,7 +23,6 @@ #include #include "bpf/BpfUtils.h" -#include "bpf/KernelUtils.h" #include @@ -83,13 +82,17 @@ class BpfRingbufBase { android::base::unique_fd mRingFd; void* mDataPos = nullptr; + // The kernel uses an "unsigned long" type for both consumer and producer position. + // Unsigned long is a 4 byte value on a 32-bit kernel, and an 8 byte value on a 64-bit kernel. + // To support 32-bit kernels, producer pos is capped at 4 bytes (despite it being 8 bytes on + // 64-bit kernels) and all comparisons of consumer and producer pos only compare the low-order 4 + // bytes (an inequality comparison is performed to support overflow). + // This solution is bitness agnostic. The consumer only increments the 8 byte consumer pos, which, + // in a little-endian architecture, is safe since the entire page is mapped into memory and a + // 32-bit kernel will just ignore the high-order bits. std::atomic_uint64_t* mConsumerPos = nullptr; - std::atomic_uint64_t* mProducerPos = nullptr; + std::atomic_uint32_t* mProducerPos = nullptr; - // The kernel uses an "unsigned long" type for both consumer and producer position. Unsigned long - // is a 4 byte value on a 32 bit kernel, and an 8 byte value on a 64 bit kernel. While 32 bit - // kernels are slowly going away (and therefore will not be supported), we *must* still support 32 - // bit userspace on a 64 bit kernel. // In order to guarantee atomic access in a 32 bit userspace environment, atomic_uint64_t is used // in addition to std::atomic::is_always_lock_free that guarantees that read / write operations // are indeed atomic. @@ -98,7 +101,9 @@ class BpfRingbufBase { // to its atomic version is safe (is_always_lock_free being true should provide additional // confidence). static_assert(std::atomic_uint64_t::is_always_lock_free); + static_assert(std::atomic_uint32_t::is_always_lock_free); static_assert(sizeof(std::atomic_uint64_t) == sizeof(uint64_t)); + static_assert(sizeof(std::atomic_uint32_t) == sizeof(uint32_t)); }; // This is a class wrapper for eBPF ring buffers. An eBPF ring buffer is a @@ -140,10 +145,6 @@ class BpfRingbuf : public BpfRingbufBase { inline base::Result BpfRingbufBase::Init(const char* path) { - if (!isKernel64Bit()) { - return android::base::Error() - << "BpfRingbuf does not support 32 bit kernels."; - } mRingFd.reset(mapRetrieveRW(path)); if (!mRingFd.ok()) { return android::base::ErrnoError() @@ -199,9 +200,9 @@ inline base::Result BpfRingbufBase::Init(const char* path) { inline base::Result BpfRingbufBase::ConsumeAll( const std::function& callback) { int64_t count = 0; - auto cons_pos = mConsumerPos->load(std::memory_order_acquire); - auto prod_pos = mProducerPos->load(std::memory_order_acquire); - while (cons_pos < prod_pos) { + uint64_t cons_pos = mConsumerPos->load(std::memory_order_acquire); + uint32_t prod_pos = mProducerPos->load(std::memory_order_acquire); + while ((cons_pos & 0xFFFFFFFF) != prod_pos) { // Find the start of the entry for this read (wrapping is done here). void* start_ptr = pointerAddBytes(mDataPos, cons_pos & mPosMask); From 85a86cb9085cbb0f48585c44837724d173084a2a Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Thu, 18 May 2023 13:54:36 -0700 Subject: [PATCH 707/777] BpfRingbuf: Clean up memory access Consumer pos is only written to by userspace (except for initialization), so reading from it does not require a memory barrier. This change also moves producer pos to be acquired before anything else and marks start_ptr as volatile, so it is only read once. Test: atest BpfRingbufTest Change-Id: I228578ef4b42c1732646f0ae928b9a0aa2445304 --- staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h index e320c77605..dd1504c92b 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h @@ -200,8 +200,9 @@ inline base::Result BpfRingbufBase::Init(const char* path) { inline base::Result BpfRingbufBase::ConsumeAll( const std::function& callback) { int64_t count = 0; - uint64_t cons_pos = mConsumerPos->load(std::memory_order_acquire); uint32_t prod_pos = mProducerPos->load(std::memory_order_acquire); + // Only userspace writes to mConsumerPos, so no need to use std::memory_order_acquire + uint64_t cons_pos = mConsumerPos->load(std::memory_order_relaxed); while ((cons_pos & 0xFFFFFFFF) != prod_pos) { // Find the start of the entry for this read (wrapping is done here). void* start_ptr = pointerAddBytes(mDataPos, cons_pos & mPosMask); @@ -211,7 +212,7 @@ inline base::Result BpfRingbufBase::ConsumeAll( // u32 len; // u32 pg_off; // }; - uint32_t length = *reinterpret_cast(start_ptr); + uint32_t length = *reinterpret_cast(start_ptr); // If the sample isn't committed, we're caught up with the producer. if (length & BPF_RINGBUF_BUSY_BIT) return count; From 93312c998eba91d9159c9e70c32e92aafbae4d18 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Thu, 18 May 2023 14:34:36 -0700 Subject: [PATCH 708/777] bpf_headers: Make bpf_headers available to libsysutils So KernelUtils.h can be used in NetlinkEvent.cpp. Test: builds Change-Id: If7a6a28e735ee19dc6b7a72330a97a8a01bcecd5 --- staticlibs/native/bpf_headers/Android.bp | 4 +++- staticlibs/native/bpf_syscall_wrappers/Android.bp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/staticlibs/native/bpf_headers/Android.bp b/staticlibs/native/bpf_headers/Android.bp index 31adef9f3c..41184ea48e 100644 --- a/staticlibs/native/bpf_headers/Android.bp +++ b/staticlibs/native/bpf_headers/Android.bp @@ -33,8 +33,10 @@ cc_library_headers { min_sdk_version: "30", apex_available: [ "//apex_available:platform", - "com.android.tethering", "com.android.art.debug", + "com.android.os.statsd", + "com.android.resolv", + "com.android.tethering", ], } diff --git a/staticlibs/native/bpf_syscall_wrappers/Android.bp b/staticlibs/native/bpf_syscall_wrappers/Android.bp index 125d631bdd..b3efc21668 100644 --- a/staticlibs/native/bpf_syscall_wrappers/Android.bp +++ b/staticlibs/native/bpf_syscall_wrappers/Android.bp @@ -33,6 +33,8 @@ cc_library_headers { "//apex_available:platform", "com.android.art.debug", "com.android.mediaprovider", + "com.android.os.statsd", + "com.android.resolv", "com.android.tethering", ], } From 6d3224e2861c35b778e7b4d20dbfd674509404c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 18 May 2023 00:44:14 +0000 Subject: [PATCH 709/777] bpfloader: ignore_on_(arch) support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Bug: 283523051 Signed-off-by: Maciej Żenczykowski Change-Id: I73768a67b50bb82ebb13e20c6ba6425e1e4236c7 --- .../native/bpf_headers/include/bpf/bpf_map_def.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h index 65540e0117..e7428b6d3f 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h @@ -179,6 +179,14 @@ struct bpf_map_def { bool ignore_on_eng:1; bool ignore_on_user:1; bool ignore_on_userdebug:1; + // The following 5 ignore_on_* fields were added in version 0.38 (U). These are ignored in + // older bpfloader versions, and zero in programs compiled before 0.38. + // These are tests on the kernel architecture, ie. they ignore userspace bit-ness. + bool ignore_on_arm32:1; + bool ignore_on_aarch64:1; + bool ignore_on_x86_32:1; + bool ignore_on_x86_64:1; + bool ignore_on_riscv64:1; char pad0[2]; // manually pad up to 4 byte alignment, may be used for extensions in the future @@ -208,6 +216,14 @@ struct bpf_prog_def { bool ignore_on_eng:1; bool ignore_on_user:1; bool ignore_on_userdebug:1; + // The following 5 ignore_on_* fields were added in version 0.38 (U). These are ignored in + // older bpfloader versions, and zero in programs compiled before 0.38. + // These are tests on the kernel architecture, ie. they ignore userspace bit-ness. + bool ignore_on_arm32:1; + bool ignore_on_aarch64:1; + bool ignore_on_x86_32:1; + bool ignore_on_x86_64:1; + bool ignore_on_riscv64:1; char pad0[2]; // manually pad up to 4 byte alignment, may be used for extensions in the future From 2998627ddd7f17eb50e8a4d401172f66efc05ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 19 May 2023 21:21:10 +0000 Subject: [PATCH 710/777] KernelUtils.h - add describeArch() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I0ae4b5fd8cf9baf04b738743d9e52f94a35aaf21 --- .../bpf_headers/include/bpf/KernelUtils.h | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h index 865f856bc5..b3dd86ccbf 100644 --- a/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h @@ -118,7 +118,7 @@ static inline __unused bool isKernel32Bit() { return !isKernel64Bit(); } -static __unused constexpr bool isArm() { +static constexpr bool isArm() { #if defined(__arm__) || defined(__aarch64__) return true; #else @@ -126,7 +126,7 @@ static __unused constexpr bool isArm() { #endif } -static __unused constexpr bool isX86() { +static constexpr bool isX86() { #if defined(__i386__) || defined(__x86_64__) return true; #else @@ -134,7 +134,7 @@ static __unused constexpr bool isX86() { #endif } -static __unused constexpr bool isRiscV() { +static constexpr bool isRiscV() { #if defined(__riscv) static_assert(isUserspace64bit(), "riscv must be 64 bit"); return true; @@ -145,6 +145,21 @@ static __unused constexpr bool isRiscV() { static_assert(isArm() || isX86() || isRiscV(), "Unknown architecture"); +static __unused const char * describeArch() { + // ordered so as to make it easier to compile time optimize, + // only thing not known at compile time is isKernel64Bit() + if (isUserspace64bit()) { + if (isArm()) return "64-on-aarch64"; + if (isX86()) return "64-on-x86-64"; + if (isRiscV()) return "64-on-riscv64"; + } else if (isKernel64Bit()) { + if (isArm()) return "32-on-aarch64"; + if (isX86()) return "32-on-x86-64"; + } else { + if (isArm()) return "32-on-arm32"; + if (isX86()) return "32-on-x86-32"; + } +} } // namespace bpf } // namespace android From 4782ab1b9ec630454c1020a1c6ae33c6c896f0bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 20 May 2023 23:11:52 +0000 Subject: [PATCH 711/777] KernelUtils.h: explicitly do not support x32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit x86 has 2 obvious ABIs: 32-bit registers/pointers/system calls (i386/i486/i586/i686) 64-bit registers/pointers/system calls (amd64 / x86_64) but there also exists a third: the memory optimizing hybrid 'x32' which uses 64-bit registers, with 32-bit pointers, and 64-bit system calls (with minor tweaks). (there is also technically an aarch64/arm64-ilp32 ABI mirroring x32) Note: It would probably be trivial to add support if we wanted to. Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I82138c5bafbc3bd37cad98eeb79441701d94c386 --- .../native/bpf_headers/include/bpf/KernelUtils.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h index b3dd86ccbf..769ec4b4bb 100644 --- a/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h @@ -119,7 +119,11 @@ static inline __unused bool isKernel32Bit() { } static constexpr bool isArm() { -#if defined(__arm__) || defined(__aarch64__) +#if defined(__arm__) + static_assert(isUserspace32bit(), "huh? arm must be 32 bit"); + return true; +#elif defined(__aarch64__) + static_assert(isUserspace64bit(), "aarch64 must be LP64 - no support for ILP32"); return true; #else return false; @@ -127,7 +131,11 @@ static constexpr bool isArm() { } static constexpr bool isX86() { -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) + static_assert(isUserspace32bit(), "huh? i386 must be 32 bit"); + return true; +#elif defined(__x86_64__) + static_assert(isUserspace64bit(), "x86_64 must be LP64 - no support for ILP32 (x32)"); return true; #else return false; From 677b663aaffc14d0fa5b19dcbc6e21271f2ce617 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 19 May 2023 18:56:03 +0900 Subject: [PATCH 712/777] Correctly test for an object being of the correct type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This `as? T` instruction warns that this is an unchecked cast. It's unchecked in the literal sense : the compiler actually doesn't check that the var is of that type. Accordingly, this will only fail if `it` is null, which never happens. Concretely what that means is that Java code calling this method like expect(AVAILABLE, network) ...will actually pass for *any* callback matching the network, because the class is not checked. Thankfully this code is recent and there doesn't seem to be a lot of tests that got accepted by this bug when they should have been rejected. Test: ConnectivityServiceTest, TH new test in this patch that fails before but succeeds after Change-Id: I2e48dae28ff92045f002cfb2798d383c9c19d5ed --- .../com/android/testutils/TestableNetworkCallbackTest.kt | 7 +++++++ .../com/android/testutils/TestableNetworkCallback.kt | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt index 4ed881af33..e838bdc564 100644 --- a/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt +++ b/staticlibs/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt @@ -353,6 +353,13 @@ class TestableNetworkCallbackTest { mCallback.expect(network = hn) } + @Test + fun testExpectClass() { + val net = Network(1) + mCallback.onAvailable(net) + assertFails { mCallback.expect(LOST, net) } + } + @Test fun testPoll() { assertNull(mCallback.poll(SHORT_TIMEOUT_MS)) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index 0e73112d1b..4b6aea2d52 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -236,7 +236,11 @@ open class TestableNetworkCallback private constructor( errorMsg: String? = null, test: (T) -> Boolean = { true } ) = expect(network, timeoutMs, errorMsg) { - test(it as? T ?: fail("Expected callback ${type.simpleName}, got $it")) + if (type.isInstance(it)) { + test(it as T) // Cast can't fail since type.isInstance(it) and type: KClass + } else { + fail("Expected callback ${type.simpleName}, got $it") + } } as T @JvmOverloads From 78cc19e25a28156ecf042935ec507b6618fe1e81 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Mon, 22 May 2023 12:13:13 +0900 Subject: [PATCH 713/777] Add logs for target uids and duration to destroyLiveTcpSockets destroyLiveTcpSockets APIs are replacement of socketDestroy in NetdNativeService which has logging for target uids and duration. Logging them would be useful in debug. So adding equivalent logging to destroyLiveTcpSockets APIs. Test: atest com.android.cts.net.HostsideVpnTests#testSocketClosed Test: atest ConnectivityManagerTest#testFirewallCloseSocketDenylistChainDeny Bug: 270298713 Change-Id: I347d010541656c92a64029b1474fae601d6e5659 --- .../android/net/module/util/netlink/InetDiagMessage.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java index e69a844c61..f8b47164a6 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java @@ -39,6 +39,7 @@ import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; import android.net.util.SocketUtils; import android.os.Process; +import android.os.SystemClock; import android.system.ErrnoException; import android.util.Log; import android.util.Range; @@ -461,11 +462,15 @@ public class InetDiagMessage extends NetlinkMessage { */ public static void destroyLiveTcpSockets(Set> ranges, Set exemptUids) throws SocketException, InterruptedIOException, ErrnoException { + final long startTimeMs = SystemClock.elapsedRealtime(); destroySockets(IPPROTO_TCP, TCP_ALIVE_STATE_FILTER, (diagMsg) -> !exemptUids.contains(diagMsg.inetDiagMsg.idiag_uid) && containsUid(diagMsg, ranges) && !isLoopback(diagMsg) && !isAdbSocket(diagMsg)); + final long durationMs = SystemClock.elapsedRealtime() - startTimeMs; + Log.d(TAG, "Destroyed live tcp sockets for uids=" + ranges + " exemptUids=" + exemptUids + + " in " + durationMs + "ms"); } /** @@ -479,10 +484,13 @@ public class InetDiagMessage extends NetlinkMessage { */ public static void destroyLiveTcpSocketsByOwnerUids(Set ownerUids) throws SocketException, InterruptedIOException, ErrnoException { + final long startTimeMs = SystemClock.elapsedRealtime(); destroySockets(IPPROTO_TCP, TCP_ALIVE_STATE_FILTER, (diagMsg) -> ownerUids.contains(diagMsg.inetDiagMsg.idiag_uid) && !isLoopback(diagMsg) && !isAdbSocket(diagMsg)); + final long durationMs = SystemClock.elapsedRealtime() - startTimeMs; + Log.d(TAG, "Destroyed live tcp sockets for uids=" + ownerUids + " in " + durationMs + "ms"); } @Override From 0cd46d480d57c003e112d58131548c41de4ef191 Mon Sep 17 00:00:00 2001 From: Hansen Kurli Date: Mon, 22 May 2023 11:06:07 +0000 Subject: [PATCH 714/777] Use ThrowingSupplier for visibleOnHandlerThread. In order to return values from functions that are run on the handler thread, use a ThrowingSupplier instead of a ThrowingRunnable. Also maintain the case with ThrowingRunnable by overloading. Test: NetworkStaticLibTests Change-Id: Ic1b86f9f764997ce5d6848f04185194a961d1106 --- .../com/android/testutils/HandlerUtilsTest.kt | 9 ++++++++- .../com/android/testutils/HandlerUtils.kt | 19 +++++++++++++------ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/testutils/HandlerUtilsTest.kt b/staticlibs/tests/unit/src/com/android/testutils/HandlerUtilsTest.kt index 30e0dafe19..0f6fa48baf 100644 --- a/staticlibs/tests/unit/src/com/android/testutils/HandlerUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/testutils/HandlerUtilsTest.kt @@ -18,8 +18,10 @@ package com.android.testutils import android.os.Handler import android.os.HandlerThread +import com.android.testutils.FunctionalUtils.ThrowingSupplier import kotlin.test.assertEquals import kotlin.test.assertFailsWith +import kotlin.test.assertNull import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 @@ -69,13 +71,18 @@ class HandlerUtilsTest { repeat(ATTEMPTS) { attempt -> var x = -10 - visibleOnHandlerThread(handler) { x = attempt } + var y = -11 + y = visibleOnHandlerThread(handler, ThrowingSupplier { x = attempt; attempt }) assertEquals(attempt, x) + assertEquals(attempt, y) handler.post { assertEquals(attempt, x) } } assertFailsWith { visibleOnHandlerThread(handler) { throw IllegalArgumentException() } } + + // Null values may be returned by the supplier + assertNull(visibleOnHandlerThread(handler, ThrowingSupplier { null })) } } diff --git a/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt b/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt index aa252a56e6..f00ca116c7 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/HandlerUtils.kt @@ -23,6 +23,7 @@ import android.os.Handler import android.os.HandlerThread import android.util.Log import com.android.testutils.FunctionalUtils.ThrowingRunnable +import com.android.testutils.FunctionalUtils.ThrowingSupplier import java.lang.Exception import java.util.concurrent.Executor import kotlin.test.fail @@ -55,7 +56,8 @@ fun waitForIdleSerialExecutor(executor: Executor, timeoutMs: Long) { } /** - * Executes a block of code, making its side effects visible on the caller and the handler thread + * Executes a block of code that returns a value, making its side effects visible on the caller and + * the handler thread. * * After this function returns, the side effects of the passed block of code are guaranteed to be * observed both on the thread running the handler and on the thread running this method. @@ -63,15 +65,15 @@ fun waitForIdleSerialExecutor(executor: Executor, timeoutMs: Long) { * until it's executed, so keep in mind this method will block, (including, if the handler isn't * running, blocking forever). */ -fun visibleOnHandlerThread(handler: Handler, r: ThrowingRunnable) { +fun visibleOnHandlerThread(handler: Handler, supplier: ThrowingSupplier): T { val cv = ConditionVariable() - var e: Exception? = null + var rv: Result = Result.failure(RuntimeException("Not run")) handler.post { try { - r.run() + rv = Result.success(supplier.get()) } catch (exception: Exception) { Log.e(TAG, "visibleOnHandlerThread caught exception", exception) - e = exception + rv = Result.failure(exception) } cv.open() } @@ -79,5 +81,10 @@ fun visibleOnHandlerThread(handler: Handler, r: ThrowingRunnable) { // and this thread also has seen the change (since cv.open() happens-before cv.block() // returns). cv.block() - e?.let { throw it } + return rv.getOrThrow() +} + +/** Overload of visibleOnHandlerThread but executes a block of code that does not return a value. */ +inline fun visibleOnHandlerThread(handler: Handler, r: ThrowingRunnable){ + visibleOnHandlerThread(handler, ThrowingSupplier { r.run() }) } From 2129040ae4b44d4f34dbe5c0462472eb86bb73fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 25 May 2023 12:30:22 +0000 Subject: [PATCH 715/777] KernelUtils.h - better static assert messages for impossible conditions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit per Lorenzo's request during cherrypick to udc-dev on https://googleplex-android-review.git.corp.google.com/c/platform/frameworks/libs/net/+/23391171 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ib19f5b3b63a6978ac5a72b2be08a2f0ba6cdd712 --- staticlibs/native/bpf_headers/include/bpf/KernelUtils.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h index 769ec4b4bb..59257b8b82 100644 --- a/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h +++ b/staticlibs/native/bpf_headers/include/bpf/KernelUtils.h @@ -57,11 +57,11 @@ static constexpr bool isUserspace64bit() { } #if defined(__LP64__) -static_assert(isUserspace64bit(), "huh?"); +static_assert(isUserspace64bit(), "huh? LP64 must have 64-bit userspace"); #elif defined(__ILP32__) -static_assert(isUserspace32bit(), "huh?"); +static_assert(isUserspace32bit(), "huh? ILP32 must have 32-bit userspace"); #else -#error "huh?" +#error "huh? must be either LP64 (64-bit userspace) or ILP32 (32-bit userspace)" #endif static_assert(isUserspace32bit() || isUserspace64bit(), "must be either 32 or 64 bit"); From 4734d678a5d4fc63836de6eb531bd6bb21ad86d2 Mon Sep 17 00:00:00 2001 From: Mike Yu Date: Thu, 25 May 2023 06:14:35 +0000 Subject: [PATCH 716/777] Change DnsPacket.DnsRecord.MAXNAMESIZE to public Change this constant to public so that the implementation of other type of DNS record, such as SVCB record, can reuse this constant instead of defining a duplicate one. Bug: 240259333 Test: TreeHugger Change-Id: Ic5c6ecfba4d16f19adb3794dd50c5fc876d9f82a --- staticlibs/framework/com/android/net/module/util/DnsPacket.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/framework/com/android/net/module/util/DnsPacket.java b/staticlibs/framework/com/android/net/module/util/DnsPacket.java index 702d114e00..79ca3a39e1 100644 --- a/staticlibs/framework/com/android/net/module/util/DnsPacket.java +++ b/staticlibs/framework/com/android/net/module/util/DnsPacket.java @@ -252,7 +252,7 @@ public abstract class DnsPacket { // Refer to RFC 1035 section 2.3.4 for MAXNAMESIZE. // NAME_NORMAL and NAME_COMPRESSION are used for checking name compression, // refer to rfc 1035 section 4.1.4. - private static final int MAXNAMESIZE = 255; + public static final int MAXNAMESIZE = 255; public static final int NAME_NORMAL = 0; public static final int NAME_COMPRESSION = 0xC0; From ab3fee4246bd100a1d1d38e827d261f7f03701ba Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 12 Apr 2023 13:53:36 +0800 Subject: [PATCH 717/777] Fix crash when socket read is interrupted The exception is thrown in some normal cases e.g. interrupt() called when Os.read is blocked and waiting for the input. Ignore such events. Test: 1. atest NetworkStackCoverageMtsConfigTests on S device 2. atest com.android.cts.net.HostsideVpnTests 3. atest NetworkStatsIntegrationTest Bug: 259632210 Change-Id: Ibff41312d9c7431c2b19f780844ab3a81b48f9e8 --- .../android/testutils/NatPacketForwarderBase.java | 3 ++- .../com/android/testutils/PacketReflectorUtil.kt | 14 +++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/NatPacketForwarderBase.java b/staticlibs/testutils/devicetests/com/android/testutils/NatPacketForwarderBase.java index 85c649309b..0a2b5d418c 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/NatPacketForwarderBase.java +++ b/staticlibs/testutils/devicetests/com/android/testutils/NatPacketForwarderBase.java @@ -151,7 +151,8 @@ public abstract class NatPacketForwarderBase extends Thread { private void processPacket() { final int len = PacketReflectorUtil.readPacket(mSrcFd, mBuf); if (len < 1) { - throw new IllegalStateException("Unexpected buffer length: " + len); + // Usually happens when socket read is being interrupted, e.g. stopping PacketForwarder. + return; } final int version = mBuf[0] >>> 4; diff --git a/staticlibs/testutils/devicetests/com/android/testutils/PacketReflectorUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/PacketReflectorUtil.kt index b028045450..498b1a36f0 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/PacketReflectorUtil.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/PacketReflectorUtil.kt @@ -20,11 +20,12 @@ package com.android.testutils import android.system.ErrnoException import android.system.Os +import android.system.OsConstants import com.android.net.module.util.IpUtils import com.android.testutils.PacketReflector.IPV4_HEADER_LENGTH import com.android.testutils.PacketReflector.IPV6_HEADER_LENGTH import java.io.FileDescriptor -import java.io.IOException +import java.io.InterruptedIOException import java.net.InetAddress import java.nio.ByteBuffer @@ -32,8 +33,15 @@ fun readPacket(fd: FileDescriptor, buf: ByteArray): Int { return try { Os.read(fd, buf, 0, buf.size) } catch (e: ErrnoException) { - -1 - } catch (e: IOException) { + // Ignore normal use cases such as the EAGAIN error indicates that the read operation + // cannot be completed immediately, or the EINTR error indicates that the read + // operation was interrupted by a signal. + if (e.errno == OsConstants.EAGAIN || e.errno == OsConstants.EINTR) { + -1 + } else { + throw e + } + } catch (e: InterruptedIOException) { -1 } } From a6fba08f82935d45b9a438898efe0f2dc6e01ac5 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 31 May 2023 20:34:28 +0900 Subject: [PATCH 718/777] Add a helper function to send RTM_NEWADDR netlink message to kernel. Bug: 260934173 Test: TH Change-Id: I6e9100e6f04a85550790c90fb0fde8d839e74578 --- .../net/module/util/netlink/NetlinkUtils.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java index b512a9598b..0f7bd80b6e 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java @@ -22,6 +22,7 @@ import static android.system.OsConstants.EIO; import static android.system.OsConstants.EPROTO; import static android.system.OsConstants.ETIMEDOUT; import static android.system.OsConstants.NETLINK_INET_DIAG; +import static android.system.OsConstants.NETLINK_ROUTE; import static android.system.OsConstants.SOCK_CLOEXEC; import static android.system.OsConstants.SOCK_DGRAM; import static android.system.OsConstants.SOL_SOCKET; @@ -41,9 +42,11 @@ import androidx.annotation.Nullable; import java.io.FileDescriptor; import java.io.IOException; import java.io.InterruptedIOException; +import java.net.Inet6Address; import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.Objects; /** * Utilities for netlink related class that may not be able to fit into a specific class. @@ -167,6 +170,31 @@ public class NetlinkUtils { } } + /** + * Send an RTM_NEWADDR message to kernel to add or update an IPv6 address. + * + * @param ifIndex interface index. + * @param ip IPv6 address to be added. + * @param prefixlen IPv6 address prefix length. + * @param flags IPv6 address flags. + * @param scope IPv6 address scope. + * @param preferred The preferred lifetime of IPv6 address. + * @param valid The valid lifetime of IPv6 address. + */ + public static boolean sendRtmNewAddressRequest(int ifIndex, @NonNull final Inet6Address ip, + short prefixlen, int flags, byte scope, long preferred, long valid) { + Objects.requireNonNull(ip, "IPv6 address to be added should not be null."); + final byte[] msg = RtNetlinkAddressMessage.newRtmNewAddressMessage(1 /* seqNo*/, ip, + prefixlen, flags, scope, ifIndex, preferred, valid); + try { + NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, msg); + return true; + } catch (ErrnoException e) { + Log.e(TAG, "Fail to send RTM_NEWADDR to add " + ip.getHostAddress(), e); + return false; + } + } + /** * Create netlink socket with the given netlink protocol type. * From cff263aa105e91c9315992d6b4c2f80f5c756476 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 1 Jun 2023 13:34:01 +0900 Subject: [PATCH 719/777] Add NetworkStackModuleTest annotation. This annotation can be used to exclude the testcases which requires the latest NetworkStack module in the CTS/MTS suite. Bug: 283200648 Test: atest CtsTetheringTestLatestSdk Change-Id: Idaffed93af077c2998081142af7b3bfa311dcd90 --- .../testutils/NetworkStackModuleTest.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 staticlibs/testutils/hostdevice/com/android/testutils/NetworkStackModuleTest.kt diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/NetworkStackModuleTest.kt b/staticlibs/testutils/hostdevice/com/android/testutils/NetworkStackModuleTest.kt new file mode 100644 index 0000000000..fe312a093c --- /dev/null +++ b/staticlibs/testutils/hostdevice/com/android/testutils/NetworkStackModuleTest.kt @@ -0,0 +1,22 @@ +/* + * 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 com.android.testutils + +/** + * Indicates that the test covers functionality that was rolled out in a NetworkStack module update. + */ +annotation class NetworkStackModuleTest From 5bec8b44a958e1c79e4aed34080edc59af782ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 7 Jun 2023 06:59:20 +0000 Subject: [PATCH 720/777] force map key/value sizes < 1024/65536 bytes to match BpfMap.java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Bug: 286154283 Signed-off-by: Maciej Żenczykowski Change-Id: I31fb48aa032e22a83e3e9f0ac8d7f2b3253e995e --- staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index 65c0b72d60..b3946ec57a 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -262,6 +262,8 @@ static void (*bpf_ringbuf_submit_unsafe)(const void* data, __u64 flags) = (void* KVER_NONE, KVER_INF, min_loader, max_loader, \ ignore_eng, ignore_user, ignore_userdebug); \ BPF_MAP_ASSERT_OK(BPF_MAP_TYPE_##TYPE, (num_entries), (md)); \ + _Static_assert(sizeof(KeyType) < 1024, "aosp/2370288 requires < 1024 byte keys"); \ + _Static_assert(sizeof(ValueType) < 65536, "aosp/2370288 requires < 65536 byte values"); \ BPF_ANNOTATE_KV_PAIR(the_map, KeyType, ValueType); \ \ static inline __always_inline __unused ValueType* bpf_##the_map##_lookup_elem( \ From 789baf20d35686e052f976002fbb5439157534a8 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 7 Jun 2023 20:08:21 +0900 Subject: [PATCH 721/777] Make IaPrefixOption constructor public. Then we can create an IaPrefixOption instance via constructor in the NetworkStackIntegration test. Bug: 260934173 Test: atest NetworkStackIntegrationTests Change-Id: I05be1dde6ba5bda125631674c5c0f8634eb18924 --- .../com/android/net/module/util/structs/IaPrefixOption.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java b/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java index 060d4915c3..f0e4409850 100644 --- a/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java +++ b/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java @@ -18,6 +18,8 @@ package com.android.net.module.util.structs; import static com.android.net.module.util.NetworkStackConstants.DHCP6_OPTION_IAPREFIX; +import androidx.annotation.VisibleForTesting; + import com.android.net.module.util.Struct; import com.android.net.module.util.Struct.Field; import com.android.net.module.util.Struct.Type; @@ -67,7 +69,8 @@ public class IaPrefixOption extends Struct { @Field(order = 5, type = Type.ByteArray, arraysize = 16) public final byte[] prefix; - IaPrefixOption(final short code, final short length, final long preferred, + @VisibleForTesting + public IaPrefixOption(final short code, final short length, final long preferred, final long valid, final byte prefixLen, final byte[] prefix) { this.code = code; this.length = length; From 8837bf21a5e32e2d7a274720f5bcf59d0bbce124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 9 Jun 2023 05:50:30 +0000 Subject: [PATCH 722/777] add macro to disable BTF on user builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 286369326 Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I6a705ae99a12fb8464730dab1119f4ce2ef3f974 --- .../native/bpf_headers/include/bpf/bpf_helpers.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index b3946ec57a..fed400274a 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -84,6 +84,16 @@ size_t _size_of_bpf_prog_def SECTION("size_of_bpf_prog_def") = sizeof(struct bpf_prog_def); \ char _license[] SECTION("license") = (NAME) +/* This macro disables loading BTF map debug information on Android <=U *and* all user builds. + * + * Note: Bpfloader v0.39+ honours 'btf_user_min_bpfloader_ver' on user builds, + * and 'btf_min_bpfloader_ver' on non-user builds. + * Older BTF capable versions unconditionally honour 'btf_min_bpfloader_ver' + */ +#define DISABLE_BTF_ON_USER_BUILDS() \ + unsigned _btf_min_bpfloader_ver SECTION("btf_min_bpfloader_ver") = 39u; \ + unsigned _btf_user_min_bpfloader_ver SECTION("btf_user_min_bpfloader_ver") = 0xFFFFFFFFu + /* flag the resulting bpf .o file as critical to system functionality, * loading all kernel version appropriate programs in it must succeed * for bpfloader success From be02054c79d83d94d3143848f8d75f9aaeb433e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 13 Jun 2023 18:47:57 -0700 Subject: [PATCH 723/777] convert ptr_to_u64() macro to an inline function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows it to be used from outside this header file, and provides slightly more type safety. Test: TreeHugger Bug: 286369326 Signed-off-by: Maciej Żenczykowski Change-Id: I98e5e37a002188813b602e51fd4fcbb9ca4466cc --- .../bpf_syscall_wrappers/include/BpfSyscallWrappers.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h index 8502961ec8..1295d3ce82 100644 --- a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h +++ b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h @@ -28,11 +28,13 @@ #define BPF_FD_TO_U32(x) static_cast<__u32>((x).get()) #endif -#define ptr_to_u64(x) ((uint64_t)(uintptr_t)(x)) - namespace android { namespace bpf { +inline uint64_t ptr_to_u64(const void * const x) { + return (uint64_t)(uintptr_t)x; +} + /* Note: bpf_attr is a union which might have a much larger size then the anonymous struct portion * of it that we are using. The kernel's bpf() system call will perform a strict check to ensure * all unused portions are zero. It will fail with E2BIG if we don't fully zero bpf_attr. @@ -199,7 +201,6 @@ DEFINE_BPF_GET_FD_INFO(MapFlags, map_flags) // int bpfGetFdMapFlags(const B } // namespace bpf } // namespace android -#undef ptr_to_u64 #undef BPF_FD_TO_U32 #undef BPF_FD_TYPE #undef BPF_FD_JUST_USE_INT From 008f51e585976ab45f674d02c88d3c7deed6885e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 13 Jun 2023 18:27:57 -0700 Subject: [PATCH 724/777] implement 'int bpfGetFdProgId(const BPF_FD_TYPE prog_fd)' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit which fetches the internal kernel identifier of an ebpf program side note: Linux in include/uapi/linux/bpf.h declares: 4.14: struct bpf_map_info 4.14: struct bpf_prog_info 4.19: struct bpf_btf_info 5.4: struct bpf_func_info 5.4: struct bpf_line_info 5.10: struct bpf_link_info 5.10: struct bpf_pidns_info Test: TreeHugger Bug: 286369326 Signed-off-by: Maciej Żenczykowski Change-Id: I8b2fe1a67bdefff521e41b3ff4ef37d29fc90fae --- .../include/BpfSyscallWrappers.h | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h index 1295d3ce82..98b1e6b2c5 100644 --- a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h +++ b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h @@ -170,33 +170,34 @@ inline int runProgram(const BPF_FD_TYPE prog_fd, const void* data, // over time), so we need to check that the field we're interested in is actually // supported/returned by the running kernel. We do this by checking it is fully // within the bounds of the struct size as reported by the kernel. -#define DEFINE_BPF_GET_FD_INFO(NAME, FIELD) \ -inline int bpfGetFd ## NAME(const BPF_FD_TYPE map_fd) { \ - struct bpf_map_info map_info = {}; \ +#define DEFINE_BPF_GET_FD(TYPE, NAME, FIELD) \ +inline int bpfGetFd ## NAME(const BPF_FD_TYPE fd) { \ + struct bpf_ ## TYPE ## _info info = {}; \ union bpf_attr attr = { .info = { \ - .bpf_fd = BPF_FD_TO_U32(map_fd), \ - .info_len = sizeof(map_info), \ - .info = ptr_to_u64(&map_info), \ + .bpf_fd = BPF_FD_TO_U32(fd), \ + .info_len = sizeof(info), \ + .info = ptr_to_u64(&info), \ }}; \ int rv = bpf(BPF_OBJ_GET_INFO_BY_FD, attr); \ if (rv) return rv; \ - if (attr.info.info_len < offsetof(bpf_map_info, FIELD) + sizeof(map_info.FIELD)) { \ + if (attr.info.info_len < offsetof(bpf_ ## TYPE ## _info, FIELD) + sizeof(info.FIELD)) { \ errno = EOPNOTSUPP; \ return -1; \ }; \ - return map_info.FIELD; \ + return info.FIELD; \ } -// All 6 of these fields are already present in Linux v4.14 (even ACK 4.14-P) +// All 7 of these fields are already present in Linux v4.14 (even ACK 4.14-P) // while BPF_OBJ_GET_INFO_BY_FD is not implemented at all in v4.9 (even ACK 4.9-Q) -DEFINE_BPF_GET_FD_INFO(MapType, type) // int bpfGetFdMapType(const BPF_FD_TYPE map_fd) -DEFINE_BPF_GET_FD_INFO(MapId, id) // int bpfGetFdMapId(const BPF_FD_TYPE map_fd) -DEFINE_BPF_GET_FD_INFO(KeySize, key_size) // int bpfGetFdKeySize(const BPF_FD_TYPE map_fd) -DEFINE_BPF_GET_FD_INFO(ValueSize, value_size) // int bpfGetFdValueSize(const BPF_FD_TYPE map_fd) -DEFINE_BPF_GET_FD_INFO(MaxEntries, max_entries) // int bpfGetFdMaxEntries(const BPF_FD_TYPE map_fd) -DEFINE_BPF_GET_FD_INFO(MapFlags, map_flags) // int bpfGetFdMapFlags(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD(map, MapType, type) // int bpfGetFdMapType(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD(map, MapId, id) // int bpfGetFdMapId(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD(map, KeySize, key_size) // int bpfGetFdKeySize(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD(map, ValueSize, value_size) // int bpfGetFdValueSize(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD(map, MaxEntries, max_entries) // int bpfGetFdMaxEntries(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD(map, MapFlags, map_flags) // int bpfGetFdMapFlags(const BPF_FD_TYPE map_fd) +DEFINE_BPF_GET_FD(prog, ProgId, id) // int bpfGetFdProgId(const BPF_FD_TYPE prog_fd) -#undef DEFINE_BPF_GET_FD_INFO +#undef DEFINE_BPF_GET_FD } // namespace bpf } // namespace android From c6e4122db8490504eaad02a76b4acd6fbb687bf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Mon, 12 Jun 2023 22:50:02 -0700 Subject: [PATCH 725/777] add createOuterMap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Icf49cc98daa339b0320b5c18cd055b8a53dcba6c --- .../include/BpfSyscallWrappers.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h index 98b1e6b2c5..ba16d53cb7 100644 --- a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h +++ b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h @@ -55,6 +55,23 @@ inline int createMap(bpf_map_type map_type, uint32_t key_size, uint32_t value_si }); } +// Note: +// 'map_type' must be one of BPF_MAP_TYPE_{ARRAY,HASH}_OF_MAPS +// 'value_size' must be sizeof(u32), ie. 4 +// 'inner_map_fd' is basically a template specifying {map_type, key_size, value_size, max_entries, map_flags} +// of the inner map type (and possibly only key_size/value_size actually matter?). +inline int createOuterMap(bpf_map_type map_type, uint32_t key_size, uint32_t value_size, + uint32_t max_entries, uint32_t map_flags, const BPF_FD_TYPE inner_map_fd) { + return bpf(BPF_MAP_CREATE, { + .map_type = map_type, + .key_size = key_size, + .value_size = value_size, + .max_entries = max_entries, + .map_flags = map_flags, + .inner_map_fd = BPF_FD_TO_U32(inner_map_fd), + }); +} + inline int writeToMapEntry(const BPF_FD_TYPE map_fd, const void* key, const void* value, uint64_t flags) { return bpf(BPF_MAP_UPDATE_ELEM, { From f1416b5494fe1e55e3ec7b156b8b57842a96e1e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 16 Jun 2023 16:30:46 +0000 Subject: [PATCH 726/777] enforce bpf ring buffer size is a power of two MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While at it enforce a min/max of 4 kiB and 256 MiB. A bpf ringbuffer must be an integer multiple of page size (which is at least 4kiB), so 4kB is forced. 256 MiB upper limit is probably higher than it should be, but it's really only here to avoid the u32/s32 conversion mess that happens for 2+ GiB. Test: TreeHugger Bug: 279819914 Signed-off-by: Maciej Żenczykowski Change-Id: I2216d2273b0956a86c4222dd6ecf7293e0bafd41 --- staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h index fed400274a..67ac0e46e9 100644 --- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h +++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h @@ -233,14 +233,22 @@ static void (*bpf_ringbuf_submit_unsafe)(const void* data, __u64 flags) = (void* selinux, pindir, share, KVER(5, 8, 0), KVER_INF, \ min_loader, max_loader, ignore_eng, ignore_user, \ ignore_userdebug); \ + \ + _Static_assert((size_bytes) >= 4096, "min 4 kiB ringbuffer size"); \ + _Static_assert((size_bytes) <= 0x10000000, "max 256 MiB ringbuffer size"); \ + _Static_assert(((size_bytes) & ((size_bytes) - 1)) == 0, \ + "ring buffer size must be a power of two"); \ + \ static inline __always_inline __unused int bpf_##the_map##_output( \ const ValueType* v) { \ return bpf_ringbuf_output_unsafe(&the_map, v, sizeof(*v), 0); \ } \ + \ static inline __always_inline __unused \ ValueType* bpf_##the_map##_reserve() { \ return bpf_ringbuf_reserve_unsafe(&the_map, sizeof(ValueType), 0); \ } \ + \ static inline __always_inline __unused void bpf_##the_map##_submit( \ const ValueType* v) { \ bpf_ringbuf_submit_unsafe(v, 0); \ From 4cb10fdc2818717a90f6009a986076ea2bcb8f4d Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Mon, 19 Jun 2023 12:44:57 +0900 Subject: [PATCH 727/777] Add netlink rta_cacheinfo structure. Bug: 183601771 Test: m Change-Id: Iaa65425fa875a9dde4d4b7c1b110d9a2a406f444 --- .../util/netlink/StructRtaCacheInfo.java | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/netlink/StructRtaCacheInfo.java diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructRtaCacheInfo.java b/staticlibs/device/com/android/net/module/util/netlink/StructRtaCacheInfo.java new file mode 100644 index 0000000000..fef1f9e813 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/netlink/StructRtaCacheInfo.java @@ -0,0 +1,92 @@ +/* + * 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 com.android.net.module.util.netlink; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.nio.ByteBuffer; + +/** + * struct rta_cacheinfo + * + * see also: + * + * include/uapi/linux/rtnetlink.h + * + * @hide + */ +public class StructRtaCacheInfo extends Struct { + // Already aligned. + public static final int STRUCT_SIZE = 32; + + @Field(order = 0, type = Type.U32) + public final long clntref; + @Field(order = 1, type = Type.U32) + public final long lastuse; + @Field(order = 2, type = Type.S32) + public final int expires; + @Field(order = 3, type = Type.U32) + public final long error; + @Field(order = 4, type = Type.U32) + public final long used; + @Field(order = 5, type = Type.U32) + public final long id; + @Field(order = 6, type = Type.U32) + public final long ts; + @Field(order = 7, type = Type.U32) + public final long tsage; + + StructRtaCacheInfo(long clntref, long lastuse, int expires, long error, long used, long id, + long ts, long tsage) { + this.clntref = clntref; + this.lastuse = lastuse; + this.expires = expires; + this.error = error; + this.used = used; + this.id = id; + this.ts = ts; + this.tsage = tsage; + } + + /** + * Parse an rta_cacheinfo struct from a {@link ByteBuffer}. + * + * @param byteBuffer The buffer from which to parse the rta_cacheinfo. + * @return the parsed rta_cacheinfo struct, or {@code null} if the rta_cacheinfo struct + * could not be parsed successfully (for example, if it was truncated). + */ + @Nullable + public static StructRtaCacheInfo parse(@NonNull final ByteBuffer byteBuffer) { + if (byteBuffer.remaining() < STRUCT_SIZE) return null; + + // The ByteOrder must already have been set to native order. + return Struct.parse(StructRtaCacheInfo.class, byteBuffer); + } + + /** + * Write a rta_cacheinfo struct to {@link ByteBuffer}. + */ + public void pack(@NonNull final ByteBuffer byteBuffer) { + // The ByteOrder must already have been set to native order. + this.writeToByteBuffer(byteBuffer); + } +} From 34ab408adecb4f15535be27435ca1dd0d3d96e6b Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Mon, 19 Jun 2023 13:11:23 +0900 Subject: [PATCH 728/777] Parse rta_cacheinfo structure in RtNetlinkRouteMessage. Bug: 183601771 Test: atest NetworkStaticLibTests Change-Id: I9ea55ad297f5183853eeaa2e53f2406d79a90a20 --- .../util/netlink/RtNetlinkRouteMessage.java | 24 ++++++++++++++++++- .../netlink/RtNetlinkRouteMessageTest.java | 12 +++++++--- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java index 1705f1c803..9acac69cc2 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java @@ -51,6 +51,7 @@ public class RtNetlinkRouteMessage extends NetlinkMessage { public static final short RTA_DST = 1; public static final short RTA_OIF = 4; public static final short RTA_GATEWAY = 5; + public static final short RTA_CACHEINFO = 12; private int mIfindex; @NonNull @@ -59,6 +60,8 @@ public class RtNetlinkRouteMessage extends NetlinkMessage { private IpPrefix mDestination; @Nullable private InetAddress mGateway; + @Nullable + private StructRtaCacheInfo mRtaCacheInfo; private RtNetlinkRouteMessage(StructNlMsgHdr header) { super(header); @@ -66,6 +69,7 @@ public class RtNetlinkRouteMessage extends NetlinkMessage { mDestination = null; mGateway = null; mIfindex = 0; + mRtaCacheInfo = null; } public int getInterfaceIndex() { @@ -87,6 +91,11 @@ public class RtNetlinkRouteMessage extends NetlinkMessage { return mGateway; } + @Nullable + public StructRtaCacheInfo getRtaCacheInfo() { + return mRtaCacheInfo; + } + /** * Check whether the address families of destination and gateway match rtm_family in * StructRtmsg. @@ -158,6 +167,13 @@ public class RtNetlinkRouteMessage extends NetlinkMessage { routeMsg.mIfindex = nlAttr.getValueAsInt(0 /* 0 isn't a valid ifindex */); } + // RTA_CACHEINFO + byteBuffer.position(baseOffset); + nlAttr = StructNlAttr.findNextAttrOfType(RTA_CACHEINFO, byteBuffer); + if (nlAttr != null) { + routeMsg.mRtaCacheInfo = StructRtaCacheInfo.parse(nlAttr.getValueAsByteBuffer()); + } + return routeMsg; } @@ -180,6 +196,11 @@ public class RtNetlinkRouteMessage extends NetlinkMessage { final StructNlAttr ifindex = new StructNlAttr(RTA_OIF, mIfindex); ifindex.pack(byteBuffer); } + if (mRtaCacheInfo != null) { + final StructNlAttr cacheInfo = new StructNlAttr(RTA_CACHEINFO, + mRtaCacheInfo.writeToBytes()); + cacheInfo.pack(byteBuffer); + } } @Override @@ -189,7 +210,8 @@ public class RtNetlinkRouteMessage extends NetlinkMessage { + "Rtmsg{" + mRtmsg.toString() + "}, " + "destination{" + mDestination.getAddress().getHostAddress() + "}, " + "gateway{" + (mGateway == null ? "" : mGateway.getHostAddress()) + "}, " - + "ifindex{" + mIfindex + "} " + + "ifindex{" + mIfindex + "}, " + + "rta_cacheinfo{" + (mRtaCacheInfo == null ? "" : mRtaCacheInfo.toString()) + "} " + "}"; } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java index 55cfd50d40..9881653a5e 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkRouteMessageTest.java @@ -87,6 +87,8 @@ public class RtNetlinkRouteMessageTest { assertEquals(routeMsg.getDestination(), TEST_IPV6_GLOBAL_PREFIX); assertEquals(735, routeMsg.getInterfaceIndex()); assertEquals((Inet6Address) routeMsg.getGateway(), TEST_IPV6_LINK_LOCAL_GATEWAY); + + assertNotNull(routeMsg.getRtaCacheInfo()); } @Test @@ -106,7 +108,9 @@ public class RtNetlinkRouteMessageTest { + "0A400000FC02000100000000" // struct rtmsg + "1400010020010DB8000100000000000000000000" // RTA_DST + "14000500FE800000000000000000000000000001" // RTA_GATEWAY - + "08000400DF020000"; // RTA_OIF + + "08000400DF020000" // RTA_OIF + + "24000C0000000000000000005EEA000000000000" // RTA_CACHEINFO + + "00000000000000000000000000000000"; @Test public void testPackRtmNewRoute() { @@ -117,7 +121,7 @@ public class RtNetlinkRouteMessageTest { assertTrue(msg instanceof RtNetlinkRouteMessage); final RtNetlinkRouteMessage routeMsg = (RtNetlinkRouteMessage) msg; - final ByteBuffer packBuffer = ByteBuffer.allocate(76); + final ByteBuffer packBuffer = ByteBuffer.allocate(112); packBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. routeMsg.pack(packBuffer); assertEquals(RTM_NEWROUTE_PACK_HEX, HexDump.toHexString(packBuffer.array())); @@ -216,7 +220,9 @@ public class RtNetlinkRouteMessageTest { + "scope: 0, type: 1, flags: 0}, " + "destination{2001:db8:1::}, " + "gateway{fe80::1}, " - + "ifindex{735} " + + "ifindex{735}, " + + "rta_cacheinfo{clntref: 0, lastuse: 0, expires: 59998, error: 0, used: 0, " + + "id: 0, ts: 0, tsage: 0} " + "}"; assertEquals(expected, routeMsg.toString()); } From 9302d7d7c3458cd5b60c61ca4e7c579fc3c1b1a6 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 22 Jun 2023 15:55:03 +0900 Subject: [PATCH 729/777] Add constants for clat and v6 fragmentation Test: manual Change-Id: Ic18186c1a09c2bb79e7727c70d2d46d511a23075 --- .../net/module/util/NetworkStackConstants.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 6a6f5e10f5..54382f9696 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -17,6 +17,7 @@ package com.android.net.module.util; import android.net.InetAddresses; +import android.net.IpPrefix; import java.net.Inet4Address; import java.net.Inet6Address; @@ -99,6 +100,8 @@ public final class NetworkStackConstants { public static final int IPV4_ADDR_LEN = 4; public static final int IPV4_FLAG_MF = 0x2000; public static final int IPV4_FLAG_DF = 0x4000; + // getSockOpt() for v4 MTU + public static final int IP_MTU = 14; public static final Inet4Address IPV4_ADDR_ALL = makeInet4Address( (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff); public static final Inet4Address IPV4_ADDR_ANY = makeInet4Address( @@ -108,6 +111,12 @@ public final class NetworkStackConstants { (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 }); + + /** + * CLAT constants + */ + public static final IpPrefix CLAT_PREFIX = new IpPrefix("192.0.0.0/29"); + /** * IPv6 constants. * @@ -121,6 +130,9 @@ public final class NetworkStackConstants { public static final int IPV6_SRC_ADDR_OFFSET = 8; public static final int IPV6_DST_ADDR_OFFSET = 24; public static final int IPV6_MIN_MTU = 1280; + public static final int IPV6_FRAGMENT_HEADER_LEN = 8; + // getSockOpt() for v6 MTU + public static final int IPV6_MTU = 24; public static final Inet6Address IPV6_ADDR_ALL_NODES_MULTICAST = (Inet6Address) InetAddresses.parseNumericAddress("ff02::1"); public static final Inet6Address IPV6_ADDR_ALL_ROUTERS_MULTICAST = From 49e4a98f7883277c337905c963e53b1d2acc4d68 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 23 May 2023 18:41:39 +0900 Subject: [PATCH 730/777] Add a dumpService variant that uses libbinder_ndk. The one in this file requires libbinder and cannot be used when libbinder is not present (e.g., when compiling against the NDK). This allows users of this code not to link against libbinder, and have the resulting binary not depend on it: $ m CtsNativeNetPlatformTestCases netd_integration_test $ objdump -p out/target/product/vsoc_x86_64/testcases/netd_integration_test/x86_64/netd_integration_test64 | grep NEEDED | grep libbinder NEEDED libbinder.so NEEDED libbinder_ndk.so $ objdump -p out/target/product/vsoc_x86_64/testcases/CtsNativeNetPlatformTestCases/x86_64/CtsNativeNetPlatformTestCases64 | grep NEEDED | grep libbinder NEEDED libbinder_ndk.so $ Bug: 268440865 Test: see other CL in topic Merged-In: Icf982675aad4777677a36e357035809fb251d6e9 Change-Id: Icf982675aad4777677a36e357035809fb251d6e9 --- staticlibs/native/nettestutils/Android.bp | 8 ++++- .../native/nettestutils/DumpService.cpp | 35 +++++++++++++++++++ .../include/nettestutils/DumpService.h | 6 ++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/staticlibs/native/nettestutils/Android.bp b/staticlibs/native/nettestutils/Android.bp index 42df8e0a86..df3bb4288c 100644 --- a/staticlibs/native/nettestutils/Android.bp +++ b/staticlibs/native/nettestutils/Android.bp @@ -21,9 +21,15 @@ cc_library_static { export_include_dirs: ["include"], srcs: ["DumpService.cpp"], + // Don't depend on libbinder, because some users of this library may not want to link to it. + // CtsNativeNetPlatformTestCases is one such user. See r.android.com/2599405 . + header_libs: [ + "libbinder_headers", + ], + shared_libs: [ - "libbinder", "libutils", + "libbinder_ndk", ], cflags: [ "-Werror", diff --git a/staticlibs/native/nettestutils/DumpService.cpp b/staticlibs/native/nettestutils/DumpService.cpp index ba3d77e941..40c3b9a25e 100644 --- a/staticlibs/native/nettestutils/DumpService.cpp +++ b/staticlibs/native/nettestutils/DumpService.cpp @@ -17,10 +17,12 @@ #include "nettestutils/DumpService.h" #include +#include #include #include +// Version for code using libbinder (e.g., AIDL interfaces with the C++ backend). android::status_t dumpService(const android::sp& binder, const std::vector& args, std::vector& outputLines) { @@ -55,3 +57,36 @@ android::status_t dumpService(const android::sp& binder, return android::OK; } + +// Version for code using libbinder_ndk (e.g., AIDL interfaces with the NDK backend).. +android::status_t dumpService(const ndk::SpAIBinder& binder, + const char** args, + uint32_t num_args, + std::vector& outputLines) { + if (!outputLines.empty()) return -EUCLEAN; + + android::base::unique_fd localFd, remoteFd; + if (!Pipe(&localFd, &remoteFd)) return -errno; + + android::status_t ret; + // dump() blocks until another thread has consumed all its output. + std::thread dumpThread = + std::thread([&ret, binder, remoteFd{std::move(remoteFd)}, args, num_args]() { + ret = AIBinder_dump(binder.get(), remoteFd, args, num_args); + }); + + std::string dumpContent; + if (!android::base::ReadFdToString(localFd.get(), &dumpContent)) { + return -errno; + } + dumpThread.join(); + if (ret != android::OK) return ret; + + std::stringstream dumpStream(dumpContent); + std::string line; + while (std::getline(dumpStream, line)) { + outputLines.push_back(std::move(line)); + } + + return android::OK; +} diff --git a/staticlibs/native/nettestutils/include/nettestutils/DumpService.h b/staticlibs/native/nettestutils/include/nettestutils/DumpService.h index 2a721817a3..323d75243d 100644 --- a/staticlibs/native/nettestutils/include/nettestutils/DumpService.h +++ b/staticlibs/native/nettestutils/include/nettestutils/DumpService.h @@ -15,9 +15,15 @@ */ #include +#include #include android::status_t dumpService(const android::sp& binder, const std::vector& args, std::vector& outputLines); + +android::status_t dumpService(const ndk::SpAIBinder& binder, + const char** args, + uint32_t num_args, + std::vector& outputLines); From cba11a2370306c198aecdfe9f3c68b369896fe3a Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 21 Jun 2023 13:16:10 +0800 Subject: [PATCH 731/777] Parse DnsRecord by factory method Currently, DnsPacket calls DnsRecord constructor to create DnsRecord instances from a ByteBuffer. However, invoking DnsRecord constructor cannot create subclass instances of DnsRecord. To fix this, use a factory method to parse DnsRecord. This factory method will peek the nsType field of the DnsRecord as an argument, and it will use this field to determine which subclass of DnsRecord to create. This change is no-op, because it does not change the functionality of DnsPacket. However, it does allow subsequent changes to create subclass instances of DnsRecord in the future. Test: atest ConnectivityCoverageTests:android.net.connectivity.com.android.net.module.util.DnsPacketTest Change-Id: Ibbdeaf6e5a844573f393f05609310658d8d225b3 --- .../android/net/module/util/DnsPacket.java | 37 ++++++++++++++++--- .../net/module/util/DnsPacketTest.java | 8 ++-- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/DnsPacket.java b/staticlibs/framework/com/android/net/module/util/DnsPacket.java index 702d114e00..2ecbc939c9 100644 --- a/staticlibs/framework/com/android/net/module/util/DnsPacket.java +++ b/staticlibs/framework/com/android/net/module/util/DnsPacket.java @@ -19,7 +19,6 @@ package com.android.net.module.util; import static android.net.DnsResolver.TYPE_A; import static android.net.DnsResolver.TYPE_AAAA; -import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; import static com.android.net.module.util.DnsPacketUtils.DnsRecordParser.domainNameToLabels; @@ -245,9 +244,11 @@ public abstract class DnsPacket { * / RDATA / * / / * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * + * Note that this class is meant to be used by composition and not inheritance, and + * that classes implementing more specific DNS records should call #parse. */ - // TODO: Make DnsResourceRecord and DnsQuestion subclasses of DnsRecord, and construct - // corresponding object from factory methods. + // TODO: Make DnsResourceRecord and DnsQuestion subclasses of DnsRecord. public static class DnsRecord { // Refer to RFC 1035 section 2.3.4 for MAXNAMESIZE. // NAME_NORMAL and NAME_COMPRESSION are used for checking name compression, @@ -281,8 +282,7 @@ public abstract class DnsPacket { * @param buf ByteBuffer input of record, must be in network byte order * (which is the default). */ - @VisibleForTesting(visibility = PACKAGE) - public DnsRecord(@RecordType int rType, @NonNull ByteBuffer buf) + private DnsRecord(@RecordType int rType, @NonNull ByteBuffer buf) throws BufferUnderflowException, ParseException { Objects.requireNonNull(buf); this.rType = rType; @@ -306,6 +306,31 @@ public abstract class DnsPacket { } } + /** + * Create a new DnsRecord or subclass of DnsRecord instance from a positioned ByteBuffer. + * + * Peek the nsType, sending the buffer to corresponding DnsRecord subclass constructors + * to allow constructing the corresponding object. + */ + @VisibleForTesting(visibility = PRIVATE) + public static DnsRecord parse(@RecordType int rType, @NonNull ByteBuffer buf) + throws BufferUnderflowException, ParseException { + Objects.requireNonNull(buf); + final int oldPos = buf.position(); + // Parsed name not used, just for jumping to nsType position. + DnsRecordParser.parseName(buf, 0 /* Parse depth */, + true /* isNameCompressionSupported */); + // Peek the nsType. + final int nsType = Short.toUnsignedInt(buf.getShort()); + buf.position(oldPos); + // Return a DnsRecord instance by default for backward compatibility, this is useful + // when a partner supports new type of DnsRecord but does not inherit DnsRecord. + switch (nsType) { + default: + return new DnsRecord(rType, buf); + } + } + /** * Make an A or AAAA record based on the specified parameters. * @@ -507,7 +532,7 @@ public abstract class DnsPacket { mRecords[i] = new ArrayList(count); for (int j = 0; j < count; ++j) { try { - mRecords[i].add(new DnsRecord(i, buffer)); + mRecords[i].add(DnsRecord.parse(i, buffer)); } catch (BufferUnderflowException e) { throw new ParseException("Parse record fail", e); } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java index 409c1ebb77..28e183a95e 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DnsPacketTest.java @@ -219,7 +219,7 @@ public class DnsPacketTest { 0x00, 0x04, /* Data length */ (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 /* Address */}; final DnsPacket.DnsRecord questionsFromBytes = - new DnsPacket.DnsRecord(DnsPacket.QDSECTION, ByteBuffer.wrap(qdWithTTLRData)); + DnsPacket.DnsRecord.parse(DnsPacket.QDSECTION, ByteBuffer.wrap(qdWithTTLRData)); assertEquals(0, questionsFromBytes.ttl); assertNull(questionsFromBytes.getRR()); @@ -230,12 +230,12 @@ public class DnsPacketTest { 0x00, 0x01, /* Type */ 0x00, 0x01, /* Class */}; assertThrows(BufferUnderflowException.class, () -> - new DnsPacket.DnsRecord(DnsPacket.ANSECTION, ByteBuffer.wrap(anWithoutTTLRData))); + DnsPacket.DnsRecord.parse(DnsPacket.ANSECTION, ByteBuffer.wrap(anWithoutTTLRData))); } private void assertDnsRecordRoundTrip(DnsPacket.DnsRecord before) throws IOException { - final DnsPacket.DnsRecord after = new DnsPacket.DnsRecord(before.rType, + final DnsPacket.DnsRecord after = DnsPacket.DnsRecord.parse(before.rType, ByteBuffer.wrap(before.getBytes())); assertEquals(after, before); } @@ -393,7 +393,7 @@ public class DnsPacketTest { "test.com", TYPE_AAAA, CLASS_IN); final DnsPacket.DnsRecord testAnswer = DnsPacket.DnsRecord.makeCNameRecord( DnsPacket.ANSECTION, "test.com", CLASS_IN, 9, "www.test.com"); - final DnsPacket.DnsRecord questionFromBytes = new DnsPacket.DnsRecord(DnsPacket.QDSECTION, + final DnsPacket.DnsRecord questionFromBytes = DnsPacket.DnsRecord.parse(DnsPacket.QDSECTION, ByteBuffer.wrap(testQuestion.getBytes())); assertEquals(testQuestion, questionFromBytes); assertEquals(testQuestion.hashCode(), questionFromBytes.hashCode()); From 8f4debc3f988f7e530d64874343141b49061d65c Mon Sep 17 00:00:00 2001 From: Mike Yu Date: Tue, 6 Jun 2023 11:28:57 +0000 Subject: [PATCH 732/777] Add DnsResolverModuleTest annotation This annotation can be used to mark a test case that requires the latest resolv module. Tests that don't run with the latest resolv module (for example CtsNetTestCasesLatestSdk) can exclude the testcases being flaky due to some known issues in old resolv module. Bug: 279846955 Test: TreeHugger Change-Id: Ie19eed1c4aa17645c4eec45493e7999027a01205 --- .../testutils/DnsResolverModuleTest.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 staticlibs/testutils/hostdevice/com/android/testutils/DnsResolverModuleTest.kt diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/DnsResolverModuleTest.kt b/staticlibs/testutils/hostdevice/com/android/testutils/DnsResolverModuleTest.kt new file mode 100644 index 0000000000..9e97d51e31 --- /dev/null +++ b/staticlibs/testutils/hostdevice/com/android/testutils/DnsResolverModuleTest.kt @@ -0,0 +1,22 @@ +/* + * 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 com.android.testutils + +/** + * Indicates that the test covers functionality that was rolled out in a resolv module update. + */ +annotation class DnsResolverModuleTest From 3a4ad37d61e7487f6078e3f078ec64eb4cb7f8ca Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 30 Jun 2023 23:00:25 +0900 Subject: [PATCH 733/777] Remove StructIfaddrMsg ctor VisibleForTesting annotation. This allows other class to refer StructIfaddrMsg constructor as well, otherwise, the default visibility is private. Bug: 263222068 Test: atest NetworkStaticLibTests Change-Id: If571b014ade51e3387748a4df0abcb49b59cb462 --- .../com/android/net/module/util/netlink/StructIfaddrMsg.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructIfaddrMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructIfaddrMsg.java index 2802726352..f9781a7b27 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructIfaddrMsg.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructIfaddrMsg.java @@ -18,7 +18,6 @@ package com.android.net.module.util.netlink; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; import com.android.net.module.util.Struct; import com.android.net.module.util.Struct.Field; @@ -50,7 +49,6 @@ public class StructIfaddrMsg extends Struct { @Field(order = 4, type = Type.S32) public final int index; - @VisibleForTesting public StructIfaddrMsg(short family, short prefixLen, short flags, short scope, int index) { this.family = family; this.prefixLen = prefixLen; From 723515738d3c297b595e23761e5836d3825b55f6 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 8 Feb 2023 16:17:42 +0900 Subject: [PATCH 734/777] Add a method helper to create RTM_DELADDR message in user space. Bug: 260934173 Bug: 263222068 Test: atest NetworkStaticLibTests Change-Id: Ibddaed91b12d3f27778d0bd2171bc5be38ff8bda --- .../net/module/util/netlink/NetlinkUtils.java | 21 +++++++++ .../util/netlink/RtNetlinkAddressMessage.java | 47 ++++++++++++++++++- .../netlink/RtNetlinkAddressMessageTest.java | 35 ++++++++++++++ 3 files changed, 102 insertions(+), 1 deletion(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java index 0f7bd80b6e..73c88c778c 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java @@ -195,6 +195,27 @@ public class NetlinkUtils { } } + /** + * Send an RTM_DELADDR message to kernel to delete an IPv6 address. + * + * @param ifIndex interface index. + * @param ip IPv6 address to be deleted. + * @param prefixlen IPv6 address prefix length. + */ + public static boolean sendRtmDelAddressRequest(int ifIndex, final Inet6Address ip, + short prefixlen) { + Objects.requireNonNull(ip, "IPv6 address to be deleted should not be null."); + final byte[] msg = RtNetlinkAddressMessage.newRtmDelAddressMessage(1 /* seqNo*/, ip, + prefixlen, ifIndex); + try { + NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, msg); + return true; + } catch (ErrnoException e) { + Log.e(TAG, "Fail to send RTM_DELADDR to delete " + ip.getHostAddress(), e); + return false; + } + } + /** * Create netlink socket with the given netlink protocol type. * diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java index 2829b927e8..cbe0ab0e93 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java +++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java @@ -161,7 +161,7 @@ public class RtNetlinkAddressMessage extends NetlinkMessage { } /** - * A convenience method to create an RTM_NEWADDR message. + * A convenience method to create a RTM_NEWADDR message. */ public static byte[] newRtmNewAddressMessage(int seqNo, @NonNull final InetAddress ip, short prefixlen, int flags, byte scope, int ifIndex, long preferred, long valid) { @@ -192,6 +192,51 @@ public class RtNetlinkAddressMessage extends NetlinkMessage { return bytes; } + /** + * A convenience method to create a RTM_DELADDR message. + */ + public static byte[] newRtmDelAddressMessage(int seqNo, @NonNull final InetAddress ip, + short prefixlen, int ifIndex) { + Objects.requireNonNull(ip, "IP address to be deleted via netlink message cannot be null"); + + final int ifaAddrAttrLength = NetlinkConstants.alignedLengthOf( + StructNlAttr.NLA_HEADERLEN + ip.getAddress().length); + final int length = StructNlMsgHdr.STRUCT_SIZE + StructIfaddrMsg.STRUCT_SIZE + + ifaAddrAttrLength; + final byte[] bytes = new byte[length]; + final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); + byteBuffer.order(ByteOrder.nativeOrder()); + + final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); + nlmsghdr.nlmsg_len = length; + nlmsghdr.nlmsg_type = NetlinkConstants.RTM_DELADDR; + nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nlmsghdr.nlmsg_seq = seqNo; + nlmsghdr.pack(byteBuffer); + + final byte family = + (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET); + // Actually kernel ignores scope and flags(only deal with IFA_F_MANAGETEMPADDR, it + // indicates that all relevant IPv6 temporary addresses should be deleted as well when + // user space intends to delete a global IPv6 address with IFA_F_MANAGETEMPADDR), so + // far IFA_F_MANAGETEMPADDR flag isn't used in user space, it's fine to ignore it. + // However, we need to add IFA_FLAGS attribute in RTM_DELADDR if flags parsing should + // be supported in the future. + final StructIfaddrMsg ifaddrmsg = new StructIfaddrMsg(family, prefixlen, + (short) 0 /* flags */, (short) 0 /* scope */, ifIndex); + ifaddrmsg.pack(byteBuffer); + + final StructNlAttr address = new StructNlAttr(IFA_ADDRESS, ip); + address.pack(byteBuffer); + + return bytes; + } + + // This function helper gives the required buffer size for IFA_ADDRESS, IFA_CACHEINFO and + // IFA_FLAGS attributes encapsulation. However, that's not a mandatory requirement for all + // RtNetlinkAddressMessage, e.g. RTM_DELADDR sent from user space to kernel to delete an + // IP address only requires IFA_ADDRESS attribute. The caller should check if these attributes + // are necessary to carry when constructing a RtNetlinkAddressMessage. private int getRequiredSpace() { int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructIfaddrMsg.STRUCT_SIZE; // IFA_ADDRESS attr diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java index 99d96b5a62..01126d2f82 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java @@ -178,6 +178,34 @@ public class RtNetlinkAddressMessageTest { assertArrayEquals(expectedNewAddress, bytes); } + @Test + public void testCreateRtmDelAddressMessage() { + // Hexadecimal representation of our created packet. + final String expectedDelAddressHex = + // struct nlmsghdr + "2C000000" + // length = 44 + "1500" + // type = 21 (RTM_DELADDR) + "0500" + // flags = NLM_F_ACK | NLM_F_REQUEST + "01000000" + // seqno = 1 + "00000000" + // pid = 0 (send to kernel) + // struct IfaddrMsg + "0A" + // family = inet6 + "40" + // prefix len = 64 + "00" + // flags = 0 + "00" + // scope = RT_SCOPE_UNIVERSE + "3B000000" + // ifindex = 59 + // struct nlattr: IFA_ADDRESS + "1400" + // len + "0100" + // type + "20010DB8000100000000000000000100"; // IP address = 2001:db8:1::100 + final byte[] expectedDelAddress = + HexEncoding.decode(expectedDelAddressHex.toCharArray(), false); + + final byte[] bytes = RtNetlinkAddressMessage.newRtmDelAddressMessage(1 /* seqno */, + TEST_GLOBAL_ADDRESS, (short) 64 /* prefix len */, 59 /* ifindex */); + assertArrayEquals(expectedDelAddress, bytes); + } + @Test public void testCreateRtmNewAddressMessage_nullIpAddress() { assertThrows(NullPointerException.class, @@ -188,6 +216,13 @@ public class RtNetlinkAddressMessageTest { (long) 0xFFFFFFFF /* valid */)); } + @Test + public void testCreateRtmDelAddressMessage_nullIpAddress() { + assertThrows(NullPointerException.class, + () -> RtNetlinkAddressMessage.newRtmDelAddressMessage(1 /* seqno */, + null /* IP address */, (short) 0 /* prefix len */, 59 /* ifindex */)); + } + @Test public void testCreateRtmNewAddressMessage_u32Flags() { // Hexadecimal representation of our created packet. From 2ba922ad85c71d4c379b2e5a325dace7e785c731 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Tue, 4 Jul 2023 17:54:39 +0900 Subject: [PATCH 735/777] Use default package version in isFeatureEnabled if package is not found Bug: 287359634 Bug: 289173013 Test: atest HostsideVpnTests Change-Id: I379cde0391f96a8ac5dcdb2ff7723ea950684e36 --- .../net/module/util/DeviceConfigUtils.java | 51 ++++++++++--------- .../module/util/DeviceConfigUtilsTest.java | 24 +++++++++ 2 files changed, 50 insertions(+), 25 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index dae4eb913f..138c1e5419 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -53,6 +53,8 @@ public final class DeviceConfigUtils { "com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK"; private static final String CONNECTIVITY_RES_PKG_DIR = "/apex/" + TETHERING_MODULE_NAME + "/"; + private static final long DEFAULT_PACKAGE_VERSION = 1000; + @VisibleForTesting public static void resetPackageVersionCacheForTest() { sPackageVersion = -1; @@ -60,17 +62,21 @@ public final class DeviceConfigUtils { } private static volatile long sPackageVersion = -1; - private static long getPackageVersion(@NonNull final Context context) - throws PackageManager.NameNotFoundException { + private static long getPackageVersion(@NonNull final Context context) { // sPackageVersion may be set by another thread just after this check, but querying the // package version several times on rare occasions is fine. if (sPackageVersion >= 0) { return sPackageVersion; } - final long version = context.getPackageManager().getPackageInfo( - context.getPackageName(), 0).getLongVersionCode(); - sPackageVersion = version; - return version; + try { + final long version = context.getPackageManager().getPackageInfo( + context.getPackageName(), 0).getLongVersionCode(); + sPackageVersion = version; + return version; + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Failed to get package info: " + e); + return DEFAULT_PACKAGE_VERSION; + } } /** @@ -173,13 +179,8 @@ public final class DeviceConfigUtils { */ public static boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, @NonNull String name, boolean defaultEnabled) { - try { - final long packageVersion = getPackageVersion(context); - return isFeatureEnabled(context, packageVersion, namespace, name, defaultEnabled); - } catch (PackageManager.NameNotFoundException e) { - Log.e(TAG, "Could not find the package name", e); - return false; - } + final long packageVersion = getPackageVersion(context); + return isFeatureEnabled(context, packageVersion, namespace, name, defaultEnabled); } /** @@ -205,18 +206,12 @@ public final class DeviceConfigUtils { throw new IllegalArgumentException( "This method is only usable by the tethering module"); } - try { - final long packageVersion = getTetheringModuleVersion(context); - return isFeatureEnabled(context, packageVersion, namespace, name, defaultEnabled); - } catch (PackageManager.NameNotFoundException e) { - Log.e(TAG, "Could not find the module name", e); - return false; - } + final long packageVersion = getTetheringModuleVersion(context); + return isFeatureEnabled(context, packageVersion, namespace, name, defaultEnabled); } private static boolean isFeatureEnabled(@NonNull Context context, long packageVersion, - @NonNull String namespace, String name, boolean defaultEnabled) - throws PackageManager.NameNotFoundException { + @NonNull String namespace, String name, boolean defaultEnabled) { final int propertyVersion = getDeviceConfigPropertyInt(namespace, name, 0 /* default value */); return (propertyVersion == 0 && defaultEnabled) @@ -251,11 +246,17 @@ public final class DeviceConfigUtils { } private static volatile long sModuleVersion = -1; - private static long getTetheringModuleVersion(@NonNull Context context) - throws PackageManager.NameNotFoundException { + private static long getTetheringModuleVersion(@NonNull Context context) { if (sModuleVersion >= 0) return sModuleVersion; - sModuleVersion = resolveTetheringModuleVersion(context); + try { + sModuleVersion = resolveTetheringModuleVersion(context); + } catch (PackageManager.NameNotFoundException e) { + // It's expected to fail tethering module version resolution on the devices with + // flattened apex + Log.e(TAG, "Failed to resolve tethering module version: " + e); + return DEFAULT_PACKAGE_VERSION; + } return sModuleVersion; } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java index b75939b9b4..328c39a4aa 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -246,10 +246,34 @@ public class DeviceConfigUtilsTest { @Test public void testFeatureIsEnabledWithException() throws Exception { doThrow(NameNotFoundException.class).when(mPm).getPackageInfo(anyString(), anyInt()); + + // Feature should be enabled by flag value "1". + doReturn("1").when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), + eq(TEST_EXPERIMENT_FLAG))); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG)); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + + // Feature should be disabled by flag value "999999999". + doReturn("999999999").when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), + eq(TEST_EXPERIMENT_FLAG))); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + + // Follow defaultEnabled if the flag is not set + doReturn(null).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), + eq(TEST_EXPERIMENT_FLAG))); + assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, false /* defaultEnabled */)); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, true /* defaultEnabled */)); + assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, true /* defaultEnabled */)); } @Test From 3ffb814525dfecc2264da77dcefd7ef28206ea3a Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Tue, 4 Jul 2023 12:38:24 +0900 Subject: [PATCH 736/777] Remove duplicated IfaddrMsg and RtgenMsg Struct used in NetlinkUtilsTests. Bug: 263222068 Test: atest NetworkStaticLibTests Change-Id: Iea5f91e0b20db7cd4cb4451b06e713dd68e9c387 --- .../module/util/netlink/NetlinkUtilsTest.java | 39 +++---------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java index 6fbfbf91ad..32ce5214bb 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java @@ -183,7 +183,7 @@ public class NetlinkUtilsTest { assertEquals(localAddr.getPortId(), nlmsghdr.nlmsg_pid); addrMessageCount++; - final IfaddrMsg ifaMsg = Struct.parse(IfaddrMsg.class, response); + final StructIfaddrMsg ifaMsg = Struct.parse(StructIfaddrMsg.class, response); assertTrue( "Non-IP address family: " + ifaMsg.family, ifaMsg.family == AF_INET || ifaMsg.family == AF_INET6); @@ -196,7 +196,7 @@ public class NetlinkUtilsTest { /** A convenience method to create an RTM_GETADDR request message. */ private static byte[] newGetAddrRequest(int seqNo) { - final int length = StructNlMsgHdr.STRUCT_SIZE + Struct.getSize(RtgenMsg.class); + final int length = StructNlMsgHdr.STRUCT_SIZE + Struct.getSize(StructIfaddrMsg.class); final byte[] bytes = new byte[length]; final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); byteBuffer.order(ByteOrder.nativeOrder()); @@ -208,38 +208,11 @@ public class NetlinkUtilsTest { nlmsghdr.nlmsg_seq = seqNo; nlmsghdr.pack(byteBuffer); - final RtgenMsg rtgenMsg = new RtgenMsg(); - rtgenMsg.family = (byte) AF_UNSPEC; - rtgenMsg.writeToByteBuffer(byteBuffer); + final StructIfaddrMsg addrMsg = new StructIfaddrMsg((byte) AF_UNSPEC /* family */, + (short) 0 /* prefixLen */, (short) 0 /* flags */, (short) 0 /* scope */, + 0 /* index */); + addrMsg.pack(byteBuffer); return bytes; } - - /** From uapi/linux/rtnetlink.h */ - private static class RtgenMsg extends Struct { - @Field(order = 0, type = Type.U8) - public short family; - } - - /** - * From uapi/linux/ifaddr.h - * - * Public ensures visibility to Struct class - */ - public static class IfaddrMsg extends Struct { - @Field(order = 0, type = Type.U8) - public short family; - - @Field(order = 1, type = Type.U8) - public short prefixlen; - - @Field(order = 2, type = Type.U8) - public short flags; - - @Field(order = 3, type = Type.U8) - public short scope; - - @Field(order = 4, type = Type.S32) - public int index; - } } From cece401526e13fc50effdf957ff5f958900f8d4e Mon Sep 17 00:00:00 2001 From: fqjc86 Date: Thu, 8 Jun 2023 19:46:45 +0800 Subject: [PATCH 737/777] Add DomainsUtils class to encode/decode domain names. Both encode and deocde methods support message compression which is described in RFC1035 section 4.1.4. We can leverage both methods in a follow-up CL to parse DHCPv4 option 119 and DNSSL RA option. This cl also adds maxLabelCount argument for DnsRecordParser#parseName to prevent the potential recursion from overflowing the stack. Bug: 189865016 Test: atest NetworkStaticLibTests Change-Id: I624649c224f141848a475ac85c56012d138c5224 --- staticlibs/Android.bp | 1 + .../android/net/module/util/DomainUtils.java | 143 ++++++++++++ .../net/module/util/DnsPacketUtils.java | 19 +- .../net/module/util/DomainUtilsTest.java | 206 ++++++++++++++++++ 4 files changed, 365 insertions(+), 4 deletions(-) create mode 100644 staticlibs/device/com/android/net/module/util/DomainUtils.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/DomainUtilsTest.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index ff65228aa4..e1b5601db2 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -35,6 +35,7 @@ java_library { name: "net-utils-device-common", srcs: [ "device/com/android/net/module/util/DeviceConfigUtils.java", + "device/com/android/net/module/util/DomainUtils.java", "device/com/android/net/module/util/FdEventsReader.java", "device/com/android/net/module/util/NetworkMonitorUtils.java", "device/com/android/net/module/util/PacketReader.java", diff --git a/staticlibs/device/com/android/net/module/util/DomainUtils.java b/staticlibs/device/com/android/net/module/util/DomainUtils.java new file mode 100644 index 0000000000..80e0b64bab --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/DomainUtils.java @@ -0,0 +1,143 @@ +/* + * 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 com.android.net.module.util; + +import android.util.ArrayMap; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.net.module.util.DnsPacketUtils.DnsRecordParser; + +import java.nio.BufferOverflowException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + +/** + * Utilities for encoding/decoding the domain name or domain search list. + * + * @hide + */ +public final class DomainUtils { + private static final String TAG = "DomainUtils"; + private static final int MAX_OPTION_LEN = 255; + + @NonNull + private static String getSubstring(@NonNull final String string, @NonNull final String[] labels, + int index) { + int beginIndex = 0; + for (int i = 0; i < index; i++) { + beginIndex += labels[i].length() + 1; // include the dot + } + return string.substring(beginIndex); + } + + /** + * Encode the given single domain name to byte array, comply with RFC1035 section-3.1. + * + * @return null if the given domain string is invalid, otherwise, return a byte array + * wrapping the encoded domain, not including any padded octets, caller should + * pad zero octets at the end if needed. + */ + @Nullable + public static byte[] encode(@NonNull final String domain) { + if (!DnsRecordParser.isHostName(domain)) return null; + return encode(new String[]{ domain }, false /* compression */); + } + + /** + * Encode the given multiple domain names to byte array, comply with RFC1035 section-3.1 + * and section 4.1.4 (message compression) if enabled. + * + * @return Null if encode fails due to BufferOverflowException, otherwise, return a byte + * array wrapping the encoded domains, not including any padded octets, caller + * should pad zero octets at the end if needed. The byte array may be empty if + * the given domain strings are invalid. + */ + @Nullable + public static byte[] encode(@NonNull final String[] domains, boolean compression) { + try { + final ByteBuffer buffer = ByteBuffer.allocate(MAX_OPTION_LEN); + final ArrayMap offsetMap = new ArrayMap<>(); + for (int i = 0; i < domains.length; i++) { + if (!DnsRecordParser.isHostName(domains[i])) { + Log.e(TAG, "Skip invalid domain name " + domains[i]); + continue; + } + final String[] labels = domains[i].split("\\."); + for (int j = 0; j < labels.length; j++) { + if (compression) { + final String suffix = getSubstring(domains[i], labels, j); + if (offsetMap.containsKey(suffix)) { + int offsetOfSuffix = offsetMap.get(suffix); + offsetOfSuffix |= 0xC000; + buffer.putShort((short) offsetOfSuffix); + break; // unnecessary to put the compressed string into map + } else { + offsetMap.put(suffix, buffer.position()); + } + } + // encode the domain name string without compression when: + // - compression feature isn't enabled, + // - suffix does not match any string in the map. + final byte[] labelBytes = labels[j].getBytes(StandardCharsets.UTF_8); + buffer.put((byte) labelBytes.length); + buffer.put(labelBytes); + if (j == labels.length - 1) { + // Pad terminate label at the end of last label. + buffer.put((byte) 0); + } + } + } + buffer.flip(); + final byte[] out = new byte[buffer.limit()]; + buffer.get(out); + return out; + } catch (BufferOverflowException e) { + Log.e(TAG, "Fail to encode domain name and stop encoding", e); + return null; + } + } + + /** + * Decode domain name(s) from the given byteBuffer. Decode follows RFC1035 section 3.1 and + * section 4.1.4(message compression). + * + * @return domain name(s) string array with space separated, or empty string if decode fails. + */ + @NonNull + public static String[] decode(@NonNull final ByteBuffer buffer, boolean compression) { + final ArrayList domainList = new ArrayList<>(); + while (buffer.remaining() > 0) { + try { + // TODO: replace the recursion with loop in parseName and don't need to pass in the + // maxLabelCount parameter to prevent recursion from overflowing stack. + final String domain = DnsRecordParser.parseName(buffer, 0 /* depth */, + 15 /* maxLabelCount */, compression); + if (!DnsRecordParser.isHostName(domain)) continue; + domainList.add(domain); + } catch (BufferUnderflowException | DnsPacket.ParseException e) { + Log.e(TAG, "Fail to parse domain name and stop parsing", e); + break; + } + } + return domainList.toArray(new String[0]); + } +} diff --git a/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java b/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java index c47bfa0746..105d783765 100644 --- a/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java +++ b/staticlibs/framework/com/android/net/module/util/DnsPacketUtils.java @@ -128,6 +128,15 @@ public final class DnsPacketUtils { && !InetAddresses.isNumericAddress(hostName); } + /** + * Parses the domain / target name of a DNS record. + */ + public static String parseName(final ByteBuffer buf, int depth, + boolean isNameCompressionSupported) throws + BufferUnderflowException, DnsPacket.ParseException { + return parseName(buf, depth, MAXLABELCOUNT, isNameCompressionSupported); + } + /** * Parses the domain / target name of a DNS record. * @@ -136,10 +145,10 @@ public final class DnsPacketUtils { * record may or may not support Name Compression, depending on the record TYPE. Moreover, * even if Name Compression is supported, its usage is left to the implementation. */ - public static String parseName(ByteBuffer buf, int depth, + public static String parseName(final ByteBuffer buf, int depth, int maxLabelCount, boolean isNameCompressionSupported) throws BufferUnderflowException, DnsPacket.ParseException { - if (depth > MAXLABELCOUNT) { + if (depth > maxLabelCount) { throw new DnsPacket.ParseException("Failed to parse name, too many labels"); } final int len = Byte.toUnsignedInt(buf.get()); @@ -158,7 +167,8 @@ public final class DnsPacketUtils { "Parse compression name fail, invalid compression"); } buf.position(offset); - final String pointed = parseName(buf, depth + 1, isNameCompressionSupported); + final String pointed = parseName(buf, depth + 1, maxLabelCount, + isNameCompressionSupported); buf.position(oldPos); return pointed; } else { @@ -168,7 +178,8 @@ public final class DnsPacketUtils { if (head.length() > MAXLABELSIZE) { throw new DnsPacket.ParseException("Parse name fail, invalid label length"); } - final String tail = parseName(buf, depth + 1, isNameCompressionSupported); + final String tail = parseName(buf, depth + 1, maxLabelCount, + isNameCompressionSupported); return TextUtils.isEmpty(tail) ? head : head + "." + tail; } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DomainUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DomainUtilsTest.java new file mode 100644 index 0000000000..606ed5fb7b --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DomainUtilsTest.java @@ -0,0 +1,206 @@ +/* + * 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 com.android.net.module.util; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import libcore.util.HexEncoding; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.nio.ByteBuffer; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class DomainUtilsTest { + @Test + public void testEncodeInvalidDomain() { + byte[] buffer = DomainUtils.encode(".google.com"); + assertNull(buffer); + + buffer = DomainUtils.encode("google.com."); + assertNull(buffer); + + buffer = DomainUtils.encode("-google.com"); + assertNull(buffer); + + buffer = DomainUtils.encode("google.com-"); + assertNull(buffer); + + buffer = DomainUtils.encode("google..com"); + assertNull(buffer); + + buffer = DomainUtils.encode("google!.com"); + assertNull(buffer); + + buffer = DomainUtils.encode("google.o"); + assertNull(buffer); + + buffer = DomainUtils.encode("google,com"); + assertNull(buffer); + } + + @Test + public void testEncodeValidDomainNamesWithoutCompression() { + // Single domain: "google.com" + String suffix = "06676F6F676C6503636F6D00"; + byte[] buffer = DomainUtils.encode("google.com"); + //assertNotNull(buffer); + assertEquals(suffix, HexEncoding.encodeToString(buffer)); + + // Single domain: "google-guest.com" + suffix = "0C676F6F676C652D677565737403636F6D00"; + buffer = DomainUtils.encode("google-guest.com"); + assertNotNull(buffer); + assertEquals(suffix, HexEncoding.encodeToString(buffer)); + + // domain search list: "example.corp.google.com", "corp.google.com", "google.com" + suffix = "076578616D706C6504636F727006676F6F676C6503636F6D00" // example.corp.google.com + + "04636F727006676F6F676C6503636F6D00" // corp.google.com + + "06676F6F676C6503636F6D00"; // google.com + buffer = DomainUtils.encode(new String[] { + "example.corp.google.com", "corp.google.com", "google.com"}, + false /* compression */); + assertNotNull(buffer); + assertEquals(suffix, HexEncoding.encodeToString(buffer)); + + + // domain search list: "example.corp.google.com", "corp..google.com"(invalid domain), + // "google.com" + suffix = "076578616D706C6504636F727006676F6F676C6503636F6D00" // example.corp.google.com + + "06676F6F676C6503636F6D00"; // google.com + buffer = DomainUtils.encode(new String[] { + "example.corp.google.com", "corp..google.com", "google.com"}, + false /* compression */); + assertNotNull(buffer); + assertEquals(suffix, HexEncoding.encodeToString(buffer)); + + // Invalid domain search list: "corp..google.com", "..google.com" + buffer = DomainUtils.encode(new String[] {"corp..google.com", "..google.com"}, + false /* compression */); + assertEquals(0, buffer.length); + } + + @Test + public void testEncodeValidDomainNamesWithCompression() { + // domain search list: "example.corp.google.com", "corp.google.com", "google.com" + String suffix = + "076578616D706C6504636F727006676F6F676C6503636F6D00" // example.corp.google.com + + "C008" // corp.google.com + + "C00D"; // google.com + byte[] buffer = DomainUtils.encode(new String[] { + "example.corp.google.com", "corp.google.com", "google.com"}, true); + assertNotNull(buffer); + assertEquals(suffix, HexEncoding.encodeToString(buffer)); + + // domain search list: "example.corp.google.com", "a.example.corp.google.com", "google.com" + suffix = "076578616D706C6504636F727006676F6F676C6503636F6D00" // example.corp.google.com + + "0161C000" // a.example.corp.google.com + + "C00D"; // google.com + buffer = DomainUtils.encode(new String[] { + "example.corp.google.com", "a.example.corp.google.com", "google.com"}, true); + assertNotNull(buffer); + assertEquals(suffix, HexEncoding.encodeToString(buffer)); + + // domain search list: "example.corp.google.com", "google.com", "gle.com" + suffix = "076578616D706C6504636F727006676F6F676C6503636F6D00" // example.corp.google.com + + "C00D" // google.com + + "03676C65C014"; // gle.com + buffer = DomainUtils.encode(new String[] { + "example.corp.google.com", "google.com", "gle.com"}, true); + assertNotNull(buffer); + assertEquals(suffix, HexEncoding.encodeToString(buffer)); + + // domain search list: "example.corp.google.com", "google.com", "google" + suffix = "076578616D706C6504636F727006676F6F676C6503636F6D00" // example.corp.google.com + + "C00D"; // google.com + buffer = DomainUtils.encode(new String[] { + "example.corp.google.com", "google.com", "google"}, true); + assertNotNull(buffer); + assertEquals(suffix, HexEncoding.encodeToString(buffer)); + + // domain search list: "example.corp.google.com", "..google.com"(invalid domain), "google" + suffix = "076578616D706C6504636F727006676F6F676C6503636F6D00"; // example.corp.google.com + buffer = DomainUtils.encode(new String[] { + "example.corp.google.com", "..google.com", "google"}, true); + assertNotNull(buffer); + assertEquals(suffix, HexEncoding.encodeToString(buffer)); + + // domain search list: "example.corp.google.com", "suffix.example.edu.cn", "edu.cn" + suffix = "076578616D706C6504636F727006676F6F676C6503636F6D00" // example.corp.google.com + + "06737566666978076578616D706C650365647502636E00" // suffix.example.edu.cn + + "C028"; // edu.cn + buffer = DomainUtils.encode(new String[] { + "example.corp.google.com", "suffix.example.edu.cn", "edu.cn"}, true); + assertNotNull(buffer); + assertEquals(suffix, HexEncoding.encodeToString(buffer)); + + // domain search list: "google.com", "example.com", "sub.example.com" + suffix = "06676F6F676C6503636F6D00" // google.com + + "076578616D706C65C007" // example.com + + "03737562C00C"; // sub.example.com + buffer = DomainUtils.encode(new String[] { + "google.com", "example.com", "sub.example.com"}, true); + assertNotNull(buffer); + assertEquals(suffix, HexEncoding.encodeToString(buffer)); + } + + @Test + public void testDecodeDomainNames() { + String suffixes = "06676F6F676C6503636F6D00" // google.com + + "076578616D706C6503636F6D00" // example.com + + "06676F6F676C6500"; // google + String[] expected = new String[] {"google.com", "example.com"}; + ByteBuffer buffer = ByteBuffer.wrap(HexEncoding.decode(suffixes)); + String[] suffixString = DomainUtils.decode(buffer, false /* compression */); + assertArrayEquals(expected, suffixString); + + // include suffix with invalid length: 64 + suffixes = "06676F6F676C6503636F6D00" // google.com + + "406578616D706C6503636F6D00" // example.com(length=64) + + "06676F6F676C6500"; // google + expected = new String[] {"google.com"}; + buffer = ByteBuffer.wrap(HexEncoding.decode(suffixes)); + suffixString = DomainUtils.decode(buffer, false /* compression */); + assertArrayEquals(expected, suffixString); + + // include suffix with invalid length: 0 + suffixes = "06676F6F676C6503636F6D00" // google.com + + "076578616D706C6503636F6D00" // example.com + + "00676F6F676C6500"; // google(length=0) + expected = new String[] {"google.com", "example.com"}; + buffer = ByteBuffer.wrap(HexEncoding.decode(suffixes)); + suffixString = DomainUtils.decode(buffer, false /* compression */); + assertArrayEquals(expected, suffixString); + + suffixes = + "076578616D706C6504636F727006676F6F676C6503636F6D00" // example.corp.google.com + + "C008" // corp.google.com + + "C00D"; // google.com + expected = new String[] {"example.corp.google.com", "corp.google.com", "google.com"}; + buffer = ByteBuffer.wrap(HexEncoding.decode(suffixes)); + suffixString = DomainUtils.decode(buffer, true /* compression */); + assertArrayEquals(expected, suffixString); + } +} From da97a39255987fded622d619ee665d57e3947890 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Tue, 4 Jul 2023 14:58:42 +0900 Subject: [PATCH 738/777] Improve testBasicWorkingGetAddrQuery by checking the specific IPv4/v6 address. Parse the entire RTM_NEWADDR message instead of only parsing the nlmsg header and Ifaddr header. Besides, that would be better to know which IP address will be returned from kernel via netlink message, that's IPv4 and IPv6 loopback addresses. Test: atest NetworkStaticLibTests Change-Id: I3a01137db4a7774fa30ebdec5a1711697991b9fe --- staticlibs/tests/unit/Android.bp | 1 + .../module/util/netlink/NetlinkUtilsTest.java | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index 40371e63b2..8c49954e06 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -22,6 +22,7 @@ android_library { "net-utils-device-common-bpf", "net-utils-device-common-ip", "net-utils-device-common-wear", + "truth", ], libs: [ "android.test.runner", diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java index 32ce5214bb..dac5911a77 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java @@ -26,6 +26,8 @@ import static com.android.net.module.util.netlink.NetlinkUtils.DEFAULT_RECV_BUFS import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -50,6 +52,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.io.FileDescriptor; +import java.net.InetAddress; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.file.Files; @@ -170,7 +173,9 @@ public class NetlinkUtilsTest { assertEquals(0, response.position()); assertEquals(ByteOrder.nativeOrder(), response.order()); - final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(response); + final NetlinkMessage msg = NetlinkMessage.parse(response, NETLINK_ROUTE); + assertNotNull(msg); + final StructNlMsgHdr nlmsghdr = msg.getHeader(); assertNotNull(nlmsghdr); if (nlmsghdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) { @@ -181,12 +186,15 @@ public class NetlinkUtilsTest { assertTrue((nlmsghdr.nlmsg_flags & StructNlMsgHdr.NLM_F_MULTI) != 0); assertEquals(testSeqno, nlmsghdr.nlmsg_seq); assertEquals(localAddr.getPortId(), nlmsghdr.nlmsg_pid); + assertTrue(msg instanceof RtNetlinkAddressMessage); addrMessageCount++; - final StructIfaddrMsg ifaMsg = Struct.parse(StructIfaddrMsg.class, response); - assertTrue( - "Non-IP address family: " + ifaMsg.family, - ifaMsg.family == AF_INET || ifaMsg.family == AF_INET6); + // From the query response we can see the RTM_NEWADDR messages representing for IPv4 + // and IPv6 loopback address: 127.0.0.1 and ::1. + final StructIfaddrMsg ifaMsg = ((RtNetlinkAddressMessage) msg).getIfaddrHeader(); + final InetAddress ipAddress = ((RtNetlinkAddressMessage) msg).getIpAddress(); + assertThat((int) ifaMsg.family).isAnyOf(AF_INET, AF_INET6); + assertTrue(ipAddress.isLoopbackAddress()); } assertTrue(addrMessageCount > 0); From a56b9497267e721ab87f4c8873cf004597419eb3 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 19 Jul 2023 12:37:16 +0900 Subject: [PATCH 739/777] Move ticksToMilliSeconds to NetlinkUtils. ticksToMilliSeconds is used to convert the clock ticks to milliseconds, move it to a common utils class, we can call this method to convert the rta_cacheinfo.rta_expires in user space as well to get when the default route will expire. Bug: 183601771 Test: atest NetworkStaticLibTests Change-Id: Iabd510fe290f835a8fe690d91921d5b706a23b56 --- .../net/module/util/netlink/NetlinkUtils.java | 16 ++++++++++++++++ .../module/util/netlink/StructNdaCacheInfo.java | 12 +----------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java index 73c88c778c..33bd36d875 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java +++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java @@ -33,6 +33,7 @@ import static android.system.OsConstants.SO_SNDTIMEO; import android.net.util.SocketUtils; import android.system.ErrnoException; import android.system.Os; +import android.system.OsConstants; import android.system.StructTimeval; import android.util.Log; @@ -291,5 +292,20 @@ public class NetlinkUtils { return Os.write(fd, bytes, offset, count); } + private static final long CLOCK_TICKS_PER_SECOND = Os.sysconf(OsConstants._SC_CLK_TCK); + + /** + * Convert the system time in clock ticks(clock_t type in times(), not in clock()) to + * milliseconds. times() clock_t ticks at the kernel's USER_HZ (100) while clock() clock_t + * ticks at CLOCKS_PER_SEC (1000000). + * + * See the NOTES on https://man7.org/linux/man-pages/man2/times.2.html for the difference + * of clock_t used in clock() and times(). + */ + public static long ticksToMilliSeconds(int intClockTicks) { + final long longClockTicks = intClockTicks & 0xffffffffL; + return (longClockTicks * 1000) / CLOCK_TICKS_PER_SECOND; + } + private NetlinkUtils() {} } diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructNdaCacheInfo.java b/staticlibs/device/com/android/net/module/util/netlink/StructNdaCacheInfo.java index 79d5ff4ad8..1f9bb7eca8 100644 --- a/staticlibs/device/com/android/net/module/util/netlink/StructNdaCacheInfo.java +++ b/staticlibs/device/com/android/net/module/util/netlink/StructNdaCacheInfo.java @@ -16,8 +16,7 @@ package com.android.net.module.util.netlink; -import android.system.Os; -import android.system.OsConstants; +import static com.android.net.module.util.netlink.NetlinkUtils.ticksToMilliSeconds; import java.nio.ByteBuffer; @@ -57,15 +56,6 @@ public class StructNdaCacheInfo { return struct; } - // TODO: investigate whether this can change during device runtime and - // decide what (if anything) should be done about that. - private static final long CLOCK_TICKS_PER_SECOND = Os.sysconf(OsConstants._SC_CLK_TCK); - - private static long ticksToMilliSeconds(int intClockTicks) { - final long longClockTicks = (long) intClockTicks & 0xffffffff; - return (longClockTicks * 1000) / CLOCK_TICKS_PER_SECOND; - } - /** * Explanatory notes, for reference. * From 2cd8b6900586836ea31353a0ebb2765faec59e2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Fri, 21 Jul 2023 22:37:18 +0000 Subject: [PATCH 740/777] BpfClassic - add three more macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Example use case: BPF_LOAD_SKB_PROTOCOL, BPF2_ACCEPT_IF_EQUAL(ETH_P_ARP), BPF2_REJECT_IF_NOT_EQUAL(ETH_P_IP), BPF_LOAD_IPV4_BE16(frag_off), BPF2_REJECT_IF_ANY_BITS_SET(IP_MF | IP_OFFMASK), BPF_ACCEPT, which is a sample program which accepts ARP plus non-fragmented IPv4. Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ibe6f9f7941f11bc7b767a092d3d108fa0291f360 --- .../native/bpf_headers/include/bpf/BpfClassic.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfClassic.h b/staticlibs/native/bpf_headers/include/bpf/BpfClassic.h index 9b38deec9f..dd0804c364 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfClassic.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfClassic.h @@ -22,11 +22,25 @@ // Reject the packet #define BPF_REJECT BPF_STMT(BPF_RET | BPF_K, 0) +// *TWO* instructions: compare and if not equal jump over the accept statement +#define BPF2_ACCEPT_IF_EQUAL(v) \ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, (v), 0, 1), \ + BPF_ACCEPT + // *TWO* instructions: compare and if equal jump over the reject statement #define BPF2_REJECT_IF_NOT_EQUAL(v) \ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, (v), 1, 0), \ BPF_REJECT +// *TWO* instructions: compare and if none of the bits are set jump over the reject statement +#define BPF2_REJECT_IF_ANY_BITS_SET(v) \ + BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, (v), 0, 1), \ + BPF_REJECT + +// loads skb->protocol +#define BPF_LOAD_SKB_PROTOCOL \ + BPF_STMT(BPF_LD | BPF_H | BPF_ABS, (__u32)SKF_AD_OFF + SKF_AD_PROTOCOL) + // 8-bit load relative to start of link layer (mac/ethernet) header. #define BPF_LOAD_MAC_RELATIVE_U8(ofs) \ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, (__u32)SKF_LL_OFF + (ofs)) From 72b0cd986a6f0fb0a2a6fc7628404082b8b02a7f Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Tue, 20 Jun 2023 18:49:13 +0900 Subject: [PATCH 741/777] Add RouteInformation option Struct. This structure is useful when building an RA with RIO for integration tests and verify the device's provisioning behavior, for example, check if devices in ULA networks can recover its IPv6 connectivity from receiving a normal RA after losing IPv6 default route (e.g. received RA with zero router lifetime). Bug: 183601771 Test: m Change-Id: I13b85000ea1633f56edc74e3d62b7a38b9a851bf --- .../util/structs/RouteInformationOption.java | 97 +++++++++++++++++++ .../module/util/NetworkStackConstants.java | 2 + 2 files changed, 99 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/structs/RouteInformationOption.java diff --git a/staticlibs/device/com/android/net/module/util/structs/RouteInformationOption.java b/staticlibs/device/com/android/net/module/util/structs/RouteInformationOption.java new file mode 100644 index 0000000000..49bafedbed --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/RouteInformationOption.java @@ -0,0 +1,97 @@ +/* + * 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 com.android.net.module.util.structs; + +import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_RIO; + +import android.net.IpPrefix; + +import androidx.annotation.NonNull; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * ICMPv6 route information option, as per https://tools.ietf.org/html/rfc4191. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Prefix Length |Resvd|Prf|Resvd| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Route Lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Prefix (Variable Length) | + * . . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class RouteInformationOption extends Struct { + public enum Preference { + HIGH((byte) 0x1), + MEDIUM((byte) 0x0), + LOW((byte) 0x3), + RESERVED((byte) 0x2); + + final byte mValue; + Preference(byte value) { + this.mValue = value; + } + } + + @Field(order = 0, type = Type.S8) + public final byte type; + @Field(order = 1, type = Type.S8) + public final byte length; // Length in 8-byte octets + @Field(order = 2, type = Type.U8) + public final short prefixLen; + @Field(order = 3, type = Type.S8) + public final byte prf; + @Field(order = 4, type = Type.U32) + public final long routeLifetime; + @Field(order = 5, type = Type.ByteArray, arraysize = 16) + public final byte[] prefix; + + RouteInformationOption(final byte type, final byte length, final short prefixLen, + final byte prf, final long routeLifetime, @NonNull final byte[] prefix) { + this.type = type; + this.length = length; + this.prefixLen = prefixLen; + this.prf = prf; + this.routeLifetime = routeLifetime; + this.prefix = prefix; + } + + /** + * Build a Route Information option from the required specified parameters. + */ + public static ByteBuffer build(final IpPrefix prefix, final Preference prf, + final long routeLifetime) { + // The prefix field is always assumed to have 16 bytes, but the number of leading + // bits in this prefix depends on IpPrefix#prefixLength, then we can simply set the + // option length to 3. + final RouteInformationOption option = new RouteInformationOption( + (byte) ICMPV6_ND_OPTION_RIO, (byte) 3 /* option length */, + (short) prefix.getPrefixLength(), (byte) (prf.mValue << 3), routeLifetime, + prefix.getRawAddress()); + return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN)); + } +} diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 6a6f5e10f5..24aabbc29d 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -140,6 +140,7 @@ public final class NetworkStackConstants { * ICMPv6 constants. * * See also: + * - https://tools.ietf.org/html/rfc4191 * - https://tools.ietf.org/html/rfc4443 * - https://tools.ietf.org/html/rfc4861 */ @@ -157,6 +158,7 @@ public final class NetworkStackConstants { public static final int ICMPV6_ND_OPTION_TLLA = 2; public static final int ICMPV6_ND_OPTION_PIO = 3; public static final int ICMPV6_ND_OPTION_MTU = 5; + public static final int ICMPV6_ND_OPTION_RIO = 24; public static final int ICMPV6_ND_OPTION_RDNSS = 25; public static final int ICMPV6_ND_OPTION_PREF64 = 38; From 48693a994aee7f570ae96ec04bf5ece3798c069e Mon Sep 17 00:00:00 2001 From: fqjc86 Date: Sun, 23 Jul 2023 00:28:01 +0530 Subject: [PATCH 742/777] Add DomainsUtils class to encode/decode domain names. Both encode and deocde methods support message compression which is described in RFC1035 section 4.1.4. We can leverage both methods in a follow-up CL to parse DHCPv4 option 119 and DNSSL RA option. This cl also adds maxLabelCount argument for DnsRecordParser#parseName to prevent the potential recursion from overflowing the stack. Bug: 189865016 Test: atest NetworkStaticLibTests Change-Id: I90101ecda64bfecb0233e80ea93c91c204fbf176 --- .../android/net/module/util/DomainUtils.java | 4 +-- .../net/module/util/DomainUtilsTest.java | 28 +++++++++++-------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/DomainUtils.java b/staticlibs/device/com/android/net/module/util/DomainUtils.java index 80e0b64bab..b327fd085c 100644 --- a/staticlibs/device/com/android/net/module/util/DomainUtils.java +++ b/staticlibs/device/com/android/net/module/util/DomainUtils.java @@ -123,7 +123,7 @@ public final class DomainUtils { * @return domain name(s) string array with space separated, or empty string if decode fails. */ @NonNull - public static String[] decode(@NonNull final ByteBuffer buffer, boolean compression) { + public static ArrayList decode(@NonNull final ByteBuffer buffer, boolean compression) { final ArrayList domainList = new ArrayList<>(); while (buffer.remaining() > 0) { try { @@ -138,6 +138,6 @@ public final class DomainUtils { break; } } - return domainList.toArray(new String[0]); + return domainList; } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DomainUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DomainUtilsTest.java index 606ed5fb7b..5eaf2add36 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DomainUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DomainUtilsTest.java @@ -30,6 +30,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; @RunWith(AndroidJUnit4.class) @SmallTest @@ -168,39 +171,40 @@ public class DomainUtilsTest { @Test public void testDecodeDomainNames() { + ArrayList suffixStringList; String suffixes = "06676F6F676C6503636F6D00" // google.com + "076578616D706C6503636F6D00" // example.com + "06676F6F676C6500"; // google - String[] expected = new String[] {"google.com", "example.com"}; + List expected = Arrays.asList("google.com", "example.com"); ByteBuffer buffer = ByteBuffer.wrap(HexEncoding.decode(suffixes)); - String[] suffixString = DomainUtils.decode(buffer, false /* compression */); - assertArrayEquals(expected, suffixString); + suffixStringList = DomainUtils.decode(buffer, false /* compression */); + assertEquals(expected, suffixStringList); // include suffix with invalid length: 64 suffixes = "06676F6F676C6503636F6D00" // google.com + "406578616D706C6503636F6D00" // example.com(length=64) + "06676F6F676C6500"; // google - expected = new String[] {"google.com"}; + expected = Arrays.asList("google.com"); buffer = ByteBuffer.wrap(HexEncoding.decode(suffixes)); - suffixString = DomainUtils.decode(buffer, false /* compression */); - assertArrayEquals(expected, suffixString); + suffixStringList = DomainUtils.decode(buffer, false /* compression */); + assertEquals(expected, suffixStringList); // include suffix with invalid length: 0 suffixes = "06676F6F676C6503636F6D00" // google.com + "076578616D706C6503636F6D00" // example.com + "00676F6F676C6500"; // google(length=0) - expected = new String[] {"google.com", "example.com"}; + expected = Arrays.asList("google.com", "example.com"); buffer = ByteBuffer.wrap(HexEncoding.decode(suffixes)); - suffixString = DomainUtils.decode(buffer, false /* compression */); - assertArrayEquals(expected, suffixString); + suffixStringList = DomainUtils.decode(buffer, false /* compression */); + assertEquals(expected, suffixStringList); suffixes = "076578616D706C6504636F727006676F6F676C6503636F6D00" // example.corp.google.com + "C008" // corp.google.com + "C00D"; // google.com - expected = new String[] {"example.corp.google.com", "corp.google.com", "google.com"}; + expected = Arrays.asList("example.corp.google.com", "corp.google.com", "google.com"); buffer = ByteBuffer.wrap(HexEncoding.decode(suffixes)); - suffixString = DomainUtils.decode(buffer, true /* compression */); - assertArrayEquals(expected, suffixString); + suffixStringList = DomainUtils.decode(buffer, true /* compression */); + assertEquals(expected, suffixStringList); } } From 5e4900dbbe4dc5e7b4088b335f3dd062cccbdd97 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 26 Jul 2023 13:36:02 +0900 Subject: [PATCH 743/777] Add an annotation for @SkipMainlinePresubmit This will typically be used in mainline-presubmit TEST_MAPPING configuration to exclude some tests. This is necessary as some tests are flaky in mainline configurations (when running on older devices), and they need to be disabled to meet SLO requirements, but they are not flaky on presubmit using the latest platform builds. Test: m Change-Id: Ia532d6d3f9833ddec613d79c0eb517d20a1c529a --- .../testutils/SkipMainlinePresubmit.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 staticlibs/testutils/hostdevice/com/android/testutils/SkipMainlinePresubmit.kt diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/SkipMainlinePresubmit.kt b/staticlibs/testutils/hostdevice/com/android/testutils/SkipMainlinePresubmit.kt new file mode 100644 index 0000000000..5952365104 --- /dev/null +++ b/staticlibs/testutils/hostdevice/com/android/testutils/SkipMainlinePresubmit.kt @@ -0,0 +1,25 @@ +/* + * 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 com.android.testutils + +/** + * Skip the test in presubmit runs for the reason specified in [reason]. + * + * This annotation is typically used to document limitations that prevent a test from being + * executed in presubmit on older builds. + */ +annotation class SkipMainlinePresubmit(val reason: String) From af464eb494a85c1a749251afeb07c50dd22f39a7 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 26 Jul 2023 14:41:33 +0800 Subject: [PATCH 744/777] Make SkipPresubmit annotation visible by HostsideVpnTests Test: TH Bug: 291701394 Change-Id: I93d72a809b2779deec3c8182c5efed6d38393ab8 --- staticlibs/testutils/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp index be4ccfed03..d88cb0b425 100644 --- a/staticlibs/testutils/Android.bp +++ b/staticlibs/testutils/Android.bp @@ -57,6 +57,7 @@ java_library { visibility: [ "//frameworks/libs/net/common/tests:__subpackages__", "//frameworks/libs/net/client-libs/tests:__subpackages__", + "//packages/modules/Connectivity/tests/cts/hostside", ], // There are downstream branches using an old version of Kotlin // that used to reserve the right to make breaking changes to the From 9e9bc973171af2d5d9fe7ed78b5c7de40901019e Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 27 Jul 2023 12:09:41 +0900 Subject: [PATCH 745/777] Remove truth lib denpendency temporarily due to code coverage regression. Bug: 291341416 Test: atest NetworkStaticLibTests Change-Id: Id8fac2ff76dab174761fbc48d0599bcce81918ed --- staticlibs/tests/unit/Android.bp | 1 - .../android/net/module/util/netlink/NetlinkUtilsTest.java | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp index 8c49954e06..40371e63b2 100644 --- a/staticlibs/tests/unit/Android.bp +++ b/staticlibs/tests/unit/Android.bp @@ -22,7 +22,6 @@ android_library { "net-utils-device-common-bpf", "net-utils-device-common-ip", "net-utils-device-common-wear", - "truth", ], libs: [ "android.test.runner", diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java index dac5911a77..3a72dd1ba6 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java @@ -26,8 +26,6 @@ import static com.android.net.module.util.netlink.NetlinkUtils.DEFAULT_RECV_BUFS import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; -import static com.google.common.truth.Truth.assertThat; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -193,7 +191,9 @@ public class NetlinkUtilsTest { // and IPv6 loopback address: 127.0.0.1 and ::1. final StructIfaddrMsg ifaMsg = ((RtNetlinkAddressMessage) msg).getIfaddrHeader(); final InetAddress ipAddress = ((RtNetlinkAddressMessage) msg).getIpAddress(); - assertThat((int) ifaMsg.family).isAnyOf(AF_INET, AF_INET6); + assertTrue( + "Non-IP address family: " + ifaMsg.family, + ifaMsg.family == AF_INET || ifaMsg.family == AF_INET6); assertTrue(ipAddress.isLoopbackAddress()); } From 80dbd06f649eae9d7be036d74d7571533d9f9e54 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 27 Jul 2023 14:51:53 +0900 Subject: [PATCH 746/777] Add Ipv6PktInfo (in6_pktinfo) struct. in6_pktinfo structure specifies the source IPv6 address and interface for an outgoing packet(used with UDP or RAW socket), we can specify the IPV6_PKTINFO ancillary data on sendmsg() with this structure to set the source address (e.g. a global IPv6 address). Bug: 293393743 Test: TH Change-Id: I2bd8ea6fcdb7398db9b3a54243c81ca27e832e45 --- .../net/module/util/structs/Ipv6PktInfo.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/structs/Ipv6PktInfo.java diff --git a/staticlibs/device/com/android/net/module/util/structs/Ipv6PktInfo.java b/staticlibs/device/com/android/net/module/util/structs/Ipv6PktInfo.java new file mode 100644 index 0000000000..0dccb72723 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/Ipv6PktInfo.java @@ -0,0 +1,42 @@ +/* + * 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 com.android.net.module.util.structs; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.Inet6Address; + +/** + * structure in6_pktinfo + * + * see also: + * + * include/uapi/linux/ipv6.h + */ +public class Ipv6PktInfo extends Struct { + @Field(order = 0, type = Type.Ipv6Address) + public final Inet6Address addr; // IPv6 source or destination address + @Field(order = 1, type = Type.S32) + public final int ifindex; // interface index + + public Ipv6PktInfo(final Inet6Address addr, final int ifindex) { + this.addr = addr; + this.ifindex = ifindex; + } +} From 9835a4eae0e37be4e11a8bb9b18286879f58d37c Mon Sep 17 00:00:00 2001 From: chiachangwang Date: Mon, 31 Jul 2023 14:01:24 +0000 Subject: [PATCH 747/777] Add resolvePkgPrefix() method This is a no-op refactor change to create resolvePkgPrefix() helper method to prevent code duplication for the follow up commit. Bug: 291870956 Test: atest NetworkStaticLibTests Change-Id: I8deea97acdb793dfa076ce55f7f2c3eb0b224461 --- .../net/module/util/DeviceConfigUtils.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index 138c1e5419..e5c5d0d587 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -224,14 +224,7 @@ public final class DeviceConfigUtils { // If that fails retry by appending "go.tethering" instead private static long resolveTetheringModuleVersion(@NonNull Context context) throws PackageManager.NameNotFoundException { - final String connResourcesPackage = getConnectivityResourcesPackageName(context); - final int pkgPrefixLen = connResourcesPackage.indexOf("connectivity"); - if (pkgPrefixLen < 0) { - throw new IllegalStateException( - "Invalid connectivity resources package: " + connResourcesPackage); - } - - final String pkgPrefix = connResourcesPackage.substring(0, pkgPrefixLen); + final String pkgPrefix = resolvePkgPrefix(context); final PackageManager packageManager = context.getPackageManager(); try { return packageManager.getPackageInfo(pkgPrefix + "tethering", @@ -245,6 +238,17 @@ public final class DeviceConfigUtils { PackageManager.MATCH_APEX).getLongVersionCode(); } + private static String resolvePkgPrefix(Context context) { + final String connResourcesPackage = getConnectivityResourcesPackageName(context); + final int pkgPrefixLen = connResourcesPackage.indexOf("connectivity"); + if (pkgPrefixLen < 0) { + throw new IllegalStateException( + "Invalid connectivity resources package: " + connResourcesPackage); + } + + return connResourcesPackage.substring(0, pkgPrefixLen); + } + private static volatile long sModuleVersion = -1; private static long getTetheringModuleVersion(@NonNull Context context) { if (sModuleVersion >= 0) return sModuleVersion; From 837837e0fefe7ec0fab4dd42f4fc6a3fc79fa5cc Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 1 Aug 2023 08:48:26 +0000 Subject: [PATCH 748/777] Use requestNetwork for mobile data, not a callback On devices that do not have always active mobile data, it needs to be requested for onAvailable to be called. Change-Id: Ic814684bcd06389c013a6e6636487d9b47627901 Test: TH --- .../testutils/connectivitypreparer/ConnectivityCheckTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitypreparer/ConnectivityCheckTest.kt b/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitypreparer/ConnectivityCheckTest.kt index 6bcb8fc182..f1f0975457 100644 --- a/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitypreparer/ConnectivityCheckTest.kt +++ b/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitypreparer/ConnectivityCheckTest.kt @@ -72,7 +72,7 @@ class ConnectivityCheckTest { val cb = TestableNetworkCallback() val cm = context.getSystemService(ConnectivityManager::class.java) ?: fail("Could not get ConnectivityManager") - cm.registerNetworkCallback( + cm.requestNetwork( NetworkRequest.Builder() .addTransportType(TRANSPORT_CELLULAR) .addCapability(NET_CAPABILITY_INTERNET).build(), cb) From 1637730010250c227dfa57d1abbd61ca8792ee17 Mon Sep 17 00:00:00 2001 From: chiachangwang Date: Mon, 31 Jul 2023 14:06:28 +0000 Subject: [PATCH 749/777] Add isFeatureSupported and isTetheringFeatureForceDisabled methods Add isFeatureSupported helper method to check whether a specific feature is supported. This is useful when a specific module version is required on a cross module feature, e.g. a connectivity feauture requires to work with a older networkstack module. This commit also adds isTetheringFeatureForceDisabled() method as a method that refers to DeviceConfig which can be controlled to explicitly disabled. Bug: 291870956 Test: atest FrameworksNetTests NetworkStaticLibTests Change-Id: I511d00663e2378c36b4ca017db4b88d88f650852 --- staticlibs/Android.bp | 1 + .../net/module/util/DeviceConfigUtils.java | 84 ++++++++++++++++++- .../net/module/util/FeatureVersions.java | 34 ++++++++ .../module/util/DeviceConfigUtilsTest.java | 84 +++++++++++++++++++ 4 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 staticlibs/device/com/android/net/module/util/FeatureVersions.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index e1b5601db2..d3e68b753e 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -41,6 +41,7 @@ java_library { "device/com/android/net/module/util/PacketReader.java", "device/com/android/net/module/util/SharedLog.java", "device/com/android/net/module/util/SocketUtils.java", + "device/com/android/net/module/util/FeatureVersions.java", // This library is used by system modules, for which the system health impact of Kotlin // has not yet been evaluated. Annotations may need jarjar'ing. // "src_devicecommon/**/*.kt", diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index e5c5d0d587..bea227d9ad 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -17,6 +17,12 @@ package com.android.net.module.util; import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; +import static android.provider.DeviceConfig.NAMESPACE_TETHERING; + +import static com.android.net.module.util.FeatureVersions.CONNECTIVITY_MODULE_ID; +import static com.android.net.module.util.FeatureVersions.MODULE_MASK; +import static com.android.net.module.util.FeatureVersions.NETWORK_STACK_MODULE_ID; +import static com.android.net.module.util.FeatureVersions.VERSION_MASK; import android.content.Context; import android.content.Intent; @@ -53,12 +59,14 @@ public final class DeviceConfigUtils { "com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK"; private static final String CONNECTIVITY_RES_PKG_DIR = "/apex/" + TETHERING_MODULE_NAME + "/"; - private static final long DEFAULT_PACKAGE_VERSION = 1000; + @VisibleForTesting + public static final long DEFAULT_PACKAGE_VERSION = 1000; @VisibleForTesting public static void resetPackageVersionCacheForTest() { sPackageVersion = -1; sModuleVersion = -1; + sNetworkStackModuleVersion = -1; } private static volatile long sPackageVersion = -1; @@ -264,6 +272,80 @@ public final class DeviceConfigUtils { return sModuleVersion; } + private static volatile long sNetworkStackModuleVersion = -1; + + /** + * Get networkstack module version. + */ + @VisibleForTesting + static long getNetworkStackModuleVersion(@NonNull Context context) { + if (sNetworkStackModuleVersion >= 0) return sNetworkStackModuleVersion; + + try { + sNetworkStackModuleVersion = resolveNetworkStackModuleVersion(context); + } catch (PackageManager.NameNotFoundException e) { + Log.wtf(TAG, "Failed to resolve networkstack module version: " + e); + return DEFAULT_PACKAGE_VERSION; + } + return sNetworkStackModuleVersion; + } + + private static long resolveNetworkStackModuleVersion(@NonNull Context context) + throws PackageManager.NameNotFoundException { + // TODO(b/293975546): Strictly speaking this is the prefix for connectivity and not + // network stack. In practice, it's the same. Read the prefix from network stack instead. + final String pkgPrefix = resolvePkgPrefix(context); + final PackageManager packageManager = context.getPackageManager(); + try { + return packageManager.getPackageInfo(pkgPrefix + "networkstack", + PackageManager.MATCH_SYSTEM_ONLY).getLongVersionCode(); + } catch (PackageManager.NameNotFoundException e) { + Log.d(TAG, "Device is using go or non-mainline modules"); + // fall through + } + + return packageManager.getPackageInfo(pkgPrefix + "go.networkstack", + PackageManager.MATCH_ALL).getLongVersionCode(); + } + + /** + * Check whether one specific feature is supported from the feature Id. The feature Id is + * composed by a module package Id and version Id from {@link FeatureVersions}. + * + * This is useful when a feature required minimal module version supported and cannot function + * well with a standalone newer module. + * @param context The global context information about an app environment. + * @param featureId The feature id that contains required module id and minimal module version + * @return true if this feature is supported, or false if not supported. + **/ + public static boolean isFeatureSupported(@NonNull Context context, long featureId) { + final long moduleVersion; + final long moduleId = featureId & MODULE_MASK; + if (moduleId == CONNECTIVITY_MODULE_ID) { + moduleVersion = getTetheringModuleVersion(context); + } else if (moduleId == NETWORK_STACK_MODULE_ID) { + moduleVersion = getNetworkStackModuleVersion(context); + } else { + throw new IllegalArgumentException("Unknown module " + moduleId); + } + // Support by default if no module version is available. + return moduleVersion == DEFAULT_PACKAGE_VERSION + || moduleVersion >= (featureId & VERSION_MASK); + } + + /** + * Check whether one specific experimental feature in tethering module from {@link DeviceConfig} + * is disabled by setting a non-zero value in the property. + * + * @param name The name of the property to look up. + * @return true if this feature is force disabled, or false if not disabled. + */ + public static boolean isTetheringFeatureForceDisabled(String name) { + final int propertyVersion = getDeviceConfigPropertyInt(NAMESPACE_TETHERING, name, + 0 /* default value */); + return propertyVersion != 0; + } + /** * Gets boolean config from resources. */ diff --git a/staticlibs/device/com/android/net/module/util/FeatureVersions.java b/staticlibs/device/com/android/net/module/util/FeatureVersions.java new file mode 100644 index 0000000000..4986a58813 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/FeatureVersions.java @@ -0,0 +1,34 @@ +/* + * 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 com.android.net.module.util; + +/** + * Class to centralize feature version control that requires a specific module or a specific + * module version. + * @hide + */ +public class FeatureVersions { + public static final long MODULE_MASK = 0xFF00_000000000L; + public static final long VERSION_MASK = 0x0000_FFFFFFFFFL; + public static final long CONNECTIVITY_MODULE_ID = 0x0100_000000000L; + public static final long NETWORK_STACK_MODULE_ID = 0x0200_000000000L; + // CLAT_ADDRESS_TRANSLATE is a feature of the network stack, which doesn't throw when system + // try to add a NAT-T keepalive packet filter with v6 address, introduced in version + // M-2023-Sept on July 3rd, 2023. + public static final long FEATURE_CLAT_ADDRESS_TRANSLATE = + NETWORK_STACK_MODULE_ID + 340900000L; +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java index 328c39a4aa..7946244da1 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -17,12 +17,16 @@ package com.android.net.module.util; import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; +import static android.provider.DeviceConfig.NAMESPACE_TETHERING; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; +import static com.android.net.module.util.FeatureVersions.CONNECTIVITY_MODULE_ID; +import static com.android.net.module.util.FeatureVersions.NETWORK_STACK_MODULE_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.anyInt; @@ -84,6 +88,8 @@ public class DeviceConfigUtilsTest { private static final String TEST_GO_APEX_PACKAGE_NAME = "com.prefix.android.go.tethering"; private static final String TEST_CONNRES_PACKAGE_NAME = "com.prefix.android.connectivity.resources"; + private static final String TEST_NETWORKSTACK_NAME = "com.prefix.android.networkstack"; + private static final String TEST_GO_NETWORKSTACK_NAME = "com.prefix.android.go.networkstack"; private final PackageInfo mPackageInfo = new PackageInfo(); private final PackageInfo mApexPackageInfo = new PackageInfo(); private MockitoSession mSession; @@ -346,4 +352,82 @@ public class DeviceConfigUtilsTest { doThrow(new Resources.NotFoundException()).when(mResources).getInteger(someResId); assertEquals(2098, DeviceConfigUtils.getResIntegerConfig(mContext, someResId, 2098)); } + + @Test + public void testGetNetworkStackModuleVersionCaching() throws Exception { + final PackageInfo networkStackPackageInfo = new PackageInfo(); + networkStackPackageInfo.setLongVersionCode(TEST_PACKAGE_VERSION); + doReturn(networkStackPackageInfo).when(mPm).getPackageInfo( + eq(TEST_NETWORKSTACK_NAME), anyInt()); + assertEquals(TEST_PACKAGE_VERSION, + DeviceConfigUtils.getNetworkStackModuleVersion(mContext)); + + assertEquals(TEST_PACKAGE_VERSION, + DeviceConfigUtils.getNetworkStackModuleVersion(mContext)); + // Package info is only queried once + verify(mPm, times(1)).getPackageInfo(anyString(), anyInt()); + verify(mContext, never()).getPackageName(); + } + + @Test + public void testGetNetworkStackModuleVersionOnNonMainline() { + assertEquals(DeviceConfigUtils.DEFAULT_PACKAGE_VERSION, + DeviceConfigUtils.getNetworkStackModuleVersion(mContext)); + } + + @Test + public void testGetNetworkStackModuleVersion() throws Exception { + final PackageInfo networkStackPackageInfo = new PackageInfo(); + final PackageInfo goNetworkStackPackageInfo = new PackageInfo(); + networkStackPackageInfo.setLongVersionCode(TEST_PACKAGE_VERSION); + goNetworkStackPackageInfo.setLongVersionCode(TEST_PACKAGE_VERSION + 1); + doReturn(goNetworkStackPackageInfo).when(mPm).getPackageInfo( + eq(TEST_NETWORKSTACK_NAME), anyInt()); + // Verify the returned value is go module version. + assertEquals(TEST_PACKAGE_VERSION + 1, + DeviceConfigUtils.getNetworkStackModuleVersion(mContext)); + } + + @Test + public void testIsFeatureSupported_networkStackFeature() throws Exception { + // Supported for DEFAULT_PACKAGE_VERSION + assertTrue(DeviceConfigUtils.isFeatureSupported( + mContext, TEST_PACKAGE_VERSION + NETWORK_STACK_MODULE_ID)); + + final PackageInfo networkStackPackageInfo = new PackageInfo(); + networkStackPackageInfo.setLongVersionCode(TEST_PACKAGE_VERSION); + doReturn(networkStackPackageInfo).when(mPm).getPackageInfo( + eq(TEST_NETWORKSTACK_NAME), anyInt()); + + assertTrue(DeviceConfigUtils.isFeatureSupported( + mContext, TEST_PACKAGE_VERSION + NETWORK_STACK_MODULE_ID)); + assertFalse(DeviceConfigUtils.isFeatureSupported( + mContext, TEST_PACKAGE_VERSION + NETWORK_STACK_MODULE_ID + 1)); + } + + @Test + public void testIsFeatureSupported_tetheringFeature() throws Exception { + assertTrue(DeviceConfigUtils.isFeatureSupported( + mContext, TEST_PACKAGE_VERSION + CONNECTIVITY_MODULE_ID)); + // Return false because feature requires a future version. + assertFalse(DeviceConfigUtils.isFeatureSupported( + mContext, 889900000L + CONNECTIVITY_MODULE_ID)); + } + + @Test + public void testIsFeatureSupported_illegalModule() throws Exception { + assertThrows(IllegalArgumentException.class, + () -> DeviceConfigUtils.isFeatureSupported(mContext, TEST_PACKAGE_VERSION)); + } + + @Test + public void testIsTetheringFeatureForceDisabled() throws Exception { + doReturn("0").when(() -> DeviceConfig.getProperty( + eq(NAMESPACE_TETHERING), eq(TEST_EXPERIMENT_FLAG))); + assertFalse(DeviceConfigUtils.isTetheringFeatureForceDisabled(TEST_EXPERIMENT_FLAG)); + + doReturn(TEST_FLAG_VALUE_STRING).when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_TETHERING), eq(TEST_EXPERIMENT_FLAG))); + assertTrue(DeviceConfigUtils.isTetheringFeatureForceDisabled(TEST_EXPERIMENT_FLAG)); + } } From 783d4fb4f63108ae03c10b67b44cf60b2348d6be Mon Sep 17 00:00:00 2001 From: Yuyang Huang Date: Thu, 3 Aug 2023 15:37:28 +0900 Subject: [PATCH 750/777] Add helpers method to SharedLog Bug: 294326360 Test: atest FrameworksNetTests Change-Id: Ib8ba3e9a556a70de28813465396c6609b7c22333 --- .../android/net/module/util/SharedLog.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/staticlibs/device/com/android/net/module/util/SharedLog.java b/staticlibs/device/com/android/net/module/util/SharedLog.java index 17b061e6ed..6b12c80d3a 100644 --- a/staticlibs/device/com/android/net/module/util/SharedLog.java +++ b/staticlibs/device/com/android/net/module/util/SharedLog.java @@ -46,6 +46,8 @@ public class SharedLog { ERROR, MARK, WARN, + VERBOSE, + TERRIBLE, } private final LocalLog mLocalLog; @@ -159,6 +161,41 @@ public class SharedLog { Log.w(mTag, record(Category.WARN, msg)); } + /** + * Log a verbose message. + * + *

The log entry will be also added to the system log. + */ + public void v(String msg) { + Log.v(mTag, record(Category.VERBOSE, msg)); + } + + /** + * Log a terrible failure message. + * + *

The log entry will be also added to the system log and will trigger system reporting + * for terrible failures. + */ + public void wtf(String msg) { + Log.wtf(mTag, record(Category.TERRIBLE, msg)); + } + + /** + * Log a terrible failure due to an exception, with the exception stacktrace if provided. + * + *

The error and exception message appear in the shared log, but the stacktrace is only + * logged in general log output (logcat). The log entry will be also added to the system log + * and will trigger system reporting for terrible failures. + */ + public void wtf(@NonNull String msg, @Nullable Throwable exception) { + if (exception == null) { + e(msg); + return; + } + Log.wtf(mTag, record(Category.TERRIBLE, msg + ": " + exception.getMessage()), exception); + } + + ////// // Methods that only log an entry (and do NOT emit to the system log). ////// From d91c89ba51b68e0121a122e7fb63754d958cb33d Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 7 Aug 2023 22:25:17 -0700 Subject: [PATCH 751/777] Fix kotlin nullable errors in net-test-utils and NetworkStaticLibTests Fix kotlin nullable errors that were exposed by setting the retention of android.annotation.NonNull and android.annotation.Nullable to class retention. Bug: 294110802 Test: builds Change-Id: I2a2c91188b64619fca190a9bd7812d32f9610abd --- .../src/com/android/net/module/util/CollectionUtilsTest.kt | 3 --- .../testutils/devicetests/com/android/testutils/FakeDns.kt | 4 ++-- .../devicetests/com/android/testutils/PacketBridge.kt | 4 ++-- .../devicetests/com/android/testutils/TestNetworkTracker.kt | 4 ++-- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt index 9fb025b353..e23f99912e 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt @@ -63,9 +63,6 @@ class CollectionUtilsTest { assertEquals(0, CollectionUtils.indexOfSubArray(haystack, byteArrayOf())) assertEquals(-1, CollectionUtils.indexOfSubArray(byteArrayOf(), byteArrayOf(3, 2))) assertEquals(0, CollectionUtils.indexOfSubArray(byteArrayOf(), byteArrayOf())) - assertThrows(NullPointerException::class.java) { - CollectionUtils.indexOfSubArray(haystack, null) - } } @Test diff --git a/staticlibs/testutils/devicetests/com/android/testutils/FakeDns.kt b/staticlibs/testutils/devicetests/com/android/testutils/FakeDns.kt index 825d74878e..1f82a35dc5 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/FakeDns.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/FakeDns.kt @@ -81,9 +81,9 @@ class FakeDns(val mockResolver: DnsResolver) { var type = if (posType != -1) it.arguments[posType] as Int else TYPE_UNSPECIFIED val answer = getAnswer(hostname, type) - if (!answer?.addresses.isNullOrEmpty()) { + if (answer != null && !answer.addresses.isNullOrEmpty()) { Handler(Looper.getMainLooper()).post({ executor.execute({ - callback.onAnswer(answer?.addresses, 0); }) }) + callback.onAnswer(answer.addresses, 0); }) }) } } diff --git a/staticlibs/testutils/devicetests/com/android/testutils/PacketBridge.kt b/staticlibs/testutils/devicetests/com/android/testutils/PacketBridge.kt index da3508dec2..d50f78a178 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/PacketBridge.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/PacketBridge.kt @@ -48,8 +48,8 @@ class PacketBridge( private val natMap = NatMap() private val binder = Binder() - private val cm = context.getSystemService(ConnectivityManager::class.java) - private val tnm = context.getSystemService(TestNetworkManager::class.java) + private val cm = context.getSystemService(ConnectivityManager::class.java)!! + private val tnm = context.getSystemService(TestNetworkManager::class.java)!! // Create test networks. private val internalIface = tnm.createTunInterface(listOf(internalAddr)) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt index b743b6c922..84fb47bc6a 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestNetworkTracker.kt @@ -91,7 +91,7 @@ private fun initTestNetwork( lp: LinkProperties?, setupTimeoutMs: Long = 10_000L ): TestNetworkTracker { - val tnm = context.getSystemService(TestNetworkManager::class.java) + val tnm = context.getSystemService(TestNetworkManager::class.java)!! val iface = if (isAtLeastS()) tnm.createTunInterface(linkAddrs) else tnm.createTunInterface(linkAddrs.toTypedArray()) val lpWithIface = if (lp == null) null else LinkProperties(lp).apply { @@ -112,7 +112,7 @@ class TestNetworkTracker internal constructor( val lp: LinkProperties?, setupTimeoutMs: Long ) : TestableNetworkCallback.HasNetwork { - private val cm = context.getSystemService(ConnectivityManager::class.java) + private val cm = context.getSystemService(ConnectivityManager::class.java)!! private val binder = Binder() private val networkCallback: NetworkCallback From a95710dd60befcbc2af875c9aba5ff64d3a6dd0c Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 9 Aug 2023 18:08:10 +0900 Subject: [PATCH 752/777] Move RFC7421_PREFIX_LENGTH from NetworkConstants to NetworkStackConstants. NetworkStack module imports RFC7421_PREFIX_LENGTH constant from filegroup services-connectivity-shared-srcs, to get rid of this dependency, move the constants to NetworkStackConstants. Bug: 290885904 Test: TH Change-Id: I0e8f068856c8843121273e0b598097d82b8465d5 --- .../com/android/net/module/util/NetworkStackConstants.java | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 94f355a903..9149160596 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -131,6 +131,7 @@ public final class NetworkStackConstants { public static final int IPV6_DST_ADDR_OFFSET = 24; public static final int IPV6_MIN_MTU = 1280; public static final int IPV6_FRAGMENT_HEADER_LEN = 8; + public static final int RFC7421_PREFIX_LENGTH = 64; // getSockOpt() for v6 MTU public static final int IPV6_MTU = 24; public static final Inet6Address IPV6_ADDR_ALL_NODES_MULTICAST = From 533af6d72df29114c88b2fe16b01771da1d0d70d Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 9 Aug 2023 05:20:21 -0700 Subject: [PATCH 753/777] TrackRecord: add a method to return callbacks since last poll This change adds a backtrace() method which returns a list of events that were received since the last time a user called poll() on a ReadHead. This is particularly useful for logging observed events while a poll was in progress that did not end up matching an event. Test: atest EthernetManagerTest Change-Id: If019cf9eb5e3e9268c5e6b74edbd8f49959cc71c --- .../android/net/module/util/TrackRecord.kt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/staticlibs/testutils/hostdevice/com/android/net/module/util/TrackRecord.kt b/staticlibs/testutils/hostdevice/com/android/net/module/util/TrackRecord.kt index efd77d1b3b..f24e4f184d 100644 --- a/staticlibs/testutils/hostdevice/com/android/net/module/util/TrackRecord.kt +++ b/staticlibs/testutils/hostdevice/com/android/net/module/util/TrackRecord.kt @@ -213,6 +213,9 @@ class ArrayTrackRecord : TrackRecord { private val slock = StampedLock() private var readHead = 0 + // A special mark used to track the start of the last poll() operation. + private var pollMark = 0 + /** * @return the current value of the mark. */ @@ -223,6 +226,7 @@ class ArrayTrackRecord : TrackRecord { val stamp = slock.tryWriteLock() if (0L == stamp) concurrentAccessDetected() readHead = v + pollMark = v slock.unlockWrite(stamp) } @@ -261,6 +265,7 @@ class ArrayTrackRecord : TrackRecord { fun poll(timeoutMs: Long, predicate: (E) -> Boolean = { true }): E? { val stamp = slock.tryWriteLock() if (0L == stamp) concurrentAccessDetected() + pollMark = readHead try { lock.withLock { val index = pollForIndexReadLocked(timeoutMs, readHead, predicate) @@ -272,6 +277,25 @@ class ArrayTrackRecord : TrackRecord { } } + /** + * Returns a list of events that were observed since the last time poll() was called on this + * ReadHead. + * + * @return list of events since poll() was called. + */ + fun backtrace(): List { + val stamp = slock.tryReadLock() + if (0L == stamp) concurrentAccessDetected() + + try { + lock.withLock { + return ArrayList(subList(pollMark, mark)) + } + } finally { + slock.unlockRead(stamp) + } + } + /** * Returns the first element after the mark or null. This never blocks. * From a6e8a281a4cb314b904b6be577a7189809ada467 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 10 Aug 2023 16:20:38 +0900 Subject: [PATCH 754/777] Fix DevSdkIgnoreRule for Q- UnboundedSdkLevel stopped working on Q as it now depends on Set.of, which is an R+ API. Arguably this should be fixed as its minSdk is still 29, but long-term UnboundedSdkLevel may drop Q support as modules now only need to support R+. Avoid using UnboundedSdkLevel on Q- in DevSdkIgnoreRule: this avoids the above problem, and also makes it compatible with even older builds, which may happen in GTS. Bug: 292868272 Test: all tests using this rule Change-Id: I5e1559d841398a6c6763283f32c9f766a3661e21 --- .../com/android/testutils/DevSdkIgnoreRule.kt | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt index 21e84dafd5..35f22b9e58 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRule.kt @@ -19,11 +19,11 @@ package com.android.testutils import android.os.Build import androidx.test.InstrumentationRegistry import com.android.modules.utils.build.UnboundedSdkLevel +import java.util.regex.Pattern import org.junit.Assume.assumeTrue import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement -import java.util.regex.Pattern @Deprecated("Use Build.VERSION_CODES", ReplaceWith("Build.VERSION_CODES.S_V2")) const val SC_V2 = Build.VERSION_CODES.S_V2 @@ -32,8 +32,22 @@ private val MAX_TARGET_SDK_ANNOTATION_RE = Pattern.compile("MaxTargetSdk([0-9]+) private val targetSdk = InstrumentationRegistry.getContext().applicationInfo.targetSdkVersion private fun isDevSdkInRange(minExclusive: String?, maxInclusive: String?): Boolean { - return (minExclusive == null || !UnboundedSdkLevel.isAtMost(minExclusive)) && - (maxInclusive == null || UnboundedSdkLevel.isAtMost(maxInclusive)) + return (minExclusive == null || !isAtMost(minExclusive)) && + (maxInclusive == null || isAtMost(maxInclusive)) +} + +private fun isAtMost(sdkVersionOrCodename: String): Boolean { + // UnboundedSdkLevel does not support builds < Q, and may stop supporting Q as well since it + // is intended for mainline modules that are now R+. + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) { + // Assume that any codename passed as argument from current code is a more recent build than + // Q: this util did not exist before Q, and codenames are only used before the corresponding + // build is finalized. This util could list 28 older codenames to check against (as per + // ro.build.version.known_codenames in more recent builds), but this does not seem valuable. + val intVersion = sdkVersionOrCodename.toIntOrNull() ?: return true + return Build.VERSION.SDK_INT <= intVersion + } + return UnboundedSdkLevel.isAtMost(sdkVersionOrCodename) } /** From 79f5dc6b4ddfd4aad127ee6a726120301f76c44d Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 11 Aug 2023 15:53:49 +0900 Subject: [PATCH 755/777] Remove the VisibleForTesting annotation on IaPrefixOption constructor. Fix AndroidLint warning in aosp/2691418. Bug: 260934173 Test: TH Change-Id: Idfaff1342931d6c3ebfd3aa2fea02ab3ed5bb6f1 --- .../com/android/net/module/util/structs/IaPrefixOption.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java b/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java index f0e4409850..59d655ca8b 100644 --- a/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java +++ b/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java @@ -18,8 +18,6 @@ package com.android.net.module.util.structs; import static com.android.net.module.util.NetworkStackConstants.DHCP6_OPTION_IAPREFIX; -import androidx.annotation.VisibleForTesting; - import com.android.net.module.util.Struct; import com.android.net.module.util.Struct.Field; import com.android.net.module.util.Struct.Type; @@ -69,7 +67,6 @@ public class IaPrefixOption extends Struct { @Field(order = 5, type = Type.ByteArray, arraysize = 16) public final byte[] prefix; - @VisibleForTesting public IaPrefixOption(final short code, final short length, final long preferred, final long valid, final byte prefixLen, final byte[] prefix) { this.code = code; From a3f942de444ead57940a1855b0571c031122d5cf Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Mon, 7 Aug 2023 12:35:58 +0900 Subject: [PATCH 756/777] Add IA Address option struct. Bug: 293393743 Test: m Change-Id: Id4ab164579a95b87fa8a8d1d00447c6a3bd394d5 --- .../module/util/structs/IaAddressOption.java | 84 +++++++++++++++++++ .../module/util/NetworkStackConstants.java | 1 + 2 files changed, 85 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/structs/IaAddressOption.java diff --git a/staticlibs/device/com/android/net/module/util/structs/IaAddressOption.java b/staticlibs/device/com/android/net/module/util/structs/IaAddressOption.java new file mode 100644 index 0000000000..575a1f367f --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/structs/IaAddressOption.java @@ -0,0 +1,84 @@ +/* + * 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 com.android.net.module.util.structs; + +import static com.android.net.module.util.NetworkStackConstants.DHCP6_OPTION_IA_ADDR; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +import java.net.Inet6Address; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * DHCPv6 IA Address option. + * https://tools.ietf.org/html/rfc8415. This does not contain any option. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_IAADDR | option-len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | IPv6-address | + * | | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | preferred-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | valid-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * . . + * . IAaddr-options . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +public class IaAddressOption extends Struct { + public static final int LENGTH = 24; // option length excluding IAaddr-options + + @Field(order = 0, type = Type.S16) + public final short code; + @Field(order = 1, type = Type.S16) + public final short length; + @Field(order = 2, type = Type.Ipv6Address) + public final Inet6Address address; + @Field(order = 3, type = Type.U32) + public final long preferred; + @Field(order = 4, type = Type.U32) + public final long valid; + + IaAddressOption(final short code, final short length, final Inet6Address address, + final long preferred, final long valid) { + this.code = code; + this.length = length; + this.address = address; + this.preferred = preferred; + this.valid = valid; + } + + /** + * Build an IA Address option from the required specific parameters. + */ + public static ByteBuffer build(final short length, final long id, final Inet6Address address, + final long preferred, final long valid) { + final IaAddressOption option = new IaAddressOption((short) DHCP6_OPTION_IA_ADDR, + length /* 24 + IAaddr-options length */, address, preferred, valid); + return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN)); + } +} diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java index 9149160596..f9895c608c 100644 --- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java +++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java @@ -240,6 +240,7 @@ public final class NetworkStackConstants { public static final int DHCP6_SERVER_PORT = 547; public static final Inet6Address ALL_DHCP_RELAY_AGENTS_AND_SERVERS = (Inet6Address) InetAddresses.parseNumericAddress("ff02::1:2"); + public static final int DHCP6_OPTION_IA_ADDR = 5; public static final int DHCP6_OPTION_IA_PD = 25; public static final int DHCP6_OPTION_IAPREFIX = 26; From aad62818449f4ee5db33d737a673a2a1de825f2a Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Wed, 16 Aug 2023 19:28:16 +0900 Subject: [PATCH 757/777] Rename to isTetheringFeatureNotChickenedOut Expected use case of isTetheringFeatureForceDisabled was `enabled = !isTetheringFeatureForceDisabled`, which is error prune. So this CL renames to isTetheringFeatureNotChickenedOut and updates to return true if the feature is not disabled. If the feature is enabled by default and disabled by flag push (kill switch), isTetheringFeatureNotChickenedOut should be used. Bug: 279108992 Test: m Change-Id: I5f85c24032bae298831bbf042874a63ea2c9b75f --- .../android/net/module/util/DeviceConfigUtils.java | 12 ++++++++---- .../net/module/util/DeviceConfigUtilsTest.java | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index bea227d9ad..5edf1b92d8 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -335,15 +335,19 @@ public final class DeviceConfigUtils { /** * Check whether one specific experimental feature in tethering module from {@link DeviceConfig} - * is disabled by setting a non-zero value in the property. + * is not disabled. Feature can be disabled by setting a non-zero value in the property. + * If the feature is enabled by default and disabled by flag push (kill switch), this method + * should be used. + * If the feature is disabled by default and enabled by flag push, + * {@link #isFeatureEnabled(Context, String, String, String, boolean)} should be used. * * @param name The name of the property to look up. - * @return true if this feature is force disabled, or false if not disabled. + * @return true if this feature is enabled, or false if disabled. */ - public static boolean isTetheringFeatureForceDisabled(String name) { + public static boolean isTetheringFeatureNotChickenedOut(String name) { final int propertyVersion = getDeviceConfigPropertyInt(NAMESPACE_TETHERING, name, 0 /* default value */); - return propertyVersion != 0; + return propertyVersion == 0; } /** diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java index 7946244da1..cc17f9fb2c 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -424,10 +424,10 @@ public class DeviceConfigUtilsTest { public void testIsTetheringFeatureForceDisabled() throws Exception { doReturn("0").when(() -> DeviceConfig.getProperty( eq(NAMESPACE_TETHERING), eq(TEST_EXPERIMENT_FLAG))); - assertFalse(DeviceConfigUtils.isTetheringFeatureForceDisabled(TEST_EXPERIMENT_FLAG)); + assertTrue(DeviceConfigUtils.isTetheringFeatureNotChickenedOut(TEST_EXPERIMENT_FLAG)); doReturn(TEST_FLAG_VALUE_STRING).when( () -> DeviceConfig.getProperty(eq(NAMESPACE_TETHERING), eq(TEST_EXPERIMENT_FLAG))); - assertTrue(DeviceConfigUtils.isTetheringFeatureForceDisabled(TEST_EXPERIMENT_FLAG)); + assertFalse(DeviceConfigUtils.isTetheringFeatureNotChickenedOut(TEST_EXPERIMENT_FLAG)); } } From 57bd2e41e90386169af09a1ce355e8dec0a96a7e Mon Sep 17 00:00:00 2001 From: Alex Buynytskyy Date: Thu, 17 Aug 2023 04:07:50 +0000 Subject: [PATCH 758/777] UpsideDownCake is now 34 Ignore-AOSP-First: UpsideDownCake Finalization Bug: 275409981 Test: build (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:8bc31011a242dddb401273b5b6505b49b649ae67) Merged-In: Ic36cad45118f0220e44279a8b6ac89d22c3319d3 Change-Id: Ic36cad45118f0220e44279a8b6ac89d22c3319d3 --- staticlibs/netd/Android.bp | 15 +++++- .../netd_event_listener_interface/2/.hash | 1 + .../net/metrics/INetdEventListener.aidl | 51 +++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 staticlibs/netd/aidl_api/netd_event_listener_interface/2/.hash create mode 100644 staticlibs/netd/aidl_api/netd_event_listener_interface/2/android/net/metrics/INetdEventListener.aidl diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp index 525160dd60..d135a1c89a 100644 --- a/staticlibs/netd/Android.bp +++ b/staticlibs/netd/Android.bp @@ -187,7 +187,7 @@ aidl_interface { srcs: [ "binder/android/net/metrics/INetdEventListener.aidl", ], - versions: ["1"], + backend: { ndk: { apex_available: [ @@ -205,6 +205,19 @@ aidl_interface { min_sdk_version: "29", }, }, + versions_with_info: [ + { + version: "1", + imports: [], + }, + { + version: "2", + imports: [], + }, + + ], + frozen: true, + } java_library { diff --git a/staticlibs/netd/aidl_api/netd_event_listener_interface/2/.hash b/staticlibs/netd/aidl_api/netd_event_listener_interface/2/.hash new file mode 100644 index 0000000000..67c55b77b6 --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_event_listener_interface/2/.hash @@ -0,0 +1 @@ +1b765b02815e970a124de92e793e42e0ceff5384 diff --git a/staticlibs/netd/aidl_api/netd_event_listener_interface/2/android/net/metrics/INetdEventListener.aidl b/staticlibs/netd/aidl_api/netd_event_listener_interface/2/android/net/metrics/INetdEventListener.aidl new file mode 100644 index 0000000000..1b0fe132ee --- /dev/null +++ b/staticlibs/netd/aidl_api/netd_event_listener_interface/2/android/net/metrics/INetdEventListener.aidl @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2016, 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.metrics; +/* @hide */ +interface INetdEventListener { + oneway void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs, @utf8InCpp String hostname, in @utf8InCpp String[] ipAddresses, int ipAddressesCount, int uid); + oneway void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname, boolean validated); + oneway void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port, int uid); + oneway void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader, in byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs); + oneway void onTcpSocketStatsEvent(in int[] networkIds, in int[] sentPackets, in int[] lostPackets, in int[] rttUs, in int[] sentAckDiffMs); + oneway void onNat64PrefixEvent(int netId, boolean added, @utf8InCpp String prefixString, int prefixLength); + const int EVENT_GETADDRINFO = 1; + const int EVENT_GETHOSTBYNAME = 2; + const int EVENT_GETHOSTBYADDR = 3; + const int EVENT_RES_NSEND = 4; + const int REPORTING_LEVEL_NONE = 0; + const int REPORTING_LEVEL_METRICS = 1; + const int REPORTING_LEVEL_FULL = 2; + const int DNS_REPORTED_IP_ADDRESSES_LIMIT = 10; +} From de112b610912a6273a3a5f8daa2030f429acfcd4 Mon Sep 17 00:00:00 2001 From: Cole Faust Date: Thu, 17 Aug 2023 04:42:53 +0000 Subject: [PATCH 759/777] Baseline NewApi issues NewApi was recently updated to support linting methods in the system, module_lib, and system_server sdks, and was demoted to a warning due to the new issues it finds. Baseline all the new issues that NewApi can be made an error again. These cls were generated automatically by a script that copied the NewApi issues from the reference baselines. Bug: 268261262 Test: m lint-check (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:b6d6bf359ca53d41a08b7e2af86f7a080e2b5741) Merged-In: I31beadf91173116b9750fe6f132a4f979a2e0d9a Change-Id: I31beadf91173116b9750fe6f132a4f979a2e0d9a --- staticlibs/lint-baseline.xml | 70 ++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 staticlibs/lint-baseline.xml diff --git a/staticlibs/lint-baseline.xml b/staticlibs/lint-baseline.xml new file mode 100644 index 0000000000..d413b2a776 --- /dev/null +++ b/staticlibs/lint-baseline.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From c046ac418e2cb4f16dff395ec2490ae1c4447518 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Tue, 15 Aug 2023 16:12:48 +0900 Subject: [PATCH 760/777] Rename to isTetheringFeatureEnabled DeviceConfigUtils has isFeatureEnabled for NetworkStack and Tethering which were confusing since the difference was only the arguments. This CL renames isFeatureEnabled for Tethering module to isTetheringFeatureEnabled to avoid confusion. Bug: 279108992 Test: m Change-Id: I16e8e4f6c0080d73533ce8bd36adfa7038347500 --- .../net/module/util/DeviceConfigUtils.java | 7 +++--- .../module/util/DeviceConfigUtilsTest.java | 24 +++++++++---------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index 5edf1b92d8..caa2b05551 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -207,8 +207,9 @@ public final class DeviceConfigUtils { * null. * @return true if this feature is enabled, or false if disabled. */ - public static boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, - @NonNull String name, @NonNull String moduleName, boolean defaultEnabled) { + public static boolean isTetheringFeatureEnabled(@NonNull Context context, + @NonNull String namespace, @NonNull String name, @NonNull String moduleName, + boolean defaultEnabled) { // TODO: migrate callers to a non-generic isTetheringFeatureEnabled method. if (!TETHERING_MODULE_NAME.equals(moduleName)) { throw new IllegalArgumentException( @@ -339,7 +340,7 @@ public final class DeviceConfigUtils { * If the feature is enabled by default and disabled by flag push (kill switch), this method * should be used. * If the feature is disabled by default and enabled by flag push, - * {@link #isFeatureEnabled(Context, String, String, String, boolean)} should be used. + * {@link #isTetheringFeatureEnabled} should be used. * * @param name The name of the property to look up. * @return true if this feature is enabled, or false if disabled. diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java index cc17f9fb2c..e80fa80a24 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -233,7 +233,7 @@ public class DeviceConfigUtilsTest { eq(TEST_EXPERIMENT_FLAG))); assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); } @@ -243,9 +243,9 @@ public class DeviceConfigUtilsTest { eq(TEST_EXPERIMENT_FLAG))); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); - assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, true /* defaultEnabled */)); } @@ -258,7 +258,7 @@ public class DeviceConfigUtilsTest { eq(TEST_EXPERIMENT_FLAG))); assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); // Feature should be disabled by flag value "999999999". @@ -266,7 +266,7 @@ public class DeviceConfigUtilsTest { eq(TEST_EXPERIMENT_FLAG))); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); - assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); // Follow defaultEnabled if the flag is not set @@ -276,9 +276,9 @@ public class DeviceConfigUtilsTest { TEST_EXPERIMENT_FLAG, false /* defaultEnabled */)); assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, true /* defaultEnabled */)); - assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, true /* defaultEnabled */)); } @@ -293,14 +293,14 @@ public class DeviceConfigUtilsTest { assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); - assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, true /* defaultEnabled */)); doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); } @@ -323,9 +323,9 @@ public class DeviceConfigUtilsTest { public void testFeatureIsEnabledCaching_APEX() throws Exception { doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); // Package info is only queried once From 3b64739d81170b2a4d26c36a507419f78782acd1 Mon Sep 17 00:00:00 2001 From: chiachangwang Date: Wed, 16 Aug 2023 07:52:14 +0000 Subject: [PATCH 761/777] Address review comments in aosp/2677976 This commit address the follow-up review comments in aosp/2677976. Fix: 296150560 Test: atest FrameworksNetTests NetworkStaticLibTests Change-Id: I0ff4cef8585e2ae496447c4d37e072c1de281775 --- .../net/module/util/FeatureVersions.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/FeatureVersions.java b/staticlibs/device/com/android/net/module/util/FeatureVersions.java index 4986a58813..149756c38f 100644 --- a/staticlibs/device/com/android/net/module/util/FeatureVersions.java +++ b/staticlibs/device/com/android/net/module/util/FeatureVersions.java @@ -22,13 +22,24 @@ package com.android.net.module.util; * @hide */ public class FeatureVersions { - public static final long MODULE_MASK = 0xFF00_000000000L; - public static final long VERSION_MASK = 0x0000_FFFFFFFFFL; - public static final long CONNECTIVITY_MODULE_ID = 0x0100_000000000L; - public static final long NETWORK_STACK_MODULE_ID = 0x0200_000000000L; + /** + * This constant is used to do bitwise shift operation to create module ids. + * The module version is composed with 9 digits which is placed in the lower 36 bits. + */ + private static final int MODULE_SHIFT = 36; + /** + * The bitmask to do bitwise-and(i.e. {@code &}) operation to get the module id. + */ + public static final long MODULE_MASK = 0xFF0_0000_0000L; + /** + * The bitmask to do bitwise-and(i.e. {@code &}) operation to get the module version. + */ + public static final long VERSION_MASK = 0x00F_FFFF_FFFFL; + public static final long CONNECTIVITY_MODULE_ID = 0x01L << MODULE_SHIFT; + public static final long NETWORK_STACK_MODULE_ID = 0x02L << MODULE_SHIFT; // CLAT_ADDRESS_TRANSLATE is a feature of the network stack, which doesn't throw when system // try to add a NAT-T keepalive packet filter with v6 address, introduced in version // M-2023-Sept on July 3rd, 2023. public static final long FEATURE_CLAT_ADDRESS_TRANSLATE = - NETWORK_STACK_MODULE_ID + 340900000L; + NETWORK_STACK_MODULE_ID + 34_09_00_000L; } From 5bf2947997b5c70b48480abf0ffc260d72da07ca Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 9 Aug 2023 06:57:32 -0700 Subject: [PATCH 762/777] Improve test logs using TrackRecord backtrace eventuallyExpect methods should print the received callbacks since poll() was called for better debugging. Test: atest EthernetManagerTest Change-Id: Ia08abf2436b050a7e319b9f70694ce3d132b4fc3 --- .../com/android/testutils/TestableNetworkCallback.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt index 4b6aea2d52..df9c61ae2d 100644 --- a/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt +++ b/staticlibs/testutils/devicetests/com/android/testutils/TestableNetworkCallback.kt @@ -389,7 +389,8 @@ open class TestableNetworkCallback private constructor( from: Int = mark, crossinline predicate: (T) -> Boolean = { true } ): T = history.poll(timeoutMs, from) { it is T && predicate(it) }.also { - assertNotNull(it, "Callback ${T::class} not received within ${timeoutMs}ms") + assertNotNull(it, "Callback ${T::class} not received within ${timeoutMs}ms. " + + "Got ${history.backtrace()}") } as T @JvmOverloads @@ -398,7 +399,8 @@ open class TestableNetworkCallback private constructor( timeoutMs: Long = defaultTimeoutMs, predicate: (cb: T) -> Boolean = { true } ) = history.poll(timeoutMs) { type.java.isInstance(it) && predicate(it as T) }.also { - assertNotNull(it, "Callback ${type.java} not received within ${timeoutMs}ms") + assertNotNull(it, "Callback ${type.java} not received within ${timeoutMs}ms. " + + "Got ${history.backtrace()}") } as T fun eventuallyExpect( @@ -407,7 +409,8 @@ open class TestableNetworkCallback private constructor( from: Int = mark, predicate: (cb: T) -> Boolean = { true } ) = history.poll(timeoutMs, from) { type.java.isInstance(it) && predicate(it as T) }.also { - assertNotNull(it, "Callback ${type.java} not received within ${timeoutMs}ms") + assertNotNull(it, "Callback ${type.java} not received within ${timeoutMs}ms. " + + "Got ${history.backtrace()}") } as T // Expects onAvailable and the callbacks that follow it. These are: From 910cf4da9b6c1909a466b9e17f5f90676b54453b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sun, 20 Aug 2023 12:02:35 +0000 Subject: [PATCH 763/777] BpfMap - slightly simplify isEmpty() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I9b93224ec2d4ff717d5e39c3ad50e63ac73f5f7c --- staticlibs/native/bpf_headers/include/bpf/BpfMap.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h index 51e6d162bd..1ddcfe66ba 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h @@ -235,12 +235,9 @@ class BpfMap { base::Result isEmpty() const { auto key = getFirstKey(); - if (!key.ok()) { - // Return error code ENOENT means the map is empty - if (key.error().code() == ENOENT) return true; - return key.error(); - } - return false; + if (key.ok()) return false; + if (key.error().code() == ENOENT) return true; + return key.error(); } private: From 2c87b8260303d16a39daaded2707d0dc0c42cc01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sun, 20 Aug 2023 13:00:51 +0000 Subject: [PATCH 764/777] BpfMap.java - remove getNextRawKey() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ida62d346c1d6df800b5d45b67de60e945ac2b4c8 --- .../com/android/net/module/util/BpfMap.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java index 9df2b035e3..ccacb31355 100644 --- a/staticlibs/device/com/android/net/module/util/BpfMap.java +++ b/staticlibs/device/com/android/net/module/util/BpfMap.java @@ -194,9 +194,11 @@ public class BpfMap implements IBpfMap } private K getNextKeyInternal(@Nullable K key) throws ErrnoException { - final byte[] rawKey = getNextRawKey( - key == null ? null : key.writeToBytes()); - if (rawKey == null) return null; + byte[] rawKey = new byte[mKeySize]; + + if (!nativeGetNextMapKey(mMapFd.getFd(), + key == null ? null : key.writeToBytes(), + rawKey)) return null; final ByteBuffer buffer = ByteBuffer.wrap(rawKey); buffer.order(ByteOrder.nativeOrder()); @@ -215,13 +217,6 @@ public class BpfMap implements IBpfMap return getNextKeyInternal(key); } - private byte[] getNextRawKey(@Nullable final byte[] key) throws ErrnoException { - byte[] nextKey = new byte[mKeySize]; - if (nativeGetNextMapKey(mMapFd.getFd(), key, nextKey)) return nextKey; - - return null; - } - /** Get the first key of eBpf map. */ @Override public K getFirstKey() throws ErrnoException { From b6a23b15042ba4a7a052c5f8cb8c7b452b1c4233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sun, 20 Aug 2023 14:04:31 +0000 Subject: [PATCH 765/777] BpfMap.java - remove getRawValue() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I6903a29773ee4782c0f2ae64561e1c0fdcba618f --- .../com/android/net/module/util/BpfMap.java | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java index 9df2b035e3..b3451c11e8 100644 --- a/staticlibs/device/com/android/net/module/util/BpfMap.java +++ b/staticlibs/device/com/android/net/module/util/BpfMap.java @@ -233,30 +233,23 @@ public class BpfMap implements IBpfMap public boolean containsKey(@NonNull K key) throws ErrnoException { Objects.requireNonNull(key); - final byte[] rawValue = getRawValue(key.writeToBytes()); - return rawValue != null; + byte[] rawValue = new byte[mValueSize]; + return nativeFindMapEntry(mMapFd.getFd(), key.writeToBytes(), rawValue); } /** Retrieve a value from the map. Return null if there is no such key. */ @Override public V getValue(@NonNull K key) throws ErrnoException { Objects.requireNonNull(key); - final byte[] rawValue = getRawValue(key.writeToBytes()); - if (rawValue == null) return null; + byte[] rawValue = new byte[mValueSize]; + if (!nativeFindMapEntry(mMapFd.getFd(), key.writeToBytes(), rawValue)) return null; final ByteBuffer buffer = ByteBuffer.wrap(rawValue); buffer.order(ByteOrder.nativeOrder()); return Struct.parse(mValueClass, buffer); } - private byte[] getRawValue(final byte[] key) throws ErrnoException { - byte[] value = new byte[mValueSize]; - if (nativeFindMapEntry(mMapFd.getFd(), key, value)) return value; - - return null; - } - /** * Iterate through the map and handle each key -> value retrieved base on the given BiConsumer. * The given BiConsumer may to delete the passed-in entry, but is not allowed to perform any From eb1eb69f862583d71382758d1736f0a18a0f956d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sun, 20 Aug 2023 23:33:23 +0000 Subject: [PATCH 766/777] BpfMap.h - add 3 using statements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit in particular base::Result is needlessly verbose Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ide0de9acec79b9aeeaff7ec92270304907bd10d4 --- .../native/bpf_headers/include/bpf/BpfMap.h | 107 +++++++++--------- 1 file changed, 56 insertions(+), 51 deletions(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h index 51e6d162bd..aa7bafe8e3 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h @@ -29,6 +29,10 @@ namespace android { namespace bpf { +using base::Result; +using base::unique_fd; +using std::function; + // This is a class wrapper for eBPF maps. The eBPF map is a special in-kernel // data structure that stores data in pairs. It can be read/write // from userspace by passing syscalls with the map file descriptor. This class @@ -80,7 +84,7 @@ class BpfMap { } #endif - base::Result getFirstKey() const { + Result getFirstKey() const { Key firstKey; if (getFirstMapKey(mMapFd, &firstKey)) { return ErrnoErrorf("Get firstKey map {} failed", mMapFd.get()); @@ -88,7 +92,7 @@ class BpfMap { return firstKey; } - base::Result getNextKey(const Key& key) const { + Result getNextKey(const Key& key) const { Key nextKey; if (getNextMapKey(mMapFd, &key, &nextKey)) { return ErrnoErrorf("Get next key of map {} failed", mMapFd.get()); @@ -96,14 +100,14 @@ class BpfMap { return nextKey; } - base::Result writeValue(const Key& key, const Value& value, uint64_t flags) { + Result writeValue(const Key& key, const Value& value, uint64_t flags) { if (writeToMapEntry(mMapFd, &key, &value, flags)) { return ErrnoErrorf("Write to map {} failed", mMapFd.get()); } return {}; } - base::Result readValue(const Key key) const { + Result readValue(const Key key) const { Value value; if (findMapEntry(mMapFd, &key, &value)) { return ErrnoErrorf("Read value of map {} failed", mMapFd.get()); @@ -111,7 +115,7 @@ class BpfMap { return value; } - base::Result deleteValue(const Key& key) { + Result deleteValue(const Key& key) { if (deleteMapEntry(mMapFd, &key)) { return ErrnoErrorf("Delete entry from map {} failed", mMapFd.get()); } @@ -119,7 +123,7 @@ class BpfMap { } protected: - [[clang::reinitializes]] base::Result init(const char* path, int fd) { + [[clang::reinitializes]] Result init(const char* path, int fd) { mMapFd.reset(fd); if (!mMapFd.ok()) { return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path); @@ -134,7 +138,7 @@ class BpfMap { public: // Function that tries to get map from a pinned path. - [[clang::reinitializes]] base::Result init(const char* path) { + [[clang::reinitializes]] Result init(const char* path) { return init(path, mapRetrieveRW(path)); } @@ -144,7 +148,7 @@ class BpfMap { // this should only ever be used by test code, it is equivalent to: // .reset(createMap(type, keysize, valuesize, max_entries, map_flags) // TODO: derive map_flags from BpfMap vs BpfMapRO - [[clang::reinitializes]] base::Result resetMap(bpf_map_type map_type, + [[clang::reinitializes]] Result resetMap(bpf_map_type map_type, uint32_t max_entries, uint32_t map_flags = 0) { mMapFd.reset(createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags)); @@ -155,28 +159,28 @@ class BpfMap { // Iterate through the map and handle each key retrieved based on the filter // without modification of map content. - base::Result iterate( - const std::function(const Key& key, const BpfMap& map)>& - filter) const; + Result iterate( + const function(const Key& key, + const BpfMap& map)>& filter) const; // Iterate through the map and get each pair, handle each pair based on the filter without modification of map content. - base::Result iterateWithValue( - const std::function(const Key& key, const Value& value, - const BpfMap& map)>& filter) const; + Result iterateWithValue( + const function(const Key& key, const Value& value, + const BpfMap& map)>& filter) const; // Iterate through the map and handle each key retrieved based on the filter - base::Result iterate( - const std::function(const Key& key, BpfMap& map)>& - filter); + Result iterate( + const function(const Key& key, + BpfMap& map)>& filter); // Iterate through the map and get each pair, handle each pair based on the filter. - base::Result iterateWithValue( - const std::function(const Key& key, const Value& value, - BpfMap& map)>& filter); + Result iterateWithValue( + const function(const Key& key, const Value& value, + BpfMap& map)>& filter); - const base::unique_fd& getMap() const { return mMapFd; }; + const unique_fd& getMap() const { return mMapFd; }; #ifdef BPF_MAP_MAKE_VISIBLE_FOR_TESTING // Copy assignment operator - due to need for fd duping, should not be used in non-test code. @@ -197,7 +201,7 @@ class BpfMap { return *this; } - void reset(base::unique_fd fd) = delete; + void reset(unique_fd fd) = delete; #ifdef BPF_MAP_MAKE_VISIBLE_FOR_TESTING // Note that unique_fd.reset() carefully saves and restores the errno, @@ -216,7 +220,7 @@ class BpfMap { bool isValid() const { return mMapFd.ok(); } - base::Result clear() { + Result clear() { while (true) { auto key = getFirstKey(); if (!key.ok()) { @@ -233,7 +237,7 @@ class BpfMap { } } - base::Result isEmpty() const { + Result isEmpty() const { auto key = getFirstKey(); if (!key.ok()) { // Return error code ENOENT means the map is empty @@ -244,17 +248,17 @@ class BpfMap { } private: - base::unique_fd mMapFd; + unique_fd mMapFd; }; template -base::Result BpfMap::iterate( - const std::function(const Key& key, const BpfMap& map)>& - filter) const { - base::Result curKey = getFirstKey(); +Result BpfMap::iterate( + const function(const Key& key, + const BpfMap& map)>& filter) const { + Result curKey = getFirstKey(); while (curKey.ok()) { - const base::Result& nextKey = getNextKey(curKey.value()); - base::Result status = filter(curKey.value(), *this); + const Result& nextKey = getNextKey(curKey.value()); + Result status = filter(curKey.value(), *this); if (!status.ok()) return status; curKey = nextKey; } @@ -263,15 +267,15 @@ base::Result BpfMap::iterate( } template -base::Result BpfMap::iterateWithValue( - const std::function(const Key& key, const Value& value, - const BpfMap& map)>& filter) const { - base::Result curKey = getFirstKey(); +Result BpfMap::iterateWithValue( + const function(const Key& key, const Value& value, + const BpfMap& map)>& filter) const { + Result curKey = getFirstKey(); while (curKey.ok()) { - const base::Result& nextKey = getNextKey(curKey.value()); - base::Result curValue = readValue(curKey.value()); + const Result& nextKey = getNextKey(curKey.value()); + Result curValue = readValue(curKey.value()); if (!curValue.ok()) return curValue.error(); - base::Result status = filter(curKey.value(), curValue.value(), *this); + Result status = filter(curKey.value(), curValue.value(), *this); if (!status.ok()) return status; curKey = nextKey; } @@ -280,12 +284,13 @@ base::Result BpfMap::iterateWithValue( } template -base::Result BpfMap::iterate( - const std::function(const Key& key, BpfMap& map)>& filter) { - base::Result curKey = getFirstKey(); +Result BpfMap::iterate( + const function(const Key& key, + BpfMap& map)>& filter) { + Result curKey = getFirstKey(); while (curKey.ok()) { - const base::Result& nextKey = getNextKey(curKey.value()); - base::Result status = filter(curKey.value(), *this); + const Result& nextKey = getNextKey(curKey.value()); + Result status = filter(curKey.value(), *this); if (!status.ok()) return status; curKey = nextKey; } @@ -294,15 +299,15 @@ base::Result BpfMap::iterate( } template -base::Result BpfMap::iterateWithValue( - const std::function(const Key& key, const Value& value, - BpfMap& map)>& filter) { - base::Result curKey = getFirstKey(); +Result BpfMap::iterateWithValue( + const function(const Key& key, const Value& value, + BpfMap& map)>& filter) { + Result curKey = getFirstKey(); while (curKey.ok()) { - const base::Result& nextKey = getNextKey(curKey.value()); - base::Result curValue = readValue(curKey.value()); + const Result& nextKey = getNextKey(curKey.value()); + Result curValue = readValue(curKey.value()); if (!curValue.ok()) return curValue.error(); - base::Result status = filter(curKey.value(), curValue.value(), *this); + Result status = filter(curKey.value(), curValue.value(), *this); if (!status.ok()) return status; curKey = nextKey; } @@ -319,7 +324,7 @@ class BpfMapRO : public BpfMap { : BpfMap(pathname, BPF_F_RDONLY) {} // Function that tries to get map from a pinned path. - [[clang::reinitializes]] base::Result init(const char* path) { + [[clang::reinitializes]] Result init(const char* path) { return BpfMap::init(path, mapRetrieveRO(path)); } }; From 12c0ea929c3343319da2fd95c8aa21c241fdd677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sun, 20 Aug 2023 17:06:45 +0000 Subject: [PATCH 767/777] BpfMap.h - hide getMap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This leaks (what should be) an internal only fd. There's still multiple uses of getMap() left in: common/native/bpf_headers/BpfMapTest.cpp Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I87a36f3f935ba9148ae4456fc6bf14b0e04f6038 --- staticlibs/native/bpf_headers/include/bpf/BpfMap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h index aa7bafe8e3..0ab2fda153 100644 --- a/staticlibs/native/bpf_headers/include/bpf/BpfMap.h +++ b/staticlibs/native/bpf_headers/include/bpf/BpfMap.h @@ -180,9 +180,9 @@ class BpfMap { const function(const Key& key, const Value& value, BpfMap& map)>& filter); +#ifdef BPF_MAP_MAKE_VISIBLE_FOR_TESTING const unique_fd& getMap() const { return mMapFd; }; -#ifdef BPF_MAP_MAKE_VISIBLE_FOR_TESTING // Copy assignment operator - due to need for fd duping, should not be used in non-test code. BpfMap& operator=(const BpfMap& other) { if (this != &other) mMapFd.reset(fcntl(other.mMapFd.get(), F_DUPFD_CLOEXEC, 0)); From 68cd7313813f630fd45ee610b8d0ce7d3438c3d1 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Tue, 22 Aug 2023 12:50:20 +0900 Subject: [PATCH 768/777] Add libnetd_utils_headers cc_library_headers There is a module that specifies libnetdutils/include from include_dirs which is not recommended. Using the cc_library_headers makes it easy to move frameworks/libs/net to packages/modules/Connectivity. Bug: 296014682 Test: m Change-Id: Ia52ede9787009102ebf626fcb3b337511b0a809f --- staticlibs/netd/libnetdutils/Android.bp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/staticlibs/netd/libnetdutils/Android.bp b/staticlibs/netd/libnetdutils/Android.bp index 08d5412158..31690331cc 100644 --- a/staticlibs/netd/libnetdutils/Android.bp +++ b/staticlibs/netd/libnetdutils/Android.bp @@ -66,3 +66,8 @@ cc_test { "libbase", ], } + +cc_library_headers { + name: "libnetd_utils_headers", + export_include_dirs: ["include"], +} From 7bca2922b882138d6293a26fb04a2d6a3e776b1f Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Tue, 22 Aug 2023 18:30:32 +0900 Subject: [PATCH 769/777] Add class to help Kotlin to pass nullable to java @NonNull for testing Follow up CL for aosp/2700076 Bug: 296972712 Test: build with aosp/2688146 Change-Id: Ib582ef41f34baf0bb896e32d681843358f928c87 --- .../android/testutils/NonNullTestUtils.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 staticlibs/testutils/devicetests/com/android/testutils/NonNullTestUtils.java diff --git a/staticlibs/testutils/devicetests/com/android/testutils/NonNullTestUtils.java b/staticlibs/testutils/devicetests/com/android/testutils/NonNullTestUtils.java new file mode 100644 index 0000000000..463c4706cc --- /dev/null +++ b/staticlibs/testutils/devicetests/com/android/testutils/NonNullTestUtils.java @@ -0,0 +1,33 @@ +/* + * 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 com.android.testutils; + +import android.annotation.NonNull; + +/** + * Utilities to help Kotlin test to verify java @NonNull code + */ +public class NonNullTestUtils { + /** + * This method allows Kotlin to pass nullable to @NonNull java code for testing. + * For Foo(@NonNull arg) java method, Kotlin can pass nullable variable by + * Foo(NonNullTestUtils.nullUnsafe(nullableVar)). + */ + @NonNull public static T nullUnsafe(T v) { + return v; + } +} From 6acc55e1298d3ec9f050ff68672eacc5465e004d Mon Sep 17 00:00:00 2001 From: Yuyang Huang Date: Tue, 22 Aug 2023 13:45:18 +0900 Subject: [PATCH 770/777] Move ArpPacket.java to frameworks/libs/net Bug: 281639507 Test: TH Change-Id: Ic0d273695d3f0f85a0ec56337a9d12d77b60ea3b --- staticlibs/Android.bp | 1 + .../net/module/util/arp/ArpPacket.java | 171 +++++++++++++++ .../net/module/util/ArpPacketTest.java | 201 ++++++++++++++++++ 3 files changed, 373 insertions(+) create mode 100644 staticlibs/device/com/android/net/module/util/arp/ArpPacket.java create mode 100644 staticlibs/tests/unit/src/com/android/net/module/util/ArpPacketTest.java diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index d3e68b753e..0b42219c64 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -34,6 +34,7 @@ package { java_library { name: "net-utils-device-common", srcs: [ + "device/com/android/net/module/util/arp/ArpPacket.java", "device/com/android/net/module/util/DeviceConfigUtils.java", "device/com/android/net/module/util/DomainUtils.java", "device/com/android/net/module/util/FdEventsReader.java", diff --git a/staticlibs/device/com/android/net/module/util/arp/ArpPacket.java b/staticlibs/device/com/android/net/module/util/arp/ArpPacket.java new file mode 100644 index 0000000000..dab9694b25 --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/arp/ArpPacket.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util.arp; + +import static android.system.OsConstants.ETH_P_ARP; +import static android.system.OsConstants.ETH_P_IP; + +import static com.android.net.module.util.NetworkStackConstants.ARP_ETHER_IPV4_LEN; +import static com.android.net.module.util.NetworkStackConstants.ARP_HWTYPE_ETHER; +import static com.android.net.module.util.NetworkStackConstants.ARP_REPLY; +import static com.android.net.module.util.NetworkStackConstants.ARP_REQUEST; +import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN; +import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_LEN; + +import android.net.MacAddress; + +import com.android.internal.annotations.VisibleForTesting; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; + +/** + * Defines basic data and operations needed to build and parse packets for the + * ARP protocol. + * + * @hide + */ +public class ArpPacket { + private static final String TAG = "ArpPacket"; + + public final short opCode; + public final Inet4Address senderIp; + public final Inet4Address targetIp; + public final MacAddress senderHwAddress; + public final MacAddress targetHwAddress; + + ArpPacket(short opCode, MacAddress senderHwAddress, Inet4Address senderIp, + MacAddress targetHwAddress, Inet4Address targetIp) { + this.opCode = opCode; + this.senderHwAddress = senderHwAddress; + this.senderIp = senderIp; + this.targetHwAddress = targetHwAddress; + this.targetIp = targetIp; + } + + /** + * Build an ARP packet from the required specified parameters. + */ + @VisibleForTesting + public static ByteBuffer buildArpPacket(final byte[] dstMac, final byte[] srcMac, + final byte[] targetIp, final byte[] targetHwAddress, byte[] senderIp, + final short opCode) { + final ByteBuffer buf = ByteBuffer.allocate(ARP_ETHER_IPV4_LEN); + + // Ether header + buf.put(dstMac); + buf.put(srcMac); + buf.putShort((short) ETH_P_ARP); + + // ARP header + buf.putShort((short) ARP_HWTYPE_ETHER); // hrd + buf.putShort((short) ETH_P_IP); // pro + buf.put((byte) ETHER_ADDR_LEN); // hln + buf.put((byte) IPV4_ADDR_LEN); // pln + buf.putShort(opCode); // op + buf.put(srcMac); // sha + buf.put(senderIp); // spa + buf.put(targetHwAddress); // tha + buf.put(targetIp); // tpa + buf.flip(); + return buf; + } + + /** + * Parse an ARP packet from a ByteBuffer object. + */ + @VisibleForTesting + public static ArpPacket parseArpPacket(final byte[] recvbuf, final int length) + throws ParseException { + try { + if (length < ARP_ETHER_IPV4_LEN || recvbuf.length < length) { + throw new ParseException("Invalid packet length: " + length); + } + + final ByteBuffer buffer = ByteBuffer.wrap(recvbuf, 0, length); + byte[] l2dst = new byte[ETHER_ADDR_LEN]; + byte[] l2src = new byte[ETHER_ADDR_LEN]; + buffer.get(l2dst); + buffer.get(l2src); + + final short etherType = buffer.getShort(); + if (etherType != ETH_P_ARP) { + throw new ParseException("Incorrect Ether Type: " + etherType); + } + + final short hwType = buffer.getShort(); + if (hwType != ARP_HWTYPE_ETHER) { + throw new ParseException("Incorrect HW Type: " + hwType); + } + + final short protoType = buffer.getShort(); + if (protoType != ETH_P_IP) { + throw new ParseException("Incorrect Protocol Type: " + protoType); + } + + final byte hwAddrLength = buffer.get(); + if (hwAddrLength != ETHER_ADDR_LEN) { + throw new ParseException("Incorrect HW address length: " + hwAddrLength); + } + + final byte ipAddrLength = buffer.get(); + if (ipAddrLength != IPV4_ADDR_LEN) { + throw new ParseException("Incorrect Protocol address length: " + ipAddrLength); + } + + final short opCode = buffer.getShort(); + if (opCode != ARP_REQUEST && opCode != ARP_REPLY) { + throw new ParseException("Incorrect opCode: " + opCode); + } + + byte[] senderHwAddress = new byte[ETHER_ADDR_LEN]; + byte[] senderIp = new byte[IPV4_ADDR_LEN]; + buffer.get(senderHwAddress); + buffer.get(senderIp); + + byte[] targetHwAddress = new byte[ETHER_ADDR_LEN]; + byte[] targetIp = new byte[IPV4_ADDR_LEN]; + buffer.get(targetHwAddress); + buffer.get(targetIp); + + return new ArpPacket(opCode, MacAddress.fromBytes(senderHwAddress), + (Inet4Address) InetAddress.getByAddress(senderIp), + MacAddress.fromBytes(targetHwAddress), + (Inet4Address) InetAddress.getByAddress(targetIp)); + } catch (IndexOutOfBoundsException e) { + throw new ParseException("Invalid index when wrapping a byte array into a buffer"); + } catch (BufferUnderflowException e) { + throw new ParseException("Invalid buffer position"); + } catch (IllegalArgumentException e) { + throw new ParseException("Invalid MAC address representation"); + } catch (UnknownHostException e) { + throw new ParseException("Invalid IP address of Host"); + } + } + + /** + * Thrown when parsing ARP packet failed. + */ + public static class ParseException extends Exception { + ParseException(String message) { + super(message); + } + } +} diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/ArpPacketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/ArpPacketTest.java new file mode 100644 index 0000000000..e25d554892 --- /dev/null +++ b/staticlibs/tests/unit/src/com/android/net/module/util/ArpPacketTest.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2019 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 com.android.net.module.util; + +import static com.android.net.module.util.NetworkStackConstants.ARP_REQUEST; +import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN; +import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST; +import static com.android.testutils.MiscAsserts.assertThrows; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import android.net.InetAddresses; +import android.net.MacAddress; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.net.module.util.arp.ArpPacket; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; +import java.nio.ByteBuffer; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public final class ArpPacketTest { + + private static final Inet4Address TEST_IPV4_ADDR = + (Inet4Address) InetAddresses.parseNumericAddress("192.168.1.2"); + private static final Inet4Address INADDR_ANY = + (Inet4Address) InetAddresses.parseNumericAddress("0.0.0.0"); + private static final byte[] TEST_SENDER_MAC_ADDR = new byte[] { + 0x00, 0x1a, 0x11, 0x22, 0x33, 0x33 }; + private static final byte[] TEST_TARGET_MAC_ADDR = new byte[] { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + private static final byte[] TEST_ARP_PROBE = new byte[] { + // dst mac address + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + // src mac address + (byte) 0x00, (byte) 0x1a, (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x33, + // ether type + (byte) 0x08, (byte) 0x06, + // hardware type + (byte) 0x00, (byte) 0x01, + // protocol type + (byte) 0x08, (byte) 0x00, + // hardware address size + (byte) 0x06, + // protocol address size + (byte) 0x04, + // opcode + (byte) 0x00, (byte) 0x01, + // sender mac address + (byte) 0x00, (byte) 0x1a, (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x33, + // sender IP address + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + // target mac address + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + // target IP address + (byte) 0xc0, (byte) 0xa8, (byte) 0x01, (byte) 0x02, + }; + + private static final byte[] TEST_ARP_ANNOUNCE = new byte[] { + // dst mac address + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + // src mac address + (byte) 0x00, (byte) 0x1a, (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x33, + // ether type + (byte) 0x08, (byte) 0x06, + // hardware type + (byte) 0x00, (byte) 0x01, + // protocol type + (byte) 0x08, (byte) 0x00, + // hardware address size + (byte) 0x06, + // protocol address size + (byte) 0x04, + // opcode + (byte) 0x00, (byte) 0x01, + // sender mac address + (byte) 0x00, (byte) 0x1a, (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x33, + // sender IP address + (byte) 0xc0, (byte) 0xa8, (byte) 0x01, (byte) 0x02, + // target mac address + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + // target IP address + (byte) 0xc0, (byte) 0xa8, (byte) 0x01, (byte) 0x02, + }; + + private static final byte[] TEST_ARP_PROBE_TRUNCATED = new byte[] { + // dst mac address + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + // src mac address + (byte) 0x00, (byte) 0x1a, (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x33, + // ether type + (byte) 0x08, (byte) 0x06, + // hardware type + (byte) 0x00, (byte) 0x01, + // protocol type + (byte) 0x08, (byte) 0x00, + // hardware address size + (byte) 0x06, + // protocol address size + (byte) 0x04, + // opcode + (byte) 0x00, + }; + + private static final byte[] TEST_ARP_PROBE_TRUNCATED_MAC = new byte[] { + // dst mac address + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + // src mac address + (byte) 0x00, (byte) 0x1a, (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x33, + // ether type + (byte) 0x08, (byte) 0x06, + // hardware type + (byte) 0x00, (byte) 0x01, + // protocol type + (byte) 0x08, (byte) 0x00, + // hardware address size + (byte) 0x06, + // protocol address size + (byte) 0x04, + // opcode + (byte) 0x00, (byte) 0x01, + // sender mac address + (byte) 0x00, (byte) 0x1a, (byte) 0x11, (byte) 0x22, (byte) 0x33, + }; + + @Test + public void testBuildArpProbePacket() throws Exception { + final ByteBuffer arpProbe = ArpPacket.buildArpPacket(ETHER_BROADCAST, + TEST_SENDER_MAC_ADDR, TEST_IPV4_ADDR.getAddress(), new byte[ETHER_ADDR_LEN], + INADDR_ANY.getAddress(), (short) ARP_REQUEST); + assertArrayEquals(arpProbe.array(), TEST_ARP_PROBE); + } + + @Test + public void testBuildArpAnnouncePacket() throws Exception { + final ByteBuffer arpAnnounce = ArpPacket.buildArpPacket(ETHER_BROADCAST, + TEST_SENDER_MAC_ADDR, TEST_IPV4_ADDR.getAddress(), new byte[ETHER_ADDR_LEN], + TEST_IPV4_ADDR.getAddress(), (short) ARP_REQUEST); + assertArrayEquals(arpAnnounce.array(), TEST_ARP_ANNOUNCE); + } + + @Test + public void testParseArpProbePacket() throws Exception { + final ArpPacket packet = ArpPacket.parseArpPacket(TEST_ARP_PROBE, TEST_ARP_PROBE.length); + assertEquals(packet.opCode, ARP_REQUEST); + assertEquals(packet.senderHwAddress, MacAddress.fromBytes(TEST_SENDER_MAC_ADDR)); + assertEquals(packet.targetHwAddress, MacAddress.fromBytes(TEST_TARGET_MAC_ADDR)); + assertEquals(packet.senderIp, INADDR_ANY); + assertEquals(packet.targetIp, TEST_IPV4_ADDR); + } + + @Test + public void testParseArpAnnouncePacket() throws Exception { + final ArpPacket packet = ArpPacket.parseArpPacket(TEST_ARP_ANNOUNCE, + TEST_ARP_ANNOUNCE.length); + assertEquals(packet.opCode, ARP_REQUEST); + assertEquals(packet.senderHwAddress, MacAddress.fromBytes(TEST_SENDER_MAC_ADDR)); + assertEquals(packet.targetHwAddress, MacAddress.fromBytes(TEST_TARGET_MAC_ADDR)); + assertEquals(packet.senderIp, TEST_IPV4_ADDR); + assertEquals(packet.targetIp, TEST_IPV4_ADDR); + } + + @Test + public void testParseArpPacket_invalidByteBufferParameters() throws Exception { + assertThrows(ArpPacket.ParseException.class, () -> ArpPacket.parseArpPacket( + TEST_ARP_PROBE, 0)); + } + + @Test + public void testParseArpPacket_truncatedPacket() throws Exception { + assertThrows(ArpPacket.ParseException.class, () -> ArpPacket.parseArpPacket( + TEST_ARP_PROBE_TRUNCATED, TEST_ARP_PROBE_TRUNCATED.length)); + } + + @Test + public void testParseArpPacket_truncatedMacAddress() throws Exception { + assertThrows(ArpPacket.ParseException.class, () -> ArpPacket.parseArpPacket( + TEST_ARP_PROBE_TRUNCATED_MAC, TEST_ARP_PROBE_TRUNCATED.length)); + } +} From 82952a222827ffc97211ac38eef603abc8c763e5 Mon Sep 17 00:00:00 2001 From: Yuyang Huang Date: Tue, 8 Aug 2023 11:42:18 +0900 Subject: [PATCH 771/777] Add util to check if permission has system signature Bug: 294777050 Test: m Change-Id: I66e94595ce5f4ab3b4f372e4e5e6cb06dc686c21 --- .../net/module/util/PermissionUtils.java | 22 +++ .../net/module/util/PermissionUtilsTest.kt | 129 ++++++++++++------ 2 files changed, 108 insertions(+), 43 deletions(-) diff --git a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java index 8315b8f6f5..d5b4c90a9c 100644 --- a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java @@ -21,12 +21,15 @@ import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; import static android.Manifest.permission.NETWORK_STACK; import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.content.pm.PermissionInfo.PROTECTION_SIGNATURE; import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PermissionInfo; import android.os.Binder; import java.io.PrintWriter; @@ -53,6 +56,25 @@ public final class PermissionUtils { return false; } + /** + * Return true if the permission has system signature. + */ + public static boolean isSystemSignaturePermission(@NonNull Context context, + @NonNull String permission) { + try { + PermissionInfo permissionInfo = context.getPackageManager().getPermissionInfo( + permission, 0 /* flags */); + if (permissionInfo == null) { + return false; + } + return "android".equals(permissionInfo.packageName) + && permissionInfo.getProtection() == PROTECTION_SIGNATURE; + } catch (PackageManager.NameNotFoundException ignored) { + // Ignored the NameNotFoundException and return false + } + return false; + } + /** * Return true if the context has one of give permission that is allowed * for a particular process and user ID running in the system. diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt index 1b6cbcb0dc..028308b3ad 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt @@ -16,96 +16,115 @@ package com.android.net.module.util +import android.Manifest.permission.INTERNET +import android.Manifest.permission.NETWORK_SETTINGS import android.Manifest.permission.NETWORK_STACK import android.content.Context import android.content.pm.PackageManager import android.content.pm.PackageManager.PERMISSION_DENIED import android.content.pm.PackageManager.PERMISSION_GRANTED import android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK +import android.os.Build import androidx.test.filters.SmallTest -import androidx.test.runner.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry import com.android.net.module.util.PermissionUtils.checkAnyPermissionOf import com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf import com.android.net.module.util.PermissionUtils.enforceNetworkStackPermission import com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr import com.android.net.module.util.PermissionUtils.enforceSystemFeature +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRunner +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertTrue import org.junit.Assert -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers import org.mockito.ArgumentMatchers.any import org.mockito.Mockito.doReturn import org.mockito.Mockito.mock -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith /** Tests for PermissionUtils */ -@RunWith(AndroidJUnit4::class) +@RunWith(DevSdkIgnoreRunner::class) @SmallTest class PermissionUtilsTest { + @get:Rule + val ignoreRule = DevSdkIgnoreRule() private val TEST_PERMISSION1 = "android.permission.TEST_PERMISSION1" private val TEST_PERMISSION2 = "android.permission.TEST_PERMISSION2" - private val context = mock(Context::class.java) - private val packageManager = mock(PackageManager::class.java) + private val mockContext = mock(Context::class.java) + private val mockPackageManager = mock(PackageManager::class.java) + + private val context by lazy { InstrumentationRegistry.getInstrumentation().context } @Before fun setup() { - doReturn(packageManager).`when`(context).packageManager + doReturn(mockPackageManager).`when`(mockContext).packageManager } @Test fun testEnforceAnyPermissionOf() { - doReturn(PERMISSION_GRANTED).`when`(context).checkCallingOrSelfPermission(TEST_PERMISSION1) - doReturn(PERMISSION_DENIED).`when`(context).checkCallingOrSelfPermission(TEST_PERMISSION2) - assertTrue(checkAnyPermissionOf(context, TEST_PERMISSION1, TEST_PERMISSION2)) - enforceAnyPermissionOf(context, TEST_PERMISSION1, TEST_PERMISSION2) + doReturn(PERMISSION_GRANTED).`when`(mockContext) + .checkCallingOrSelfPermission(TEST_PERMISSION1) + doReturn(PERMISSION_DENIED).`when`(mockContext) + .checkCallingOrSelfPermission(TEST_PERMISSION2) + assertTrue(checkAnyPermissionOf(mockContext, TEST_PERMISSION1, TEST_PERMISSION2)) + enforceAnyPermissionOf(mockContext, TEST_PERMISSION1, TEST_PERMISSION2) - doReturn(PERMISSION_DENIED).`when`(context).checkCallingOrSelfPermission(TEST_PERMISSION1) - doReturn(PERMISSION_GRANTED).`when`(context).checkCallingOrSelfPermission(TEST_PERMISSION2) - assertTrue(checkAnyPermissionOf(context, TEST_PERMISSION1, TEST_PERMISSION2)) - enforceAnyPermissionOf(context, TEST_PERMISSION1, TEST_PERMISSION2) + doReturn(PERMISSION_DENIED).`when`(mockContext) + .checkCallingOrSelfPermission(TEST_PERMISSION1) + doReturn(PERMISSION_GRANTED).`when`(mockContext) + .checkCallingOrSelfPermission(TEST_PERMISSION2) + assertTrue(checkAnyPermissionOf(mockContext, TEST_PERMISSION1, TEST_PERMISSION2)) + enforceAnyPermissionOf(mockContext, TEST_PERMISSION1, TEST_PERMISSION2) - doReturn(PERMISSION_DENIED).`when`(context).checkCallingOrSelfPermission(any()) - assertFalse(checkAnyPermissionOf(context, TEST_PERMISSION1, TEST_PERMISSION2)) + doReturn(PERMISSION_DENIED).`when`(mockContext).checkCallingOrSelfPermission(any()) + assertFalse(checkAnyPermissionOf(mockContext, TEST_PERMISSION1, TEST_PERMISSION2)) assertFailsWith("Expect fail but permission granted.") { - enforceAnyPermissionOf(context, TEST_PERMISSION1, TEST_PERMISSION2) } + enforceAnyPermissionOf(mockContext, TEST_PERMISSION1, TEST_PERMISSION2) + } } @Test fun testEnforceNetworkStackPermissionOr() { - doReturn(PERMISSION_GRANTED).`when`(context).checkCallingOrSelfPermission(NETWORK_STACK) - doReturn(PERMISSION_DENIED).`when`(context) - .checkCallingOrSelfPermission(PERMISSION_MAINLINE_NETWORK_STACK) - enforceNetworkStackPermission(context) - enforceNetworkStackPermissionOr(context, TEST_PERMISSION1) + doReturn(PERMISSION_GRANTED).`when`(mockContext).checkCallingOrSelfPermission(NETWORK_STACK) + doReturn(PERMISSION_DENIED).`when`(mockContext) + .checkCallingOrSelfPermission(PERMISSION_MAINLINE_NETWORK_STACK) + enforceNetworkStackPermission(mockContext) + enforceNetworkStackPermissionOr(mockContext, TEST_PERMISSION1) - doReturn(PERMISSION_DENIED).`when`(context).checkCallingOrSelfPermission(NETWORK_STACK) - doReturn(PERMISSION_GRANTED).`when`(context) - .checkCallingOrSelfPermission(PERMISSION_MAINLINE_NETWORK_STACK) - enforceNetworkStackPermission(context) - enforceNetworkStackPermissionOr(context, TEST_PERMISSION2) + doReturn(PERMISSION_DENIED).`when`(mockContext).checkCallingOrSelfPermission(NETWORK_STACK) + doReturn(PERMISSION_GRANTED).`when`(mockContext) + .checkCallingOrSelfPermission(PERMISSION_MAINLINE_NETWORK_STACK) + enforceNetworkStackPermission(mockContext) + enforceNetworkStackPermissionOr(mockContext, TEST_PERMISSION2) - doReturn(PERMISSION_DENIED).`when`(context).checkCallingOrSelfPermission(NETWORK_STACK) - doReturn(PERMISSION_DENIED).`when`(context) - .checkCallingOrSelfPermission(PERMISSION_MAINLINE_NETWORK_STACK) - doReturn(PERMISSION_GRANTED).`when`(context).checkCallingOrSelfPermission(TEST_PERMISSION1) + doReturn(PERMISSION_DENIED).`when`(mockContext).checkCallingOrSelfPermission(NETWORK_STACK) + doReturn(PERMISSION_DENIED).`when`(mockContext) + .checkCallingOrSelfPermission(PERMISSION_MAINLINE_NETWORK_STACK) + doReturn(PERMISSION_GRANTED).`when`(mockContext) + .checkCallingOrSelfPermission(TEST_PERMISSION1) assertFailsWith("Expect fail but permission granted.") { - enforceNetworkStackPermission(context) } - enforceNetworkStackPermissionOr(context, TEST_PERMISSION1) + enforceNetworkStackPermission(mockContext) + } + enforceNetworkStackPermissionOr(mockContext, TEST_PERMISSION1) - doReturn(PERMISSION_DENIED).`when`(context).checkCallingOrSelfPermission(any()) + doReturn(PERMISSION_DENIED).`when`(mockContext).checkCallingOrSelfPermission(any()) assertFailsWith("Expect fail but permission granted.") { - enforceNetworkStackPermission(context) } + enforceNetworkStackPermission(mockContext) + } assertFailsWith("Expect fail but permission granted.") { - enforceNetworkStackPermissionOr(context, TEST_PERMISSION2) } + enforceNetworkStackPermissionOr(mockContext, TEST_PERMISSION2) + } } private fun mockHasSystemFeature(featureName: String, hasFeature: Boolean) { - doReturn(hasFeature).`when`(packageManager) - .hasSystemFeature(ArgumentMatchers.eq(featureName)) + doReturn(hasFeature).`when`(mockPackageManager) + .hasSystemFeature(ArgumentMatchers.eq(featureName)) } @Test @@ -114,14 +133,38 @@ class PermissionUtilsTest { val exceptionMessage = "test exception message" mockHasSystemFeature(featureName = systemFeature, hasFeature = false) val e = assertFailsWith("Should fail without feature") { - enforceSystemFeature(context, systemFeature, exceptionMessage) } + enforceSystemFeature(mockContext, systemFeature, exceptionMessage) + } assertEquals(exceptionMessage, e.message) mockHasSystemFeature(featureName = systemFeature, hasFeature = true) try { - enforceSystemFeature(context, systemFeature, "") + enforceSystemFeature(mockContext, systemFeature, "") } catch (e: UnsupportedOperationException) { Assert.fail("Exception should have not been thrown with system feature enabled") } } + + @Test + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) + fun testIsSystemSignaturePermission() { + assertTrue( + PermissionUtils.isSystemSignaturePermission( + context, + NETWORK_SETTINGS + ) + ) + assertFalse( + PermissionUtils + .isSystemSignaturePermission(context, PERMISSION_MAINLINE_NETWORK_STACK) + ) + assertFalse( + PermissionUtils + .isSystemSignaturePermission(context, "test_permission") + ) + assertFalse( + PermissionUtils + .isSystemSignaturePermission(context, INTERNET) + ) + } } From 9209b0016403aea1e53258fece9071f589de7b8b Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Mon, 28 Aug 2023 17:37:30 +0900 Subject: [PATCH 772/777] Add isNetworkStackFeatureNotChickenedOut API for NetworkStack module. Bug: 279108992 Test: atest NetworkStaticLibsTests Change-Id: If42eb401b812017bd4d724b4323a8d51f7430606 --- .../net/module/util/DeviceConfigUtils.java | 39 +++++++++++++++---- .../module/util/DeviceConfigUtilsTest.java | 15 ++++++- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index caa2b05551..fb130f6740 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -17,6 +17,7 @@ package com.android.net.module.util; import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; +import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static android.provider.DeviceConfig.NAMESPACE_TETHERING; import static com.android.net.module.util.FeatureVersions.CONNECTIVITY_MODULE_ID; @@ -335,22 +336,44 @@ public final class DeviceConfigUtils { } /** - * Check whether one specific experimental feature in tethering module from {@link DeviceConfig} - * is not disabled. Feature can be disabled by setting a non-zero value in the property. - * If the feature is enabled by default and disabled by flag push (kill switch), this method - * should be used. - * If the feature is disabled by default and enabled by flag push, - * {@link #isTetheringFeatureEnabled} should be used. + * Check whether one specific experimental feature in specific namespace from + * {@link DeviceConfig} is not disabled. Feature can be disabled by setting a non-zero + * value in the property. If the feature is enabled by default and disabled by flag push + * (kill switch), this method should be used. If the feature is disabled by default and + * enabled by flag push, {@link #isFeatureEnabled} should be used. * + * @param namespace The namespace containing the property to look up. * @param name The name of the property to look up. * @return true if this feature is enabled, or false if disabled. */ - public static boolean isTetheringFeatureNotChickenedOut(String name) { - final int propertyVersion = getDeviceConfigPropertyInt(NAMESPACE_TETHERING, name, + private static boolean isFeatureNotChickenedOut(String namespace, String name) { + final int propertyVersion = getDeviceConfigPropertyInt(namespace, name, 0 /* default value */); return propertyVersion == 0; } + /** + * Check whether one specific experimental feature in Tethering module from {@link DeviceConfig} + * is not disabled. + * + * @param name The name of the property in tethering module to look up. + * @return true if this feature is enabled, or false if disabled. + */ + public static boolean isTetheringFeatureNotChickenedOut(String name) { + return isFeatureNotChickenedOut(NAMESPACE_TETHERING, name); + } + + /** + * Check whether one specific experimental feature in NetworkStack module from + * {@link DeviceConfig} is not disabled. + * + * @param name The name of the property in NetworkStack module to look up. + * @return true if this feature is enabled, or false if disabled. + */ + public static boolean isNetworkStackFeatureNotChickenedOut(String name) { + return isFeatureNotChickenedOut(NAMESPACE_CONNECTIVITY, name); + } + /** * Gets boolean config from resources. */ diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java index e80fa80a24..f259e687e0 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -17,6 +17,7 @@ package com.android.net.module.util; import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; +import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static android.provider.DeviceConfig.NAMESPACE_TETHERING; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -421,7 +422,7 @@ public class DeviceConfigUtilsTest { } @Test - public void testIsTetheringFeatureForceDisabled() throws Exception { + public void testIsTetheringFeatureNotChickenedOut() throws Exception { doReturn("0").when(() -> DeviceConfig.getProperty( eq(NAMESPACE_TETHERING), eq(TEST_EXPERIMENT_FLAG))); assertTrue(DeviceConfigUtils.isTetheringFeatureNotChickenedOut(TEST_EXPERIMENT_FLAG)); @@ -430,4 +431,16 @@ public class DeviceConfigUtilsTest { () -> DeviceConfig.getProperty(eq(NAMESPACE_TETHERING), eq(TEST_EXPERIMENT_FLAG))); assertFalse(DeviceConfigUtils.isTetheringFeatureNotChickenedOut(TEST_EXPERIMENT_FLAG)); } + + @Test + public void testIsNetworkStackFeatureNotChickenedOut() throws Exception { + doReturn("0").when(() -> DeviceConfig.getProperty( + eq(NAMESPACE_CONNECTIVITY), eq(TEST_EXPERIMENT_FLAG))); + assertTrue(DeviceConfigUtils.isNetworkStackFeatureNotChickenedOut(TEST_EXPERIMENT_FLAG)); + + doReturn(TEST_FLAG_VALUE_STRING).when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), + eq(TEST_EXPERIMENT_FLAG))); + assertFalse(DeviceConfigUtils.isNetworkStackFeatureNotChickenedOut(TEST_EXPERIMENT_FLAG)); + } } From 66d39cdccd9943a5d5348878fb1c523e825eb746 Mon Sep 17 00:00:00 2001 From: Mark White Date: Mon, 7 Aug 2023 15:20:07 +0000 Subject: [PATCH 773/777] Created empty framework-location non-updatable module Bug: 289776578 Test: m CtsLocationCoarseTestCases CtsLocationFineTestCases CtsLocationGnssTestCases CtsLocationNoneTestCases CtsLocationPrivilegedTestCases Change-Id: I6922384386e6e6467484d20f6db74a4e49209374 --- staticlibs/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 0b42219c64..d8d0accb19 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -246,6 +246,7 @@ java_library { "framework-annotations-lib", "framework-connectivity.stubs.module_lib", "framework-connectivity-t.stubs.module_lib", + "framework-location.stubs.module_lib", ], jarjar_rules: "jarjar-rules-shared.txt", visibility: [ From e2eff036edeb63cfba5bd9f60729c35a719caabd Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Fri, 25 Aug 2023 16:15:00 +0800 Subject: [PATCH 774/777] Make structs in StructTest accessible from Struct After link Struct statically into framework-connectivity, the structs in StructTest are no longer accessible from Struct because Struct is loaded by bootclasspath classloader. Make classes and members public for accessing from Struct. Test: atest ConnectivityCoverageTests:android.net.connectivity.com.android.net.module.util.StructTest Bug: 297836825 Change-Id: I3b1f466f10247306c84d6cac0d7402353770fac4 --- .../android/net/module/util/StructTest.java | 144 +++++++++--------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java index 4e46210649..b4da043953 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java @@ -89,20 +89,20 @@ public class StructTest { return Struct.parse(clazz, buf); } - static class HeaderMsgWithConstructor extends Struct { + public static class HeaderMsgWithConstructor extends Struct { static int sType; static int sLength; @Field(order = 0, type = Type.U8, padding = 1) - final short mFamily; + public final short mFamily; @Field(order = 1, type = Type.U16) - final int mLen; + public final int mLen; @Field(order = 2, type = Type.S32) - final int mIfindex; + public final int mIfindex; @Field(order = 3, type = Type.U8) - final short mIcmpType; + public final short mIcmpType; @Field(order = 4, type = Type.U8, padding = 6) - final short mIcmpCode; + public final short mIcmpCode; HeaderMsgWithConstructor(final short family, final int len, final int ifindex, final short type, final short code) { @@ -133,20 +133,20 @@ public class StructTest { verifyHeaderParsing(msg); } - static class HeaderMsgWithoutConstructor extends Struct { + public static class HeaderMsgWithoutConstructor extends Struct { static int sType; static int sLength; @Field(order = 0, type = Type.U8, padding = 1) - short mFamily; + public short mFamily; @Field(order = 1, type = Type.U16) - int mLen; + public int mLen; @Field(order = 2, type = Type.S32) - int mIfindex; + public int mIfindex; @Field(order = 3, type = Type.U8) - short mIcmpType; + public short mIcmpType; @Field(order = 4, type = Type.U8, padding = 6) - short mIcmpCode; + public short mIcmpCode; } @Test @@ -164,7 +164,7 @@ public class StructTest { msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); } - static class HeaderMessage { + public static class HeaderMessage { @Field(order = 0, type = Type.U8, padding = 1) short mFamily; @Field(order = 1, type = Type.U16) @@ -183,7 +183,7 @@ public class StructTest { assertThrows(IllegalArgumentException.class, () -> Struct.parse(HeaderMessage.class, buf)); } - static class HeaderMessageMissingAnnotation extends Struct { + public static class HeaderMessageMissingAnnotation extends Struct { @Field(order = 0, type = Type.U8, padding = 1) short mFamily; @Field(order = 1, type = Type.U16) @@ -202,15 +202,15 @@ public class StructTest { () -> Struct.parse(HeaderMessageMissingAnnotation.class, buf)); } - static class NetworkOrderMessage extends Struct { + public static class NetworkOrderMessage extends Struct { @Field(order = 0, type = Type.UBE16) - final int mUBE16; + public final int mUBE16; @Field(order = 1, type = Type.UBE32) - final long mUBE32; + public final long mUBE32; @Field(order = 2, type = Type.UBE64) - final BigInteger mUBE64; + public final BigInteger mUBE64; @Field(order = 3, type = Type.UBE63) - final long mUBE63; + public final long mUBE63; NetworkOrderMessage(final int be16, final long be32, final BigInteger be64, final long be63) { @@ -235,19 +235,19 @@ public class StructTest { msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); } - static class UnsignedDataMessage extends Struct { + public static class UnsignedDataMessage extends Struct { @Field(order = 0, type = Type.U8) - final short mU8; + public final short mU8; @Field(order = 1, type = Type.U16) - final int mU16; + public final int mU16; @Field(order = 2, type = Type.U32) - final long mU32; + public final long mU32; @Field(order = 3, type = Type.U64) - final BigInteger mU64; + public final BigInteger mU64; @Field(order = 4, type = Type.U63) - final long mU63; + public final long mU63; @Field(order = 5, type = Type.U63) - final long mLU64; // represent U64 data with U63 type + public final long mLU64; // represent U64 data with U63 type UnsignedDataMessage(final short u8, final int u16, final long u32, final BigInteger u64, final long u63, final long lu64) { @@ -276,7 +276,7 @@ public class StructTest { msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); } - static class U64DataMessage extends Struct { + public static class U64DataMessage extends Struct { @Field(order = 0, type = Type.U64) long mU64; } @@ -290,10 +290,10 @@ public class StructTest { private static final String SMALL_VALUE_BIGINTEGER = "3412000000000000" + "0000000000001234" + "0000000000000000"; - static class SmallValueBigInteger extends Struct { - @Field(order = 0, type = Type.U64) final BigInteger mSmallValue; - @Field(order = 1, type = Type.UBE64) final BigInteger mBSmallValue; - @Field(order = 2, type = Type.U64) final BigInteger mZero; + public static class SmallValueBigInteger extends Struct { + @Field(order = 0, type = Type.U64) public final BigInteger mSmallValue; + @Field(order = 1, type = Type.UBE64) public final BigInteger mBSmallValue; + @Field(order = 2, type = Type.U64) public final BigInteger mZero; SmallValueBigInteger(final BigInteger smallValue, final BigInteger bSmallValue, final BigInteger zero) { @@ -316,15 +316,15 @@ public class StructTest { msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); } - static class SignedDataMessage extends Struct { + public static class SignedDataMessage extends Struct { @Field(order = 0, type = Type.S8) - final byte mS8; + public final byte mS8; @Field(order = 1, type = Type.S16) - final short mS16; + public final short mS16; @Field(order = 2, type = Type.S32) - final int mS32; + public final int mS32; @Field(order = 3, type = Type.S64) - final long mS64; + public final long mS64; SignedDataMessage(final byte s8, final short s16, final int s32, final long s64) { mS8 = s8; @@ -362,7 +362,7 @@ public class StructTest { msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); } - static class HeaderMessageWithDuplicateOrder extends Struct { + public static class HeaderMessageWithDuplicateOrder extends Struct { @Field(order = 0, type = Type.U8, padding = 1) short mFamily; @Field(order = 1, type = Type.U16) @@ -382,7 +382,7 @@ public class StructTest { () -> Struct.parse(HeaderMessageWithDuplicateOrder.class, buf)); } - static class HeaderMessageWithNegativeOrder extends Struct { + public static class HeaderMessageWithNegativeOrder extends Struct { @Field(order = 0, type = Type.U8, padding = 1) short mFamily; @Field(order = 1, type = Type.U16) @@ -402,7 +402,7 @@ public class StructTest { () -> Struct.parse(HeaderMessageWithNegativeOrder.class, buf)); } - static class HeaderMessageOutOfIndexBounds extends Struct { + public static class HeaderMessageOutOfIndexBounds extends Struct { @Field(order = 0, type = Type.U8, padding = 1) short mFamily; @Field(order = 1, type = Type.U16) @@ -422,7 +422,7 @@ public class StructTest { () -> Struct.parse(HeaderMessageOutOfIndexBounds.class, buf)); } - static class HeaderMessageMismatchedPrimitiveType extends Struct { + public static class HeaderMessageMismatchedPrimitiveType extends Struct { @Field(order = 0, type = Type.U8, padding = 1) short mFamily; @Field(order = 1, type = Type.U16) @@ -442,11 +442,11 @@ public class StructTest { () -> Struct.parse(HeaderMessageMismatchedPrimitiveType.class, buf)); } - static class PrefixMessage extends Struct { + public static class PrefixMessage extends Struct { @Field(order = 0, type = Type.UBE16) - final int mLifetime; + public final int mLifetime; @Field(order = 1, type = Type.ByteArray, arraysize = 12) - final byte[] mPrefix; + public final byte[] mPrefix; PrefixMessage(final int lifetime, final byte[] prefix) { mLifetime = lifetime; @@ -469,7 +469,7 @@ public class StructTest { msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); } - static class PrefixMessageWithZeroLengthArray extends Struct { + public static class PrefixMessageWithZeroLengthArray extends Struct { @Field(order = 0, type = Type.UBE16) final int mLifetime; @Field(order = 1, type = Type.ByteArray, arraysize = 0) @@ -495,7 +495,7 @@ public class StructTest { verifyPrefixByteArrayParsing(msg); } - static class HeaderMessageWithMutableField extends Struct { + public static class HeaderMessageWithMutableField extends Struct { @Field(order = 0, type = Type.U8, padding = 1) final short mFamily; @Field(order = 1, type = Type.U16) @@ -521,20 +521,20 @@ public class StructTest { () -> Struct.parse(HeaderMessageWithMutableField.class, buf)); } - static class HeaderMsgWithStaticConstant extends Struct { + public static class HeaderMsgWithStaticConstant extends Struct { private static final String TAG = "HeaderMessage"; private static final int FIELD_COUNT = 5; @Field(order = 0, type = Type.U8, padding = 1) - final short mFamily; + public final short mFamily; @Field(order = 1, type = Type.U16) - final int mLen; + public final int mLen; @Field(order = 2, type = Type.S32) - final int mIfindex; + public final int mIfindex; @Field(order = 3, type = Type.U8) - final short mIcmpType; + public final short mIcmpType; @Field(order = 4, type = Type.U8, padding = 6) - final short mIcmpCode; + public final short mIcmpCode; HeaderMsgWithStaticConstant(final short family, final int len, final int ifindex, final short type, final short code) { @@ -561,7 +561,7 @@ public class StructTest { msg.writeToBytes(ByteOrder.LITTLE_ENDIAN)); } - static class MismatchedConstructor extends Struct { + public static class MismatchedConstructor extends Struct { @Field(order = 0, type = Type.U16) final int mInt1; @Field(order = 1, type = Type.U16) final int mInt2; MismatchedConstructor(String int1, String int2) { @@ -577,9 +577,9 @@ public class StructTest { () -> Struct.parse(MismatchedConstructor.class, buf)); } - static class ClassWithTwoConstructors extends Struct { - @Field(order = 0, type = Type.U16) final int mInt1; - @Field(order = 1, type = Type.U16) final int mInt2; + public static class ClassWithTwoConstructors extends Struct { + @Field(order = 0, type = Type.U16) public final int mInt1; + @Field(order = 1, type = Type.U16) public final int mInt2; ClassWithTwoConstructors(String int1, String int2) { mInt1 = Integer.valueOf(int1); mInt2 = Integer.valueOf(int2); @@ -645,14 +645,14 @@ public class StructTest { } } - static class BigEndianDataMessage extends Struct { - @Field(order = 0, type = Type.S32) int mInt1; - @Field(order = 1, type = Type.S32) int mInt2; - @Field(order = 2, type = Type.UBE16) int mInt3; - @Field(order = 3, type = Type.U16) int mInt4; - @Field(order = 4, type = Type.U64) BigInteger mBigInteger1; - @Field(order = 5, type = Type.UBE64) BigInteger mBigInteger2; - @Field(order = 6, type = Type.S64) long mLong; + public static class BigEndianDataMessage extends Struct { + @Field(order = 0, type = Type.S32) public int mInt1; + @Field(order = 1, type = Type.S32) public int mInt2; + @Field(order = 2, type = Type.UBE16) public int mInt3; + @Field(order = 3, type = Type.U16) public int mInt4; + @Field(order = 4, type = Type.U64) public BigInteger mBigInteger1; + @Field(order = 5, type = Type.UBE64) public BigInteger mBigInteger2; + @Field(order = 6, type = Type.S64) public long mLong; } private static final String BIG_ENDIAN_DATA = "00000001" + "fffffffe" + "fffe" + "fffe" @@ -680,9 +680,9 @@ public class StructTest { return ByteBuffer.wrap(HexDump.hexStringToByteArray(hexString)); } - static class MacAddressMessage extends Struct { - @Field(order = 0, type = Type.EUI48) final MacAddress mMac1; - @Field(order = 1, type = Type.EUI48) final MacAddress mMac2; + public static class MacAddressMessage extends Struct { + public @Field(order = 0, type = Type.EUI48) final MacAddress mMac1; + public @Field(order = 1, type = Type.EUI48) final MacAddress mMac2; MacAddressMessage(final MacAddress mac1, final MacAddress mac2) { this.mMac1 = mac1; @@ -703,7 +703,7 @@ public class StructTest { msg.writeToBytes(ByteOrder.BIG_ENDIAN)); } - static class BadMacAddressType extends Struct { + public static class BadMacAddressType extends Struct { @Field(order = 0, type = Type.EUI48) byte[] mMac; } @@ -742,7 +742,7 @@ public class StructTest { assertArrayEquals(toByteBuffer(hexString).array(), msg.writeToBytes()); } - static class IpAddressMessage extends Struct { + public static class IpAddressMessage extends Struct { @Field(order = 0, type = Type.Ipv4Address) public final Inet4Address ipv4Address; @Field(order = 1, type = Type.Ipv6Address) public final Inet6Address ipv6Address; @@ -765,7 +765,7 @@ public class StructTest { msg.writeToBytes(ByteOrder.BIG_ENDIAN)); } - static class WrongIpAddressType extends Struct { + public static class WrongIpAddressType extends Struct { @Field(order = 0, type = Type.Ipv4Address) public byte[] ipv4Address; @Field(order = 1, type = Type.Ipv6Address) public byte[] ipv6Address; } @@ -777,7 +777,7 @@ public class StructTest { toByteBuffer("c0a86401" + "20010db8000300040005000600070008"))); } - static class FullTypeMessage extends Struct { + public static class FullTypeMessage extends Struct { @Field(order = 0, type = Type.U8) public final short u8; @Field(order = 1, type = Type.U16) public final int u16; @Field(order = 2, type = Type.U32) public final long u32; @@ -886,7 +886,7 @@ public class StructTest { assertTrue(msg.equals(msg1)); } - static class FullTypeMessageWithDupType extends Struct { + public static class FullTypeMessageWithDupType extends Struct { @Field(order = 0, type = Type.U8) public final short u8; @Field(order = 1, type = Type.U16) public final int u16; @Field(order = 2, type = Type.U32) public final long u32; @@ -1029,7 +1029,7 @@ public class StructTest { assertEquals(msg.hashCode(), msg1.hashCode()); } - static class InvalidByteArray extends Struct { + public static class InvalidByteArray extends Struct { @Field(order = 0, type = Type.ByteArray, arraysize = 12) public byte[] bytes; } From 6a22207190409013fc332e5f1d6033ce14f21484 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Tue, 15 Aug 2023 16:28:34 +0900 Subject: [PATCH 775/777] Remove unnecessary arguments from isTetheringFeatureEnabled Test: m Bug: 279108992 Change-Id: Iadc1b4665c364bf754ed32e7bb53b78e555ed457 --- .../net/module/util/DeviceConfigUtils.java | 20 ++--- .../module/util/DeviceConfigUtilsTest.java | 76 +++++++++---------- 2 files changed, 44 insertions(+), 52 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index fb130f6740..771d44fa9e 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -200,24 +200,20 @@ public final class DeviceConfigUtils { * * This is useful to ensure that if a module install is rolled back, flags are not left fully * rolled out on a version where they have not been well tested. + * + * If the feature is disabled by default and enabled by flag push, this method should be used. + * If the feature is enabled by default and disabled by flag push (kill switch), + * {@link #isTetheringFeatureNotChickenedOut(String)} should be used. + * * @param context The global context information about an app environment. - * @param namespace The namespace containing the property to look up. * @param name The name of the property to look up. - * @param moduleName The mainline module name which is released as apex. - * @param defaultEnabled The value to return if the property does not exist or its value is - * null. * @return true if this feature is enabled, or false if disabled. */ public static boolean isTetheringFeatureEnabled(@NonNull Context context, - @NonNull String namespace, @NonNull String name, @NonNull String moduleName, - boolean defaultEnabled) { - // TODO: migrate callers to a non-generic isTetheringFeatureEnabled method. - if (!TETHERING_MODULE_NAME.equals(moduleName)) { - throw new IllegalArgumentException( - "This method is only usable by the tethering module"); - } + @NonNull String name) { final long packageVersion = getTetheringModuleVersion(context); - return isFeatureEnabled(context, packageVersion, namespace, name, defaultEnabled); + return isFeatureEnabled(context, packageVersion, NAMESPACE_TETHERING, name, + false /* defaultEnabled */); } private static boolean isFeatureEnabled(@NonNull Context context, long packageVersion, diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java index f259e687e0..7a71a4ae1e 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -84,7 +84,6 @@ public class DeviceConfigUtilsTest { // that manifest, and is reflected in android.content.pm.ApplicationInfo. Contrary to the APEX // (module) name, different package names are typically used to identify the organization that // built and signed the APEX modules. - private static final String TEST_APEX_NAME = "com.android.tethering"; private static final String TEST_APEX_PACKAGE_NAME = "com.prefix.android.tethering"; private static final String TEST_GO_APEX_PACKAGE_NAME = "com.prefix.android.go.tethering"; private static final String TEST_CONNRES_PACKAGE_NAME = @@ -230,24 +229,24 @@ public class DeviceConfigUtilsTest { @Test public void testFeatureIsEnabled() { - doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), - eq(TEST_EXPERIMENT_FLAG))); + doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG)); + doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING, + TEST_EXPERIMENT_FLAG)); assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); - assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); } @Test public void testFeatureDefaultEnabled() { - doReturn(null).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), - eq(TEST_EXPERIMENT_FLAG))); + doReturn(null).when(() -> DeviceConfig.getProperty(TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG)); + doReturn(null).when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING, + TEST_EXPERIMENT_FLAG)); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); - assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); - assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, true /* defaultEnabled */)); + assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); } @Test @@ -255,32 +254,33 @@ public class DeviceConfigUtilsTest { doThrow(NameNotFoundException.class).when(mPm).getPackageInfo(anyString(), anyInt()); // Feature should be enabled by flag value "1". - doReturn("1").when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), - eq(TEST_EXPERIMENT_FLAG))); + doReturn("1").when(() -> DeviceConfig.getProperty(TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG)); + doReturn("1").when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING, + TEST_EXPERIMENT_FLAG)); assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); - assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); // Feature should be disabled by flag value "999999999". - doReturn("999999999").when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), - eq(TEST_EXPERIMENT_FLAG))); + doReturn("999999999").when(() -> DeviceConfig.getProperty(TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG)); + doReturn("999999999").when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING, + TEST_EXPERIMENT_FLAG)); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); - assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); // Follow defaultEnabled if the flag is not set - doReturn(null).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), - eq(TEST_EXPERIMENT_FLAG))); + doReturn(null).when(() -> DeviceConfig.getProperty(TEST_NAME_SPACE, + TEST_EXPERIMENT_FLAG)); + doReturn(null).when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING, + TEST_EXPERIMENT_FLAG)); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, false /* defaultEnabled */)); assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, true /* defaultEnabled */)); - assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); - assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, true /* defaultEnabled */)); + assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); } @Test @@ -290,19 +290,17 @@ public class DeviceConfigUtilsTest { doReturn(mApexPackageInfo).when(mPm).getPackageInfo( eq(TEST_GO_APEX_PACKAGE_NAME), anyInt()); doReturn("0").when(() -> DeviceConfig.getProperty( - eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG))); + TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); + doReturn("0").when(() -> DeviceConfig.getProperty( + NAMESPACE_TETHERING, TEST_EXPERIMENT_FLAG)); assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); - assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); - assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, true /* defaultEnabled */)); + assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); - doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), - eq(TEST_EXPERIMENT_FLAG))); - assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING, + TEST_EXPERIMENT_FLAG)); + assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); } @Test @@ -322,12 +320,10 @@ public class DeviceConfigUtilsTest { @Test public void testFeatureIsEnabledCaching_APEX() throws Exception { - doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), - eq(TEST_EXPERIMENT_FLAG))); - assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); - assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, TEST_APEX_NAME, false /* defaultEnabled */)); + doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING, + TEST_EXPERIMENT_FLAG)); + assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); + assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); // Package info is only queried once verify(mPm, times(1)).getPackageInfo(anyString(), anyInt()); From e323c1db813147ace0c0255d3d86a7634a6e7407 Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Tue, 15 Aug 2023 17:27:47 +0900 Subject: [PATCH 776/777] Rename to isNetworkStackFeatureEnabled DeviceConfigUtils had isFeatureEnabled for NetworkStack and Tethering which were confusing since the difference was only the arguments. This CL renames isFeatureEnabled for NetworkStack module to isNetworkStackFeatureEnabled to avoid confusion. This CL also removes unnecessary arguments. Bug: 279108992 Test: m Change-Id: I523b98bd3754c209c64ce7d1513b5afcb36599b9 --- .../net/module/util/DeviceConfigUtils.java | 11 ++-- .../module/util/DeviceConfigUtilsTest.java | 53 +++++++++---------- 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java index 771d44fa9e..e646f37a6e 100644 --- a/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java +++ b/staticlibs/device/com/android/net/module/util/DeviceConfigUtils.java @@ -162,13 +162,12 @@ public final class DeviceConfigUtils { * This is useful to ensure that if a module install is rolled back, flags are not left fully * rolled out on a version where they have not been well tested. * @param context The global context information about an app environment. - * @param namespace The namespace containing the property to look up. * @param name The name of the property to look up. * @return true if this feature is enabled, or false if disabled. */ - public static boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, + public static boolean isNetworkStackFeatureEnabled(@NonNull Context context, @NonNull String name) { - return isFeatureEnabled(context, namespace, name, false /* defaultEnabled */); + return isNetworkStackFeatureEnabled(context, name, false /* defaultEnabled */); } /** @@ -180,16 +179,16 @@ public final class DeviceConfigUtils { * This is useful to ensure that if a module install is rolled back, flags are not left fully * rolled out on a version where they have not been well tested. * @param context The global context information about an app environment. - * @param namespace The namespace containing the property to look up. * @param name The name of the property to look up. * @param defaultEnabled The value to return if the property does not exist or its value is * null. * @return true if this feature is enabled, or false if disabled. */ - public static boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, + public static boolean isNetworkStackFeatureEnabled(@NonNull Context context, @NonNull String name, boolean defaultEnabled) { final long packageVersion = getPackageVersion(context); - return isFeatureEnabled(context, packageVersion, namespace, name, defaultEnabled); + return isFeatureEnabled(context, packageVersion, NAMESPACE_CONNECTIVITY, name, + defaultEnabled); } /** diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java index 7a71a4ae1e..5a96bcbb04 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java +++ b/staticlibs/tests/unit/src/com/android/net/module/util/DeviceConfigUtilsTest.java @@ -228,24 +228,26 @@ public class DeviceConfigUtilsTest { } @Test - public void testFeatureIsEnabled() { - doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(TEST_NAME_SPACE, + public void testIsNetworkStackFeatureEnabled() { + doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, TEST_EXPERIMENT_FLAG)); + assertTrue(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); + } + + @Test + public void testIsTetheringFeatureEnabled() { doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING, TEST_EXPERIMENT_FLAG)); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG)); assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); } @Test public void testFeatureDefaultEnabled() { - doReturn(null).when(() -> DeviceConfig.getProperty(TEST_NAME_SPACE, + doReturn(null).when(() -> DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, TEST_EXPERIMENT_FLAG)); doReturn(null).when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING, TEST_EXPERIMENT_FLAG)); - assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG)); + assertFalse(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); } @@ -254,32 +256,30 @@ public class DeviceConfigUtilsTest { doThrow(NameNotFoundException.class).when(mPm).getPackageInfo(anyString(), anyInt()); // Feature should be enabled by flag value "1". - doReturn("1").when(() -> DeviceConfig.getProperty(TEST_NAME_SPACE, + doReturn("1").when(() -> DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, TEST_EXPERIMENT_FLAG)); doReturn("1").when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING, TEST_EXPERIMENT_FLAG)); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG)); + assertTrue(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); // Feature should be disabled by flag value "999999999". - doReturn("999999999").when(() -> DeviceConfig.getProperty(TEST_NAME_SPACE, + doReturn("999999999").when(() -> DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, TEST_EXPERIMENT_FLAG)); doReturn("999999999").when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING, TEST_EXPERIMENT_FLAG)); - assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG)); + assertFalse(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); // Follow defaultEnabled if the flag is not set - doReturn(null).when(() -> DeviceConfig.getProperty(TEST_NAME_SPACE, + doReturn(null).when(() -> DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, TEST_EXPERIMENT_FLAG)); doReturn(null).when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING, TEST_EXPERIMENT_FLAG)); - assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, false /* defaultEnabled */)); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG, true /* defaultEnabled */)); + assertFalse(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG, + false /* defaultEnabled */)); + assertTrue(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG, + true /* defaultEnabled */)); assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); } @@ -290,12 +290,11 @@ public class DeviceConfigUtilsTest { doReturn(mApexPackageInfo).when(mPm).getPackageInfo( eq(TEST_GO_APEX_PACKAGE_NAME), anyInt()); doReturn("0").when(() -> DeviceConfig.getProperty( - TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG)); + NAMESPACE_CONNECTIVITY, TEST_EXPERIMENT_FLAG)); doReturn("0").when(() -> DeviceConfig.getProperty( NAMESPACE_TETHERING, TEST_EXPERIMENT_FLAG)); - assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG)); + assertFalse(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); assertFalse(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING, @@ -304,13 +303,11 @@ public class DeviceConfigUtilsTest { } @Test - public void testFeatureIsEnabledCaching_APK() throws Exception { - doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE), - eq(TEST_EXPERIMENT_FLAG))); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, - TEST_EXPERIMENT_FLAG)); - assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE, + public void testIsNetworkStackFeatureEnabledCaching() throws Exception { + doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, TEST_EXPERIMENT_FLAG)); + assertTrue(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); + assertTrue(DeviceConfigUtils.isNetworkStackFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); // Package info is only queried once verify(mContext, times(1)).getPackageManager(); @@ -319,7 +316,7 @@ public class DeviceConfigUtilsTest { } @Test - public void testFeatureIsEnabledCaching_APEX() throws Exception { + public void testIsTetheringFeatureEnabledCaching() throws Exception { doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(NAMESPACE_TETHERING, TEST_EXPERIMENT_FLAG)); assertTrue(DeviceConfigUtils.isTetheringFeatureEnabled(mContext, TEST_EXPERIMENT_FLAG)); From 325f675273d9f20252674d56ce74ea8e74169806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 6 Sep 2023 23:50:47 +0000 Subject: [PATCH 777/777] fix a compile warning about out of order field init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit http://cs/h/prodkernel/kernel/upstream/torvalds/linux-2.6/+/master:tools/include/uapi/linux/bpf.h?l=1486 struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */ __u32 prog_fd; __u32 retval; __u32 data_size_in; __u32 data_size_out; __aligned_u64 data_in; __aligned_u64 data_out; ... Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I2c08b65bdcdbd7fb9872b6d4cbbf542fe28ef916 --- .../native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h index ba16d53cb7..13f7cb396c 100644 --- a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h +++ b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h @@ -175,8 +175,8 @@ inline int runProgram(const BPF_FD_TYPE prog_fd, const void* data, return bpf(BPF_PROG_RUN, { .test = { .prog_fd = BPF_FD_TO_U32(prog_fd), - .data_in = ptr_to_u64(data), .data_size_in = data_size, + .data_in = ptr_to_u64(data), }, }); }