Merge "Avoid fd to be closed by ParcelFileDescriptor's finalizer" into main
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp
index 19dd492..3e7c697 100644
--- a/Tethering/apex/Android.bp
+++ b/Tethering/apex/Android.bp
@@ -111,7 +111,7 @@
],
prebuilts: [
"current_sdkinfo",
- "netbpfload.33rc",
+ "netbpfload.31rc",
"netbpfload.35rc",
"ot-daemon.34rc",
],
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index b50831d..e37c5db 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -708,8 +708,7 @@
// If tethering is already enabled with a different request,
// disable before re-enabling.
if (unfinishedRequest != null && !unfinishedRequest.equalsIgnoreUidPackage(request)) {
- enableTetheringInternal(false /* disabled */, unfinishedRequest, null);
- mEntitlementMgr.stopProvisioningIfNeeded(type);
+ stopTetheringInternal(type);
}
mPendingTetheringRequests.put(type, request);
@@ -1152,7 +1151,10 @@
} catch (RemoteException e) { }
}
- final TetheringRequest request = createLegacyGlobalScopeTetheringRequest(type);
+ TetheringRequest request = getPendingTetheringRequest(type);
+ if (request == null) {
+ request = createLegacyGlobalScopeTetheringRequest(type);
+ }
int result = tetherInternal(request, iface);
switch (type) {
case TETHERING_WIFI:
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
index b3e9c1b..3c91a1b 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
@@ -130,9 +130,6 @@
public static final String TETHER_ENABLE_WEAR_TETHERING =
"tether_enable_wear_tethering";
- public static final String TETHER_FORCE_RANDOM_PREFIX_BASE_SELECTION =
- "tether_force_random_prefix_base_selection";
-
public static final String TETHER_ENABLE_SYNC_SM = "tether_enable_sync_sm";
/**
@@ -142,7 +139,7 @@
public static final int DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS = 5000;
/** A flag for using synchronous or asynchronous state machine. */
- public static boolean USE_SYNC_SM = false;
+ public static boolean USE_SYNC_SM = true;
/**
* A feature flag to control whether the active sessions metrics should be enabled.
@@ -195,6 +192,10 @@
return DeviceConfigUtils.isTetheringFeatureEnabled(context, name);
}
+ boolean isFeatureNotChickenedOut(@NonNull Context context, @NonNull String name) {
+ return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(context, name);
+ }
+
boolean getDeviceConfigBoolean(@NonNull String namespace, @NonNull String name,
boolean defaultValue) {
return DeviceConfig.getBoolean(namespace, name, defaultValue);
@@ -394,7 +395,7 @@
* use the async state machine.
*/
public void readEnableSyncSM(final Context ctx) {
- USE_SYNC_SM = mDeps.isFeatureEnabled(ctx, TETHER_ENABLE_SYNC_SM);
+ USE_SYNC_SM = mDeps.isFeatureNotChickenedOut(ctx, TETHER_ENABLE_SYNC_SM);
}
/** Does the dumping.*/
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/FakeTetheringConfiguration.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/FakeTetheringConfiguration.java
index 087be26..c97fa3d 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/FakeTetheringConfiguration.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/FakeTetheringConfiguration.java
@@ -33,6 +33,11 @@
}
@Override
+ boolean isFeatureNotChickenedOut(@NonNull Context context, @NonNull String name) {
+ return true;
+ }
+
+ @Override
boolean getDeviceConfigBoolean(@NonNull String namespace, @NonNull String name,
boolean defaultValue) {
return defaultValue;
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
index f9e3a6a..ada88fb 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
@@ -26,7 +26,6 @@
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
import static android.net.ip.IpServer.CMD_NOTIFY_PREFIX_CONFLICT;
-import static com.android.net.module.util.PrivateAddressCoordinator.TETHER_FORCE_RANDOM_PREFIX_BASE_SELECTION;
import static com.android.networkstack.tethering.util.PrefixUtils.asIpPrefix;
import static org.junit.Assert.assertEquals;
@@ -51,6 +50,7 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.ip.IpServer;
+import android.os.Build;
import android.os.IBinder;
import androidx.test.filters.SmallTest;
@@ -58,8 +58,10 @@
import com.android.net.module.util.IIpv4PrefixRequest;
import com.android.net.module.util.PrivateAddressCoordinator;
+import com.android.testutils.DevSdkIgnoreRule;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -71,6 +73,9 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public final class PrivateAddressCoordinatorTest {
+ @Rule
+ public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
+
private static final String TEST_IFNAME = "test0";
@Mock private IpServer mHotspotIpServer;
@@ -231,11 +236,9 @@
assertEquals(usbAddress, newUsbAddress);
final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork,
- new LinkAddress("192.168.88.23/16"), null,
- makeNetworkCapabilities(TRANSPORT_WIFI));
+ hotspotAddress, null, makeNetworkCapabilities(TRANSPORT_WIFI));
updateUpstreamPrefix(wifiUpstream);
verify(mHotspotIpServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
- verify(mUsbIpServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
}
private UpstreamNetworkState buildUpstreamNetworkState(final Network network,
@@ -323,10 +326,9 @@
assertFalse(localHotspotPrefix.containsPrefix(hotspotPrefix));
}
+ @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@Test
public void testStartedPrefixRange() throws Exception {
- when(mDeps.isFeatureEnabled(TETHER_FORCE_RANDOM_PREFIX_BASE_SELECTION)).thenReturn(true);
-
startedPrefixBaseTest("192.168.0.0/16", 0);
startedPrefixBaseTest("192.168.0.0/16", 1);
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
index dd51c7a..0159573 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
@@ -160,6 +160,11 @@
}
@Override
+ boolean isFeatureNotChickenedOut(@NonNull Context context, @NonNull String name) {
+ return isMockFlagEnabled(name, true /* defaultEnabled */);
+ }
+
+ @Override
boolean getDeviceConfigBoolean(@NonNull String namespace, @NonNull String name,
boolean defaultValue) {
// Flags should use isFeatureEnabled instead of getBoolean; see comments in
@@ -767,9 +772,9 @@
@Test
public void testEnableSyncSMFlag() throws Exception {
- // Test default disabled
+ // Test default enabled
setTetherEnableSyncSMFlagEnabled(null);
- assertEnableSyncSM(false);
+ assertEnableSyncSM(true);
setTetherEnableSyncSMFlagEnabled(true);
assertEnableSyncSM(true);
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index e1c2db9..50ecfe1 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -2879,6 +2879,44 @@
}
@Test
+ @IgnoreAfter(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ public void testRequestStaticIpLegacyTether() throws Exception {
+ initTetheringOnTestThread();
+
+ // Call startTethering with static ip
+ final LinkAddress serverLinkAddr = new LinkAddress("192.168.0.123/24");
+ final LinkAddress clientLinkAddr = new LinkAddress("192.168.0.42/24");
+ final String serverAddr = "192.168.0.123";
+ final int clientAddrParceled = 0xc0a8002a;
+ final ArgumentCaptor<DhcpServingParamsParcel> dhcpParamsCaptor =
+ ArgumentCaptor.forClass(DhcpServingParamsParcel.class);
+ when(mWifiManager.startTetheredHotspot(any())).thenReturn(true);
+ mTethering.startTethering(createTetheringRequest(TETHERING_WIFI,
+ serverLinkAddr, clientLinkAddr, false, CONNECTIVITY_SCOPE_GLOBAL, null),
+ TEST_CALLER_PKG, null);
+ mLooper.dispatchAll();
+ verify(mWifiManager, times(1)).startTetheredHotspot(any());
+ mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
+
+ // Call legacyTether on the interface before the link layer event comes back.
+ // This happens, for example, in pre-T bluetooth tethering: Settings calls startTethering,
+ // and then the bluetooth code calls the tether() API.
+ final ResultListener tetherResult = new ResultListener(TETHER_ERROR_NO_ERROR);
+ mTethering.legacyTether(TEST_WLAN_IFNAME, tetherResult);
+ mLooper.dispatchAll();
+ tetherResult.assertHasResult();
+
+ // Verify that the static ip set in startTethering is used
+ verify(mNetd).interfaceSetCfg(argThat(cfg -> serverAddr.equals(cfg.ipv4Addr)));
+ verify(mIpServerDependencies, times(1)).makeDhcpServer(any(), dhcpParamsCaptor.capture(),
+ any());
+ final DhcpServingParamsParcel params = dhcpParamsCaptor.getValue();
+ assertEquals(serverAddr, intToInet4AddressHTH(params.serverAddr).getHostAddress());
+ assertEquals(24, params.serverAddrPrefixLength);
+ assertEquals(clientAddrParceled, params.singleClientAddr);
+ }
+
+ @Test
public void testUpstreamNetworkChanged() throws Exception {
initTetheringOnTestThread();
final InOrder inOrder = inOrder(mNotificationUpdater);
diff --git a/bpf/headers/include/bpf_helpers.h b/bpf/headers/include/bpf_helpers.h
index 6a0e5a8..9d6b6f6 100644
--- a/bpf/headers/include/bpf_helpers.h
+++ b/bpf/headers/include/bpf_helpers.h
@@ -46,12 +46,12 @@
#define BPFLOADER_U_QPR2_VERSION 41u
#define BPFLOADER_PLATFORM_VERSION BPFLOADER_U_QPR2_VERSION
-// Android Mainline - this bpfloader should eventually go back to T (or even S)
+// Android Mainline BpfLoader when running on Android S (sdk=31)
// Note: this value (and the following +1u's) are hardcoded in NetBpfLoad.cpp
-#define BPFLOADER_MAINLINE_VERSION 42u
+#define BPFLOADER_MAINLINE_S_VERSION 42u
// Android Mainline BpfLoader when running on Android T (sdk=33)
-#define BPFLOADER_MAINLINE_T_VERSION (BPFLOADER_MAINLINE_VERSION + 1u)
+#define BPFLOADER_MAINLINE_T_VERSION (BPFLOADER_MAINLINE_S_VERSION + 1u)
// Android Mainline BpfLoader when running on Android U (sdk=34)
#define BPFLOADER_MAINLINE_U_VERSION (BPFLOADER_MAINLINE_T_VERSION + 1u)
@@ -112,7 +112,7 @@
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); \
- unsigned _btf_min_bpfloader_ver SECTION("btf_min_bpfloader_ver") = BPFLOADER_MAINLINE_VERSION; \
+ unsigned _btf_min_bpfloader_ver SECTION("btf_min_bpfloader_ver") = BPFLOADER_MAINLINE_S_VERSION; \
unsigned _btf_user_min_bpfloader_ver SECTION("btf_user_min_bpfloader_ver") = 0xFFFFFFFFu; \
char _license[] SECTION("license") = (NAME)
diff --git a/bpf/headers/include/bpf_map_def.h b/bpf/headers/include/bpf_map_def.h
index e95ca5f..2e5afca 100644
--- a/bpf/headers/include/bpf_map_def.h
+++ b/bpf/headers/include/bpf_map_def.h
@@ -163,7 +163,7 @@
enum bpf_map_type type;
unsigned int key_size;
unsigned int value_size;
- int max_entries; // negative means BPF_F_NO_PREALLOC, but *might* not work with S
+ unsigned int max_entries;
unsigned int map_flags;
// The following are not supported by the Android bpfloader:
diff --git a/bpf/loader/Android.bp b/bpf/loader/Android.bp
index b08913a..edb260c 100644
--- a/bpf/loader/Android.bp
+++ b/bpf/loader/Android.bp
@@ -56,15 +56,15 @@
installable: false,
}
-// Versioned netbpfload init rc: init system will process it only on api T/33+ devices
+// Versioned netbpfload init rc: init system will process it only on api S/31+ devices
// Note: R[30] S[31] Sv2[32] T[33] U[34] V[35])
//
// For details of versioned rc files see:
// https://android.googlesource.com/platform/system/core/+/HEAD/init/README.md#versioned-rc-files-within-apexs
prebuilt_etc {
- name: "netbpfload.33rc",
- src: "netbpfload.33rc",
- filename: "netbpfload.33rc",
+ name: "netbpfload.31rc",
+ src: "netbpfload.31rc",
+ filename: "netbpfload.31rc",
installable: false,
}
diff --git a/bpf/loader/NetBpfLoad.cpp b/bpf/loader/NetBpfLoad.cpp
index 9486e75..9c62e74 100644
--- a/bpf/loader/NetBpfLoad.cpp
+++ b/bpf/loader/NetBpfLoad.cpp
@@ -60,7 +60,7 @@
#include "bpf_map_def.h"
// The following matches bpf_helpers.h, which is only for inclusion in bpf code
-#define BPFLOADER_MAINLINE_VERSION 42u
+#define BPFLOADER_MAINLINE_S_VERSION 42u
#define BPFLOADER_MAINLINE_25Q2_VERSION 47u
using android::base::EndsWith;
@@ -1187,7 +1187,7 @@
ret = readCodeSections(elfFile, cs);
// BPF .o's with no programs are only supported by mainline netbpfload,
// make sure .o's targeting non-mainline (ie. S) bpfloader don't show up.
- if (ret == -ENOENT && bpfLoaderMinVer >= BPFLOADER_MAINLINE_VERSION)
+ if (ret == -ENOENT && bpfLoaderMinVer >= BPFLOADER_MAINLINE_S_VERSION)
return 0;
if (ret) {
ALOGE("Couldn't read all code sections in %s", elfPath);
@@ -1422,7 +1422,7 @@
const bool has_platform_netbpfload_rc = exists("/system/etc/init/netbpfload.rc");
// Version of Network BpfLoader depends on the Android OS version
- unsigned int bpfloader_ver = BPFLOADER_MAINLINE_VERSION; // [42u]
+ unsigned int bpfloader_ver = BPFLOADER_MAINLINE_S_VERSION; // [42u]
if (isAtLeastT) ++bpfloader_ver; // [43] BPFLOADER_MAINLINE_T_VERSION
if (isAtLeastU) ++bpfloader_ver; // [44] BPFLOADER_MAINLINE_U_VERSION
if (runningAsRoot) ++bpfloader_ver; // [45] BPFLOADER_MAINLINE_U_QPR3_VERSION
diff --git a/bpf/loader/netbpfload.33rc b/bpf/loader/netbpfload.31rc
similarity index 77%
rename from bpf/loader/netbpfload.33rc
rename to bpf/loader/netbpfload.31rc
index eb937dd..6bc488e 100644
--- a/bpf/loader/netbpfload.33rc
+++ b/bpf/loader/netbpfload.31rc
@@ -1,6 +1,8 @@
-# This file takes effect only on T and U (on V netbpfload.35rc takes priority).
+# This file takes effect only on S, T and U (on V netbpfload.35rc takes priority).
#
-# The service is started from netd's libnetd_updatable shared library
+# The service is started from netd's
+# S: dnsresolver call into ADnsHelper_init
+# T/U: libnetd_updatable shared library
# on initial (boot time) startup of netd.
#
# However we never start this service on U QPR3.
diff --git a/bpf/progs/clatd.c b/bpf/progs/clatd.c
index 2d4551e..2bb9d6f 100644
--- a/bpf/progs/clatd.c
+++ b/bpf/progs/clatd.c
@@ -288,6 +288,9 @@
// We cannot handle IP options, just standard 20 byte == 5 dword minimal IPv4 header
if (ip4->ihl != 5) return TC_ACT_PIPE;
+ // Packet must not be multicast
+ if ((ip4->daddr & 0xf0000000) == 0xe0000000) return TC_ACT_PIPE;
+
// Calculate the IPv4 one's complement checksum of the IPv4 header.
__wsum sum4 = 0;
for (unsigned i = 0; i < sizeof(*ip4) / sizeof(__u16); ++i) {
diff --git a/clatd/ipv4.c b/clatd/ipv4.c
index 2be02e3..81bf87b 100644
--- a/clatd/ipv4.c
+++ b/clatd/ipv4.c
@@ -85,6 +85,11 @@
return 0;
}
+ if ((header->daddr & 0xf0000000) == 0xe0000000) {
+ logmsg_dbg(ANDROID_LOG_INFO, "ip_packet/daddr is multicast: %x", header->daddr);
+ return 0;
+ }
+
/* rfc6145 - If any IPv4 options are present in the IPv4 packet, they MUST be
* ignored and the packet translated normally; there is no attempt to
* translate the options.
diff --git a/framework/Android.bp b/framework/Android.bp
index f66bc60..ab3af9a 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -295,7 +295,6 @@
":framework-connectivity-t-pre-jarjar{.jar}",
":framework-connectivity.stubs.module_lib{.jar}",
":framework-connectivity-t.stubs.module_lib{.jar}",
- ":framework-connectivity-module-api-stubs-including-flagged{.jar}",
"jarjar-excludes.txt",
],
tools: [
@@ -308,7 +307,6 @@
"--prefix android.net.connectivity " +
"--apistubs $(location :framework-connectivity.stubs.module_lib{.jar}) " +
"--apistubs $(location :framework-connectivity-t.stubs.module_lib{.jar}) " +
- "--apistubs $(location :framework-connectivity-module-api-stubs-including-flagged{.jar}) " +
// Make a ":"-separated list. There will be an extra ":" but empty items are ignored.
"--unsupportedapi $$(printf ':%s' $(locations :connectivity-hiddenapi-files)) " +
"--excludes $(location jarjar-excludes.txt) " +
@@ -320,35 +318,6 @@
],
}
-droidstubs {
- name: "framework-connectivity-module-api-stubs-including-flagged-droidstubs",
- srcs: [
- ":framework-connectivity-sources",
- ":framework-connectivity-tiramisu-updatable-sources",
- ":framework-networksecurity-sources",
- ":framework-nearby-java-sources",
- ":framework-thread-sources",
- ],
- flags: [
- "--show-for-stub-purposes-annotation android.annotation.SystemApi" +
- "\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)",
- "--show-for-stub-purposes-annotation android.annotation.SystemApi" +
- "\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\)",
- ],
- aidl: {
- include_dirs: [
- "packages/modules/Connectivity/framework/aidl-export",
- "packages/modules/Connectivity/Tethering/common/TetheringLib/src",
- "frameworks/native/aidl/binder", // For PersistableBundle.aidl
- ],
- },
-}
-
-java_library {
- name: "framework-connectivity-module-api-stubs-including-flagged",
- srcs: [":framework-connectivity-module-api-stubs-including-flagged-droidstubs"],
-}
-
// Library providing limited APIs within the connectivity module, so that R+ components like
// Tethering have a controlled way to depend on newer components like framework-connectivity that
// are not loaded on R.
diff --git a/framework/jni/android_net_NetworkUtils.cpp b/framework/jni/android_net_NetworkUtils.cpp
index 3779a00..7404f32 100644
--- a/framework/jni/android_net_NetworkUtils.cpp
+++ b/framework/jni/android_net_NetworkUtils.cpp
@@ -23,9 +23,9 @@
#include <netinet/in.h>
#include <string.h>
+#include <DnsProxydProtocol.h> // NETID_USE_LOCAL_NAMESERVERS
#include <bpf/BpfClassic.h>
#include <bpf/KernelUtils.h>
-#include <DnsProxydProtocol.h> // NETID_USE_LOCAL_NAMESERVERS
#include <nativehelper/JNIPlatformHelp.h>
#include <nativehelper/ScopedPrimitiveArray.h>
#include <utils/Log.h>
@@ -259,6 +259,21 @@
return bpf::isX86();
}
+static jlong android_net_utils_getSocketCookie(JNIEnv *env, jclass clazz,
+ jobject javaFd) {
+ int sock = AFileDescriptor_getFd(env, javaFd);
+ uint64_t cookie = 0;
+ socklen_t cookie_len = sizeof(cookie);
+ if (getsockopt(sock, SOL_SOCKET, SO_COOKIE, &cookie, &cookie_len)) {
+ // Failure is almost certainly either EBADF or ENOTSOCK
+ jniThrowErrnoException(env, "getSocketCookie", errno);
+ } else if (cookie_len != sizeof(cookie)) {
+ // This probably cannot actually happen, but...
+ jniThrowErrnoException(env, "getSocketCookie", 523); // EBADCOOKIE
+ }
+ return static_cast<jlong>(cookie);
+}
+
// ----------------------------------------------------------------------------
/*
@@ -283,6 +298,7 @@
(void*) android_net_utils_setsockoptBytes},
{ "isKernel64Bit", "()Z", (void*) android_net_utils_isKernel64Bit },
{ "isKernelX86", "()Z", (void*) android_net_utils_isKernelX86 },
+ { "getSocketCookie", "(Ljava/io/FileDescriptor;)J", (void*) android_net_utils_getSocketCookie },
};
// clang-format on
diff --git a/framework/src/android/net/NetworkUtils.java b/framework/src/android/net/NetworkUtils.java
index 18feb84..6b2eb08 100644
--- a/framework/src/android/net/NetworkUtils.java
+++ b/framework/src/android/net/NetworkUtils.java
@@ -443,4 +443,13 @@
/** Returns whether the Linux Kernel is x86 */
public static native boolean isKernelX86();
+
+ /**
+ * Returns socket cookie.
+ *
+ * @param fd The socket file descriptor
+ * @return The socket cookie.
+ * @throws ErrnoException if retrieving the socket cookie fails.
+ */
+ public static native long getSocketCookie(FileDescriptor fd) throws ErrnoException;
}
diff --git a/service-t/Android.bp b/service-t/Android.bp
index d2e2a80..ab38c7a 100644
--- a/service-t/Android.bp
+++ b/service-t/Android.bp
@@ -29,6 +29,7 @@
name: "service-connectivity-tiramisu-sources",
srcs: [
"src/**/*.java",
+ ":vcn-location-sources",
],
visibility: ["//visibility:private"],
}
diff --git a/service-t/src/com/android/server/ConnectivityServiceInitializer.java b/service-t/src/com/android/server/ConnectivityServiceInitializer.java
index 5d23fdc..5ef1aef 100644
--- a/service-t/src/com/android/server/ConnectivityServiceInitializer.java
+++ b/service-t/src/com/android/server/ConnectivityServiceInitializer.java
@@ -30,6 +30,9 @@
import com.android.server.nearby.NearbyService;
import com.android.server.net.ct.CertificateTransparencyService;
import com.android.server.thread.ThreadNetworkService;
+import com.android.server.vcn.VcnLocation;
+
+import java.lang.reflect.Constructor;
/**
* Connectivity service initializer for core networking. This is called by system server to create
@@ -37,6 +40,9 @@
*/
public final class ConnectivityServiceInitializer extends SystemService {
private static final String TAG = ConnectivityServiceInitializer.class.getSimpleName();
+ private static final String CONNECTIVITY_SERVICE_INITIALIZER_B_CLASS =
+ "com.android.server.ConnectivityServiceInitializerB";
+
private final ConnectivityNativeService mConnectivityNative;
private final ConnectivityService mConnectivity;
private final IpSecService mIpSecService;
@@ -45,6 +51,7 @@
private final EthernetServiceImpl mEthernetServiceImpl;
private final ThreadNetworkService mThreadNetworkService;
private final CertificateTransparencyService mCertificateTransparencyService;
+ private final SystemService mConnectivityServiceInitializerB;
public ConnectivityServiceInitializer(Context context) {
super(context);
@@ -58,6 +65,7 @@
mNearbyService = createNearbyService(context);
mThreadNetworkService = createThreadNetworkService(context);
mCertificateTransparencyService = createCertificateTransparencyService(context);
+ mConnectivityServiceInitializerB = createConnectivityServiceInitializerB(context);
}
@Override
@@ -99,6 +107,11 @@
publishBinderService(ThreadNetworkManager.SERVICE_NAME, mThreadNetworkService,
/* allowIsolated= */ false);
}
+
+ if (mConnectivityServiceInitializerB != null) {
+ Log.i(TAG, "ConnectivityServiceInitializerB#onStart");
+ mConnectivityServiceInitializerB.onStart();
+ }
}
@Override
@@ -118,6 +131,10 @@
if (SdkLevel.isAtLeastV() && mCertificateTransparencyService != null) {
mCertificateTransparencyService.onBootPhase(phase);
}
+
+ if (mConnectivityServiceInitializerB != null) {
+ mConnectivityServiceInitializerB.onBootPhase(phase);
+ }
}
/**
@@ -202,4 +219,28 @@
? new CertificateTransparencyService(context)
: null;
}
+
+ // TODO: b/374174952 After VCN code is moved to the Connectivity folder, merge
+ // ConnectivityServiceInitializerB into ConnectivityServiceInitializer and directly create and
+ // register VcnManagementService in ConnectivityServiceInitializer
+ /** Return ConnectivityServiceInitializerB instance if enable, otherwise null. */
+ @Nullable
+ private SystemService createConnectivityServiceInitializerB(Context context) {
+ if (!VcnLocation.IS_VCN_IN_MAINLINE || !SdkLevel.isAtLeastB()) {
+ return null;
+ }
+
+ try {
+ final Class<?> connectivityServiceInitializerBClass =
+ Class.forName(CONNECTIVITY_SERVICE_INITIALIZER_B_CLASS);
+ final Constructor constructor =
+ connectivityServiceInitializerBClass.getConstructor(Context.class);
+
+ return (SystemService) constructor.newInstance(context);
+ } catch (Exception e) {
+ Log.e(TAG, "Fail to load ConnectivityServiceInitializerB " + e);
+ }
+
+ return null;
+ }
}
diff --git a/service/ServiceConnectivityResources/res/raw/ct_public_keys.pem b/service/ServiceConnectivityResources/res/raw/ct_public_keys.pem
index 80dccbe..8a5ebbf 100644
--- a/service/ServiceConnectivityResources/res/raw/ct_public_keys.pem
+++ b/service/ServiceConnectivityResources/res/raw/ct_public_keys.pem
@@ -1,4 +1,18 @@
-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAmDwwE2FRpVJlw58fo5Ra
+Fsocb7DP3FJwwuaghXL3xPtyZisDDXIpfVG+UwDPyIGrRuYzeu9pjZ/0xGSYSPZ0
+l/H8L2XurInoAbj+Z370HB7W3njIOqG9rw5N6u/xT4nscBj1HKeUwh+Hwc0F1UHS
+MP8J32nWAfVepHrte3Jy+w/V7BId6WjJmxtI9OoJ7WTsoTeD+jLANUJWtpbx0p1L
+OAy70BlHbB0UvAJdMH149qi7Y9KaJ74Ea2ofKY43NWGgWfR+fY6V7CCfUXCOgvNM
+qq5QGyMnFKrlP0XkoOaVJkK92VEtyNff8KUXik2ZyUzhNkg4ZplCrhESWeykckB/
+mdZpVc45KZ+6Sx3U+FF30eRwlu2Nw2h1KKHzYfa6M1bcy1f/xw+IDq4R+1rR7sPb
+J2mMKz0OPeCXwGEXWzBuMOs0IQu6gyNdyVZcRSyQ+LcUzvEwksLP6G/ycqmwVfdw
+JE28k3MPUR3IxnMDQrdcZb7M7kjBoykKW3jQfwlEoK4EcNQbMXVn8Ws8rcwgQcQJ
+MjjQnbISojsJYo2fG+TE6d9rORB6CYVzICOj4YguXm4LO89cYQlR600W32pP5y3o
+3/yAd9OjsKrNfREDlcCXUx1APc7gOF351RFdHlDI0+RF/pIHbH3sww3VMCJ+tjst
+ZldgJk9yaz0cvOdKyVWC83ECAwEAAQ==
+-----END PUBLIC KEY-----
+-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnmb1lacOnP5H1bwb06mG
fEUeC9PZRwNQskSs9KaWrpfrSkLKuHXkVCbgeagbUR/Sh1OeIhyJRSS0PLCO0JjC
UpGhYMrIGRgEET4IrP9f8aMFqxxxBUEanI+OxAhIJlP9tiWfGdKAASYcxg/DyXXz
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index adf593e..2c6390f 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -423,14 +423,14 @@
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
* @hide
*/
-public class ConnectivityService extends IConnectivityManager.Stub
- implements PendingIntent.OnFinished {
+public class ConnectivityService extends IConnectivityManager.Stub {
private static final String TAG = ConnectivityService.class.getSimpleName();
private static final String DIAG_ARG = "--diag";
@@ -9810,8 +9810,8 @@
}
// The both list contain current link properties + stacked links for new and old LP.
- List<LinkProperties> newLinkProperties = new ArrayList<>();
- List<LinkProperties> oldLinkProperties = new ArrayList<>();
+ final List<LinkProperties> newLinkProperties = new ArrayList<>();
+ final List<LinkProperties> oldLinkProperties = new ArrayList<>();
if (newLp != null) {
newLinkProperties.add(newLp);
@@ -9824,13 +9824,13 @@
// map contains interface name to list of local network prefixes added because of change
// in link properties
- Map<String, List<IpPrefix>> prefixesAddedForInterface = new ArrayMap<>();
+ final Map<String, List<IpPrefix>> prefixesAddedForInterface = new ArrayMap<>();
final CompareResult<LinkProperties> linkPropertiesDiff = new CompareResult<>(
oldLinkProperties, newLinkProperties);
for (LinkProperties linkProperty : linkPropertiesDiff.added) {
- List<IpPrefix> unicastLocalPrefixesToBeAdded = new ArrayList<>();
+ final List<IpPrefix> unicastLocalPrefixesToBeAdded = new ArrayList<>();
for (LinkAddress linkAddress : linkProperty.getLinkAddresses()) {
unicastLocalPrefixesToBeAdded.addAll(
getLocalNetworkPrefixesForAddress(linkAddress));
@@ -9838,7 +9838,7 @@
addLocalAddressesToBpfMap(linkProperty.getInterfaceName(),
unicastLocalPrefixesToBeAdded, linkProperty);
- // adding iterface name -> ip prefixes that we added to map
+ // populating interface name -> ip prefixes which were added to local_net_access map.
if (!prefixesAddedForInterface.containsKey(linkProperty.getInterfaceName())) {
prefixesAddedForInterface.put(linkProperty.getInterfaceName(), new ArrayList<>());
}
@@ -9847,9 +9847,9 @@
}
for (LinkProperties linkProperty : linkPropertiesDiff.removed) {
- List<IpPrefix> unicastLocalPrefixesToBeRemoved = new ArrayList<>();
- List<IpPrefix> unicastLocalPrefixesAdded = prefixesAddedForInterface.getOrDefault(
- linkProperty.getInterfaceName(), new ArrayList<>());
+ final List<IpPrefix> unicastLocalPrefixesToBeRemoved = new ArrayList<>();
+ final List<IpPrefix> unicastLocalPrefixesAdded = prefixesAddedForInterface.getOrDefault(
+ linkProperty.getInterfaceName(), Collections.emptyList());
for (LinkAddress linkAddress : linkProperty.getLinkAddresses()) {
unicastLocalPrefixesToBeRemoved.addAll(
@@ -9857,8 +9857,8 @@
}
// This is to ensure if 10.0.10.0/24 was added and 10.0.11.0/24 was removed both will
- // still populate the same prefix of 10.0.0.0/8, which mean we should not remove the
- // prefix because of removal of 10.0.11.0/24
+ // still populate the same prefix of 10.0.0.0/8, which mean 10.0.0.0/8 should not be
+ // removed due to removal of 10.0.11.0/24
unicastLocalPrefixesToBeRemoved.removeAll(unicastLocalPrefixesAdded);
removeLocalAddressesFromBpfMap(linkProperty.getInterfaceName(),
@@ -10936,10 +10936,42 @@
// else not handled
}
+ /**
+ * A small class to manage releasing a lock exactly once even if releaseLock is called
+ * multiple times. See b/390043283
+ * PendingIntent#send throws CanceledException in various cases. In some of them it will
+ * still call onSendFinished, in others it won't and the client can't know. This class
+ * keeps a ref to the wakelock that it releases exactly once, thanks to Atomics semantics.
+ */
+ private class WakeLockOnFinishedReceiver implements PendingIntent.OnFinished {
+ private final AtomicReference<PowerManager.WakeLock> mLock;
+ WakeLockOnFinishedReceiver(@NonNull final PowerManager.WakeLock lock) {
+ mLock = new AtomicReference<>(lock);
+ lock.acquire();
+ }
+
+ public void releaseLock() {
+ final PowerManager.WakeLock lock = mLock.getAndSet(null);
+ if (null != lock) lock.release();
+ }
+
+ @Override
+ public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
+ String resultData, Bundle resultExtras) {
+ if (DBG) log("Finished sending " + pendingIntent);
+ releaseLock();
+ releasePendingNetworkRequestWithDelay(pendingIntent);
+ }
+ }
+
// TODO(b/193460475): Remove when tooling supports SystemApi to public API.
@SuppressLint("NewApi")
private void sendIntent(PendingIntent pendingIntent, Intent intent) {
- mPendingIntentWakeLock.acquire();
+ // Since the receiver will take the lock exactly once and release it exactly once, it
+ // is safe to pass the same wakelock to all receivers and avoid creating a new lock
+ // every time.
+ final WakeLockOnFinishedReceiver receiver =
+ new WakeLockOnFinishedReceiver(mPendingIntentWakeLock);
try {
if (DBG) log("Sending " + pendingIntent);
final BroadcastOptions options = BroadcastOptions.makeBasic();
@@ -10948,25 +10980,14 @@
// utilizing the PendingIntent as a backdoor to do this.
options.setPendingIntentBackgroundActivityLaunchAllowed(false);
}
- pendingIntent.send(mContext, 0, intent, this /* onFinished */, null /* Handler */,
+ pendingIntent.send(mContext, 0, intent, receiver, null /* Handler */,
null /* requiredPermission */,
mDeps.isAtLeastT() ? options.toBundle() : null);
} catch (PendingIntent.CanceledException e) {
if (DBG) log(pendingIntent + " was not sent, it had been canceled.");
- mPendingIntentWakeLock.release();
+ receiver.releaseLock();
releasePendingNetworkRequest(pendingIntent);
}
- // ...otherwise, mPendingIntentWakeLock.release() gets called by onSendFinished()
- }
-
- @Override
- public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
- String resultData, Bundle resultExtras) {
- if (DBG) log("Finished sending " + pendingIntent);
- mPendingIntentWakeLock.release();
- // Release with a delay so the receiving client has an opportunity to put in its
- // own request.
- releasePendingNetworkRequestWithDelay(pendingIntent);
}
@Nullable
diff --git a/staticlibs/device/com/android/net/module/util/PrivateAddressCoordinator.java b/staticlibs/device/com/android/net/module/util/PrivateAddressCoordinator.java
index bb95585..2ce5b86 100644
--- a/staticlibs/device/com/android/net/module/util/PrivateAddressCoordinator.java
+++ b/staticlibs/device/com/android/net/module/util/PrivateAddressCoordinator.java
@@ -33,12 +33,14 @@
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
+import android.os.Build;
import android.os.RemoteException;
import android.util.ArrayMap;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.build.SdkLevel;
import java.io.PrintWriter;
import java.net.Inet4Address;
@@ -67,9 +69,6 @@
// WARNING: Keep in sync with chooseDownstreamAddress
public static final int PREFIX_LENGTH = 24;
- public static final String TETHER_FORCE_RANDOM_PREFIX_BASE_SELECTION =
- "tether_force_random_prefix_base_selection";
-
// Upstream monitor would be stopped when tethering is down. When tethering restart, downstream
// address may be requested before coordinator get current upstream notification. To ensure
// coordinator do not select conflict downstream prefix, mUpstreamPrefixMap would not be cleared
@@ -258,8 +257,15 @@
return null;
}
+ // TODO: Remove this method when SdkLevel.isAtLeastB() is fixed, aosp is at sdk level 36 or use
+ // NetworkStackUtils.isAtLeast25Q2 when it is moved to a static lib.
+ public static boolean isAtLeast25Q2() {
+ return SdkLevel.isAtLeastB() || (SdkLevel.isAtLeastV()
+ && "Baklava".equals(Build.VERSION.CODENAME));
+ }
+
private int getRandomPrefixIndex() {
- if (!mDeps.isFeatureEnabled(TETHER_FORCE_RANDOM_PREFIX_BASE_SELECTION)) return 0;
+ if (!isAtLeast25Q2()) return 0;
final int random = getRandomInt() & 0xffffff;
// This is to select the starting prefix range (/8, /12, or /16) instead of the actual
diff --git a/tests/cts/hostside/Android.bp b/tests/cts/hostside/Android.bp
index 0ac9ce1..0b4375a 100644
--- a/tests/cts/hostside/Android.bp
+++ b/tests/cts/hostside/Android.bp
@@ -27,7 +27,7 @@
// Note that some of the test helper apps (e.g., CtsHostsideNetworkCapTestsAppSdk33) override
// this with older SDK versions.
// Also note that unlike android_test targets, "current" does not work: the target SDK is set to
- // something like "VanillaIceCream" instead of 100000. This means that the tests will not run on
+ // something like "VanillaIceCream" instead of 10000. This means that the tests will not run on
// released devices with errors such as "Requires development platform VanillaIceCream but this
// is a release platform".
target_sdk_version: "10000",
diff --git a/tests/cts/multidevices/Android.bp b/tests/cts/multidevices/Android.bp
index a082a95..c730b86 100644
--- a/tests/cts/multidevices/Android.bp
+++ b/tests/cts/multidevices/Android.bp
@@ -42,9 +42,4 @@
// Package the snippet with the mobly test
":connectivity_multi_devices_snippet",
],
- version: {
- py3: {
- embedded_launcher: true,
- },
- },
}
diff --git a/tests/cts/multidevices/snippet/Wifip2pMultiDevicesSnippet.kt b/tests/cts/multidevices/snippet/Wifip2pMultiDevicesSnippet.kt
index f8c9351..3816537 100644
--- a/tests/cts/multidevices/snippet/Wifip2pMultiDevicesSnippet.kt
+++ b/tests/cts/multidevices/snippet/Wifip2pMultiDevicesSnippet.kt
@@ -21,8 +21,8 @@
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.content.pm.PackageManager.FEATURE_WIFI_DIRECT
import android.net.MacAddress
-import android.net.wifi.WifiManager
import android.net.wifi.p2p.WifiP2pConfig
import android.net.wifi.p2p.WifiP2pDevice
import android.net.wifi.p2p.WifiP2pDeviceList
@@ -44,10 +44,6 @@
class Wifip2pMultiDevicesSnippet : Snippet {
private val context by lazy { InstrumentationRegistry.getInstrumentation().getTargetContext() }
- private val wifiManager by lazy {
- context.getSystemService(WifiManager::class.java)
- ?: fail("Could not get WifiManager service")
- }
private val wifip2pManager by lazy {
context.getSystemService(WifiP2pManager::class.java)
?: fail("Could not get WifiP2pManager service")
@@ -84,7 +80,7 @@
}
@Rpc(description = "Check whether the device supports Wi-Fi P2P.")
- fun isP2pSupported() = wifiManager.isP2pSupported()
+ fun isP2pSupported() = context.packageManager.hasSystemFeature(FEATURE_WIFI_DIRECT)
@Rpc(description = "Start Wi-Fi P2P")
fun startWifiP2p() {
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index aa7d618..87c2b9e 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -90,7 +90,6 @@
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
-import static android.net.cts.util.CtsNetUtils.ConnectivityActionReceiver;
import static android.net.cts.util.CtsNetUtils.HTTP_PORT;
import static android.net.cts.util.CtsNetUtils.NETWORK_CALLBACK_ACTION;
import static android.net.cts.util.CtsNetUtils.TEST_HOST;
@@ -111,6 +110,7 @@
import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_LOCKDOWN_VPN;
import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_NONE;
import static com.android.networkstack.apishim.ConstantsShim.RECEIVER_EXPORTED;
+import static com.android.networkstack.apishim.ConstantsShim.RECEIVER_NOT_EXPORTED;
import static com.android.testutils.Cleanup.testAndCleanup;
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
import static com.android.testutils.MiscAsserts.assertEventuallyTrue;
@@ -178,6 +178,7 @@
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.ConditionVariable;
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
@@ -1229,42 +1230,43 @@
* {@link #testRegisterNetworkCallback} except that a {@code PendingIntent} is used instead
* of a {@code NetworkCallback}.
*/
- @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
+ // This test is flaky before aosp/3482151 which fixed the issue in the ConnectivityService
+ // code. Unfortunately this means T can't be fixed, so don't run this test with a module
+ // that hasn't been updated.
+ @ConnectivityModuleTest
public void testRegisterNetworkCallback_withPendingIntent() {
- assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
+ final ConditionVariable received = new ConditionVariable();
- // Create a ConnectivityActionReceiver that has an IntentFilter for our locally defined
- // action, NETWORK_CALLBACK_ACTION.
- final IntentFilter filter = new IntentFilter();
- filter.addAction(NETWORK_CALLBACK_ACTION);
+ // Register a callback with intent and a request for any Internet-providing network,
+ // which should match the currently connected network.
+ final BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(final Context context, final Intent intent) {
+ received.open();
+ }
+ };
- final ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
- mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
- final int flags = SdkLevel.isAtLeastT() ? RECEIVER_EXPORTED : 0;
- mContext.registerReceiver(receiver, filter, flags);
+ final int flags = SdkLevel.isAtLeastT() ? RECEIVER_NOT_EXPORTED : 0;
+ mContext.registerReceiver(receiver, new IntentFilter(NETWORK_CALLBACK_ACTION), flags);
// Create a broadcast PendingIntent for NETWORK_CALLBACK_ACTION.
final Intent intent = new Intent(NETWORK_CALLBACK_ACTION)
.setPackage(mContext.getPackageName());
- // While ConnectivityService would put extra info such as network or request id before
- // broadcasting the inner intent. The MUTABLE flag needs to be added accordingly.
final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0 /*requestCode*/,
intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE);
- // We will register for a WIFI network being available or lost.
- mCm.registerNetworkCallback(makeWifiNetworkRequest(), pendingIntent);
+ // Register for a network providing Internet being available or lost.
+ final NetworkRequest nr = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .build();
+ mCm.registerNetworkCallback(nr, pendingIntent);
try {
- mCtsNetUtils.ensureWifiConnected();
-
- // Now we expect to get the Intent delivered notifying of the availability of the wifi
- // network even if it was already connected as a state-based action when the callback
- // is registered.
- assertTrue("Did not receive expected Intent " + intent + " for TRANSPORT_WIFI",
- receiver.waitForState());
- } catch (InterruptedException e) {
- fail("Broadcast receiver or NetworkCallback wait was interrupted.");
+ // Wait for delivery of the Intent notifying of the availability of the
+ // INTERNET-providing network. Test setup makes sure it's already connected.
+ assertTrue("Did not receive expected Intent " + intent + " for INTERNET",
+ received.block(NETWORK_CALLBACK_TIMEOUT_MS));
} finally {
mCm.unregisterNetworkCallback(pendingIntent);
pendingIntent.cancel();
@@ -1272,6 +1274,33 @@
}
}
+ // Up to R ConnectivityService can't be updated through mainline, and there was a bug
+ // where registering a callback with a canceled pending intent would crash the system.
+ @Test
+ // Running this test without aosp/3482151 will likely crash the device.
+ @ConnectivityModuleTest
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testRegisterNetworkCallback_pendingIntent_classNotFound() {
+ final Intent intent = new Intent()
+ .setClassName(mContext.getPackageName(), "NonExistent");
+ final PendingIntent pi = PendingIntent.getActivity(mContext, /* requestCode */ 1,
+ intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE);
+
+ final NetworkRequest nr = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .build();
+ try {
+ // Before the fix delivered through Mainline, this used to crash the system, because
+ // trying to send the pending intent would throw which would prompt ConnectivityService
+ // to release the wake lock, but it would still send a finished notification at which
+ // point CS would try to release the wake lock again and crash.
+ mCm.registerNetworkCallback(nr, pi);
+ } finally {
+ mCm.unregisterNetworkCallback(pi);
+ pi.cancel();
+ }
+ }
+
private void runIdenticalPendingIntentsRequestTest(boolean useListen) throws Exception {
assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
@@ -1377,12 +1406,20 @@
}
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ // This test is flaky before aosp/3482151 which fixed the issue in the ConnectivityService
+ // code. Unfortunately this means T can't be fixed, so don't run this test with a module
+ // that hasn't been updated.
+ @ConnectivityModuleTest
@Test
public void testRegisterNetworkRequest_identicalPendingIntents() throws Exception {
runIdenticalPendingIntentsRequestTest(false /* useListen */);
}
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ // This test is flaky before aosp/3482151 which fixed the issue in the ConnectivityService
+ // code. Unfortunately this means T can't be fixed, so don't run this test with a module
+ // that hasn't been updated.
+ @ConnectivityModuleTest
@Test
public void testRegisterNetworkCallback_identicalPendingIntents() throws Exception {
runIdenticalPendingIntentsRequestTest(true /* useListen */);
diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java
index 75b2814..27cba3a 100644
--- a/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java
+++ b/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java
@@ -160,11 +160,15 @@
@Override
public void onStopTetheringSucceeded() {
mHistory.add(new CallbackValue.OnStopTetheringSucceeded());
+ // Call the parent method so that the coverage linter sees it: http://b/385014495
+ TetheringManager.StopTetheringCallback.super.onStopTetheringSucceeded();
}
@Override
public void onStopTetheringFailed(final int error) {
mHistory.add(new CallbackValue.OnStopTetheringFailed(error));
+ // Call the parent method so that the coverage linter sees it: http://b/385014495
+ TetheringManager.StopTetheringCallback.super.onStopTetheringFailed(error);
}
/**
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSLocalNetworkProtectionTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSLocalNetworkProtectionTest.kt
index 5bf6e04..84c9835 100644
--- a/tests/unit/java/com/android/server/connectivityservice/CSLocalNetworkProtectionTest.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/CSLocalNetworkProtectionTest.kt
@@ -38,6 +38,7 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito.never
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
private const val LONG_TIMEOUT_MS = 5_000
@@ -45,6 +46,7 @@
private const val PREFIX_LENGTH_IPV6 = 32
private const val WIFI_IFNAME = "wlan0"
private const val WIFI_IFNAME_2 = "wlan1"
+private const val WIFI_IFNAME_3 = "wlan2"
private val wifiNc = NetworkCapabilities.Builder()
.addTransportType(TRANSPORT_WIFI)
@@ -78,6 +80,20 @@
LOCAL_IPV6_IP_ADDRESS_PREFIX.getPrefixLength()
)
+ private val LOCAL_IPV6_IP_ADDRESS_2_PREFIX =
+ IpPrefix("2601:19b:67f:e220:1cf1:35ff:fe8c:db87/64")
+ private val LOCAL_IPV6_LINK_ADDRESS_2 = LinkAddress(
+ LOCAL_IPV6_IP_ADDRESS_2_PREFIX.getAddress(),
+ LOCAL_IPV6_IP_ADDRESS_2_PREFIX.getPrefixLength()
+ )
+
+ private val LOCAL_IPV6_IP_ADDRESS_3_PREFIX =
+ IpPrefix("fe80::/10")
+ private val LOCAL_IPV6_LINK_ADDRESS_3 = LinkAddress(
+ LOCAL_IPV6_IP_ADDRESS_3_PREFIX.getAddress(),
+ LOCAL_IPV6_IP_ADDRESS_3_PREFIX.getPrefixLength()
+ )
+
private val LOCAL_IPV4_IP_ADDRESS_PREFIX_1 = IpPrefix("10.0.0.184/24")
private val LOCAL_IPV4_LINK_ADDRRESS_1 =
LinkAddress(
@@ -190,7 +206,7 @@
}
@Test
- fun testStackedLinkPropertiesWithDifferentLinkAddresses_AddressAddedInBpfMap() {
+ fun testAddingThenRemovingStackedLinkProperties_AddressAddedThenRemovedInBpfMap() {
val nr = nr(TRANSPORT_WIFI)
val cb = TestableNetworkCallback()
cm.requestNetwork(nr, cb)
@@ -230,49 +246,6 @@
)
// As both addresses are in stacked links, so no address should be removed from the map.
verify(bpfNetMaps, never()).removeLocalNetAccess(any(), any(), any(), any(), any())
- }
-
- @Test
- fun testRemovingStackedLinkProperties_AddressRemovedInBpfMap() {
- val nr = nr(TRANSPORT_WIFI)
- val cb = TestableNetworkCallback()
- cm.requestNetwork(nr, cb)
-
- val wifiLp = lp(WIFI_IFNAME, LOCAL_IPV6_LINK_ADDRESS)
- val wifiLp2 = lp(WIFI_IFNAME_2, LOCAL_IPV4_LINK_ADDRRESS_1)
- // populating stacked link
- wifiLp.addStackedLink(wifiLp2)
- val wifiAgent = Agent(nc = wifiNc, lp = wifiLp)
- wifiAgent.connect()
- cb.expectAvailableCallbacks(wifiAgent.network, validated = false)
-
- // Multicast and Broadcast address should always be populated in local_net_access map
- verifyPopulationOfMulticastAndBroadcastAddress()
- // Verifying IPv6 address should be populated in local_net_access map
- verify(bpfNetMaps).addLocalNetAccess(
- eq(PREFIX_LENGTH_IPV6 + LOCAL_IPV6_IP_ADDRESS_PREFIX.getPrefixLength()),
- eq(WIFI_IFNAME),
- eq(LOCAL_IPV6_IP_ADDRESS_PREFIX.getAddress()),
- eq(0),
- eq(0),
- eq(false)
- )
-
- // Multicast and Broadcast address should always be populated on stacked link
- // in local_net_access map
- verifyPopulationOfMulticastAndBroadcastAddress(WIFI_IFNAME_2)
- // Verifying IPv4 matching prefix(10.0.0.0/8) should be populated as part of stacked link
- // in local_net_access map
- verify(bpfNetMaps).addLocalNetAccess(
- eq(PREFIX_LENGTH_IPV4 + 8),
- eq(WIFI_IFNAME_2),
- eq(InetAddresses.parseNumericAddress("10.0.0.0")),
- eq(0),
- eq(0),
- eq(false)
- )
- // As both addresses are in stacked links, so no address should be removed from the map.
- verify(bpfNetMaps, never()).removeLocalNetAccess(any(), any(), any(), any(), any())
// replacing link properties without stacked links
val wifiLp_3 = lp(WIFI_IFNAME, LOCAL_IPV6_LINK_ADDRESS)
@@ -290,6 +263,107 @@
}
@Test
+ fun testChangeStackedLinkProperties_AddressReplacedBpfMap() {
+ val nr = nr(TRANSPORT_WIFI)
+ val cb = TestableNetworkCallback()
+ cm.requestNetwork(nr, cb)
+
+ val wifiLp = lp(WIFI_IFNAME, LOCAL_IPV6_LINK_ADDRESS)
+ val wifiLp2 = lp(WIFI_IFNAME_2, LOCAL_IPV4_LINK_ADDRRESS_1)
+ // populating stacked link
+ wifiLp.addStackedLink(wifiLp2)
+ val wifiAgent = Agent(nc = wifiNc, lp = wifiLp)
+ wifiAgent.connect()
+ cb.expectAvailableCallbacks(wifiAgent.network, validated = false)
+
+ // Multicast and Broadcast address should always be populated in local_net_access map
+ verifyPopulationOfMulticastAndBroadcastAddress()
+ // Verifying IPv6 address should be populated in local_net_access map
+ verify(bpfNetMaps).addLocalNetAccess(
+ eq(PREFIX_LENGTH_IPV6 + LOCAL_IPV6_IP_ADDRESS_PREFIX.getPrefixLength()),
+ eq(WIFI_IFNAME),
+ eq(LOCAL_IPV6_IP_ADDRESS_PREFIX.getAddress()),
+ eq(0),
+ eq(0),
+ eq(false)
+ )
+
+ // Multicast and Broadcast address should always be populated on stacked link
+ // in local_net_access map
+ verifyPopulationOfMulticastAndBroadcastAddress(WIFI_IFNAME_2)
+ // Verifying IPv4 matching prefix(10.0.0.0/8) should be populated as part of stacked link
+ // in local_net_access map
+ verify(bpfNetMaps).addLocalNetAccess(
+ eq(PREFIX_LENGTH_IPV4 + 8),
+ eq(WIFI_IFNAME_2),
+ eq(InetAddresses.parseNumericAddress("10.0.0.0")),
+ eq(0),
+ eq(0),
+ eq(false)
+ )
+ // As both addresses are in stacked links, so no address should be removed from the map.
+ verify(bpfNetMaps, never()).removeLocalNetAccess(any(), any(), any(), any(), any())
+
+ // replacing link properties multiple stacked links
+ val wifiLp_3 = lp(WIFI_IFNAME, LOCAL_IPV6_LINK_ADDRESS_2)
+ val wifiLp_4 = lp(WIFI_IFNAME_2, LOCAL_IPV4_LINK_ADDRRESS_2)
+ val wifiLp_5 = lp(WIFI_IFNAME_3, LOCAL_IPV6_LINK_ADDRESS_3)
+ wifiLp_3.addStackedLink(wifiLp_4)
+ wifiLp_3.addStackedLink(wifiLp_5)
+ wifiAgent.sendLinkProperties(wifiLp_3)
+ cb.expect<LinkPropertiesChanged>(wifiAgent.network)
+
+ // Multicast and Broadcast address should always be populated on stacked link
+ // in local_net_access map
+ verifyPopulationOfMulticastAndBroadcastAddress(WIFI_IFNAME_3)
+ // Verifying new base IPv6 address should be populated in local_net_access map
+ verify(bpfNetMaps).addLocalNetAccess(
+ eq(PREFIX_LENGTH_IPV6 + LOCAL_IPV6_IP_ADDRESS_2_PREFIX.getPrefixLength()),
+ eq(WIFI_IFNAME),
+ eq(LOCAL_IPV6_IP_ADDRESS_2_PREFIX.getAddress()),
+ eq(0),
+ eq(0),
+ eq(false)
+ )
+ // Verifying IPv4 matching prefix(10.0.0.0/8) should be populated as part of stacked link
+ // in local_net_access map
+ verify(bpfNetMaps, times(2)).addLocalNetAccess(
+ eq(PREFIX_LENGTH_IPV4 + 8),
+ eq(WIFI_IFNAME_2),
+ eq(InetAddresses.parseNumericAddress("10.0.0.0")),
+ eq(0),
+ eq(0),
+ eq(false)
+ )
+ // Verifying newly stacked IPv6 address should be populated in local_net_access map
+ verify(bpfNetMaps).addLocalNetAccess(
+ eq(PREFIX_LENGTH_IPV6 + LOCAL_IPV6_IP_ADDRESS_3_PREFIX.getPrefixLength()),
+ eq(WIFI_IFNAME_3),
+ eq(LOCAL_IPV6_IP_ADDRESS_3_PREFIX.getAddress()),
+ eq(0),
+ eq(0),
+ eq(false)
+ )
+ // Verifying old base IPv6 address should be removed from local_net_access map
+ verify(bpfNetMaps).removeLocalNetAccess(
+ eq(PREFIX_LENGTH_IPV6 + LOCAL_IPV6_IP_ADDRESS_PREFIX.getPrefixLength()),
+ eq(WIFI_IFNAME),
+ eq(LOCAL_IPV6_IP_ADDRESS_PREFIX.getAddress()),
+ eq(0),
+ eq(0)
+ )
+ // As both stacked links is had same prefix, 10.0.0.0/8 should not be removed from
+ // local_net_access map.
+ verify(bpfNetMaps, never()).removeLocalNetAccess(
+ eq(PREFIX_LENGTH_IPV4 + 8),
+ eq(WIFI_IFNAME_2),
+ eq(InetAddresses.parseNumericAddress("10.0.0.0")),
+ eq(0),
+ eq(0)
+ )
+ }
+
+ @Test
fun testChangeLinkPropertiesWithLinkAddressesInSameRange_AddressIntactInBpfMap() {
val nr = nr(TRANSPORT_WIFI)
val cb = TestableNetworkCallback()
diff --git a/tests/unit/java/com/android/server/net/HeaderCompressionUtilsTest.kt b/tests/unit/java/com/android/server/net/HeaderCompressionUtilsTest.kt
index 8431194..7ebe384 100644
--- a/tests/unit/java/com/android/server/net/HeaderCompressionUtilsTest.kt
+++ b/tests/unit/java/com/android/server/net/HeaderCompressionUtilsTest.kt
@@ -17,12 +17,14 @@
package com.android.server.net
import android.os.Build
+import com.android.internal.util.HexDump
import com.android.testutils.ConnectivityModuleTest
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
-import com.android.internal.util.HexDump
import com.google.common.truth.Truth.assertThat
-
+import java.io.IOException
+import java.nio.BufferUnderflowException
+import kotlin.test.assertFailsWith
import org.junit.Test
import org.junit.runner.RunWith
@@ -184,6 +186,83 @@
}
@Test
+ fun testHeaderDecompression_invalidPacket() {
+ // 1-byte packet
+ var input = "60"
+ assertFailsWith(BufferUnderflowException::class) { decompressHex(input) }
+
+ // Short packet -- incomplete header
+ // TF: 11, NH: 0, HLIM: 11, CID: 0, SAC: 0, SAM: 10, M: 1, DAC: 0, DAM: 11
+ input = "7b2b" +
+ "44" + // next header
+ "1234" // source
+ assertFailsWith(BufferUnderflowException::class) { decompressHex(input) }
+
+ // Packet starts with 0b111 instead of 0b011
+ // TF: 11, NH: 0, HLIM: 11, CID: 0, SAC: 0, SAM: 10, M: 1, DAC: 0, DAM: 11
+ input = "fb2b" +
+ "44" + // next header
+ "1234" + // source
+ "89" + // dest
+ "abcdef01" // payload
+ assertFailsWith(IOException::class) { decompressHex(input) }
+
+ // Illegal option NH = 1. Note that the packet is not valid as the code should throw as soon
+ // as the illegal option is encountered.
+ // TF: 11, NH: 1, HLIM: 11, CID: 0, SAC: 0, SAM: 10, M: 1, DAC: 0, DAM: 11
+ input = "7f2b" +
+ "1234" + // source
+ "89" + // dest
+ "e0" // Hop-by-hop options NHC
+ assertFailsWith(IOException::class) { decompressHex(input) }
+
+ // Illegal option CID = 1.
+ // TF: 11, NH: 0, HLIM: 11, CID: 1, SAC: 0, SAM: 10, M: 1, DAC: 0, DAM: 11
+ input = "7bab00" +
+ "1234" + // source
+ "89" + // dest
+ "e0" // Hop-by-hop options NHC
+ assertFailsWith(IOException::class) { decompressHex(input) }
+
+ // Illegal option SAC = 1.
+ // TF: 11, NH: 0, HLIM: 11, CID: 0, SAC: 1, SAM: 10, M: 1, DAC: 0, DAM: 11
+ input = "7b6b" +
+ "1234" + // source
+ "89" + // dest
+ "e0" // Hop-by-hop options NHC
+ assertFailsWith(IOException::class) { decompressHex(input) }
+
+ // Illegal option DAC = 1.
+ // TF: 10, NH: 0, HLIM: 10, CID: 0, SAC: 0, SAM: 10, M: 0, DAC: 1, DAM: 10
+ input = "7226" +
+ "cc" + // traffic class
+ "43" + // next header
+ "1234" + // source
+ "abcd" + // dest
+ "abcdef" // payload
+ assertFailsWith(IOException::class) { decompressHex(input) }
+
+
+ // Unsupported option DAM = 11
+ // TF: 10, NH: 0, HLIM: 10, CID: 0, SAC: 0, SAM: 10, M: 0, DAC: 0, DAM: 11
+ input = "7223" +
+ "cc" + // traffic class
+ "43" + // next header
+ "1234" + // source
+ "abcdef" // payload
+ assertFailsWith(IOException::class) { decompressHex(input) }
+
+ // Unsupported option SAM = 11
+ // TF: 10, NH: 0, HLIM: 10, CID: 0, SAC: 0, SAM: 11, M: 0, DAC: 0, DAM: 10
+ input = "7232" +
+ "cc" + // traffic class
+ "43" + // next header
+ "abcd" + // dest
+ "abcdef" // payload
+ assertFailsWith(IOException::class) { decompressHex(input) }
+ }
+
+ @Test
fun testHeaderCompression() {
val input = "60120304000011fffe800000000000000000000000000001fe800000000000000000000000000002"
val output = "60000102030411fffe800000000000000000000000000001fe800000000000000000000000000002"
diff --git a/thread/tests/cts/Android.bp b/thread/tests/cts/Android.bp
index 2630d21..901dee7 100644
--- a/thread/tests/cts/Android.bp
+++ b/thread/tests/cts/Android.bp
@@ -51,7 +51,6 @@
libs: [
"android.test.base.stubs",
"android.test.runner.stubs",
- "framework-connectivity-module-api-stubs-including-flagged",
],
// Test coverage system runs on different devices. Need to
// compile for all architectures.
diff --git a/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkControllerTest.java b/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkControllerTest.java
index 2d487ca..a979721 100644
--- a/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkControllerTest.java
+++ b/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkControllerTest.java
@@ -1296,6 +1296,7 @@
}
@Test
+ @Ignore("b/333649897, b/332195449: The 3 meshcop tests are flaky in different environments")
public void meshcopService_threadEnabledButNotJoined_discoveredButNoNetwork() throws Exception {
setUpTestNetwork();
@@ -1348,6 +1349,7 @@
}
@Test
+ @Ignore("b/333649897, b/332195449: The 3 meshcop tests are flaky in different environments")
public void meshcopService_threadDisabled_notDiscovered() throws Exception {
setUpTestNetwork();
CompletableFuture<NsdServiceInfo> serviceLostFuture = new CompletableFuture<>();
diff --git a/thread/tests/integration/src/android/net/thread/ServiceDiscoveryTest.java b/thread/tests/integration/src/android/net/thread/ServiceDiscoveryTest.java
index 6c2a9bb..f959ccf 100644
--- a/thread/tests/integration/src/android/net/thread/ServiceDiscoveryTest.java
+++ b/thread/tests/integration/src/android/net/thread/ServiceDiscoveryTest.java
@@ -113,8 +113,8 @@
@Before
public void setUp() throws Exception {
- mOtCtl.factoryReset();
mController.setEnabledAndWait(true);
+ mController.leaveAndWait();
mController.joinAndWait(DEFAULT_DATASET);
mNsdManager = mContext.getSystemService(NsdManager.class);
diff --git a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
index 7a5895f..2641a77 100644
--- a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
+++ b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
@@ -132,10 +132,6 @@
mOtCtl = new OtDaemonController();
mController.setEnabledAndWait(true);
mController.leaveAndWait();
-
- // TODO: b/323301831 - This is a workaround to avoid unnecessary delay to re-form a network
- mOtCtl.factoryReset();
-
mFtd = new FullThreadDevice(10 /* nodeId */);
}
@@ -352,7 +348,6 @@
mOtCtl.executeCommand("netdata register");
mController.leaveAndWait();
- mOtCtl.factoryReset();
mController.joinAndWait(DEFAULT_DATASET);
LinkProperties lp = cm.getLinkProperties(getThreadNetwork(CALLBACK_TIMEOUT));
diff --git a/thread/tests/integration/src/android/net/thread/ThreadNetworkShellCommandTest.java b/thread/tests/integration/src/android/net/thread/ThreadNetworkShellCommandTest.java
index 2f0ab34..ac688dd 100644
--- a/thread/tests/integration/src/android/net/thread/ThreadNetworkShellCommandTest.java
+++ b/thread/tests/integration/src/android/net/thread/ThreadNetworkShellCommandTest.java
@@ -66,11 +66,7 @@
@Before
public void setUp() throws Exception {
- // TODO(b/366141754): The current implementation of "thread_network ot-ctl factoryreset"
- // results in timeout error.
- // A future fix will provide proper support for factoryreset, allowing us to replace the
- // legacy "ot-ctl".
- mOtCtl.factoryReset();
+ mController.leaveAndWait();
mFtd = new FullThreadDevice(10 /* nodeId */);
ensureThreadEnabled();
diff --git a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.kt b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.kt
index 801e21e..f00c9cd 100644
--- a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.kt
+++ b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.kt
@@ -603,11 +603,12 @@
/** Enables Thread and joins the specified Thread network. */
@JvmStatic
fun enableThreadAndJoinNetwork(dataset: ActiveOperationalDataset) {
- // TODO: b/323301831 - This is a workaround to avoid unnecessary delay to re-form a network
- OtDaemonController().factoryReset();
-
val context: Context = requireNotNull(ApplicationProvider.getApplicationContext());
val controller = requireNotNull(ThreadNetworkControllerWrapper.newInstance(context));
+
+ // TODO: b/323301831 - This is a workaround to avoid unnecessary delay to re-form a network
+ controller.leaveAndWait();
+
controller.setEnabledAndWait(true);
controller.joinAndWait(dataset);
}
diff --git a/thread/tests/multidevices/Android.bp b/thread/tests/multidevices/Android.bp
index 050caa8..1d2ae62 100644
--- a/thread/tests/multidevices/Android.bp
+++ b/thread/tests/multidevices/Android.bp
@@ -35,9 +35,4 @@
"mts-tethering",
"general-tests",
],
- version: {
- py3: {
- embedded_launcher: true,
- },
- },
}