From e96bd02054d620bb37acea0f7fcd56ee7c2287c5 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 21 Apr 2020 12:42:37 +0000 Subject: [PATCH 1/4] Fix test initialization errors on Q ConnectivityDiagnosticsManagerTest, MultinetworkApiTest, NetworkAgentTest crashed before the runner could start them: - Ignore ConnectivityDiagnosticsManagerTest on Q: it tests an API that was introduced in R. - Build JNI libraries used by MultinetworkApiTest against the NDK to avoid errors loading the libraries on older platforms, when transitive dependencies have been added. - Do not attempt to override Handler#getLooper() (which is final) in NetworkAgentTest; it appears to have been overridden by accident by specifying "val looper" in the TestableNetworkAgent definition, which generates a getter. Test: atest CtsNetTestCasesLatestSdk:ConnectivityDiagnosticsManagerTest atest CtsNetTestCasesLatestSdk:MultinetworkApiTest atest CtsNetTestCasesLatestSdk:NetworkAgentTest Bug: 150918852 Merged-In: I262b54c6897ed755adaeb2b118c638320634f7a1 Change-Id: I262b54c6897ed755adaeb2b118c638320634f7a1 --- tests/cts/net/jni/Android.bp | 2 + tests/cts/net/jni/NativeDnsJni.c | 41 +++++++++++-------- tests/cts/net/jni/NativeMultinetworkJni.cpp | 35 ++++++++-------- .../ConnectivityDiagnosticsManagerTest.java | 9 ++-- .../src/android/net/cts/NetworkAgentTest.kt | 2 +- 5 files changed, 51 insertions(+), 38 deletions(-) diff --git a/tests/cts/net/jni/Android.bp b/tests/cts/net/jni/Android.bp index baed48dfae..3953aeb701 100644 --- a/tests/cts/net/jni/Android.bp +++ b/tests/cts/net/jni/Android.bp @@ -16,6 +16,7 @@ cc_library_shared { name: "libnativedns_jni", srcs: ["NativeDnsJni.c"], + sdk_version: "current", shared_libs: [ "libnativehelper_compat_libc++", @@ -35,6 +36,7 @@ cc_library_shared { name: "libnativemultinetwork_jni", srcs: ["NativeMultinetworkJni.cpp"], + sdk_version: "current", cflags: [ "-Wall", "-Werror", diff --git a/tests/cts/net/jni/NativeDnsJni.c b/tests/cts/net/jni/NativeDnsJni.c index 6d3d1c3250..4ec800e555 100644 --- a/tests/cts/net/jni/NativeDnsJni.c +++ b/tests/cts/net/jni/NativeDnsJni.c @@ -19,7 +19,12 @@ #include #include #include -#include + +#include + +#define LOG_TAG "NativeDns-JNI" +#define LOGD(fmt, ...) \ + __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##__VA_ARGS__) const char *GoogleDNSIpV4Address="8.8.8.8"; const char *GoogleDNSIpV4Address2="8.8.4.4"; @@ -33,7 +38,7 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas struct addrinfo *answer; int res = getaddrinfo(node, service, NULL, &answer); - ALOGD("getaddrinfo(www.google.com) gave res=%d (%s)", res, gai_strerror(res)); + LOGD("getaddrinfo(www.google.com) gave res=%d (%s)", res, gai_strerror(res)); if (res != 0) return JNI_FALSE; // check for v4 & v6 @@ -47,12 +52,12 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas inet_ntop(current->ai_family, &((struct sockaddr_in *)current->ai_addr)->sin_addr, buf, sizeof(buf)); foundv4 = 1; - ALOGD(" %s", buf); + LOGD(" %s", buf); } else if (current->ai_addr->sa_family == AF_INET6) { inet_ntop(current->ai_family, &((struct sockaddr_in6 *)current->ai_addr)->sin6_addr, buf, sizeof(buf)); foundv6 = 1; - ALOGD(" %s", buf); + LOGD(" %s", buf); } current = current->ai_next; } @@ -60,14 +65,14 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas freeaddrinfo(answer); answer = NULL; if (foundv4 != 1 && foundv6 != 1) { - ALOGD("getaddrinfo(www.google.com) didn't find either v4 or v6 address"); + LOGD("getaddrinfo(www.google.com) didn't find either v4 or v6 address"); return JNI_FALSE; } } node = "ipv6.google.com"; res = getaddrinfo(node, service, NULL, &answer); - ALOGD("getaddrinfo(ipv6.google.com) gave res=%d", res); + LOGD("getaddrinfo(ipv6.google.com) gave res=%d", res); if (res != 0) return JNI_FALSE; { @@ -79,12 +84,12 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas if (current->ai_addr->sa_family == AF_INET) { inet_ntop(current->ai_family, &((struct sockaddr_in *)current->ai_addr)->sin_addr, buf, sizeof(buf)); - ALOGD(" %s", buf); + LOGD(" %s", buf); foundv4 = 1; } else if (current->ai_addr->sa_family == AF_INET6) { inet_ntop(current->ai_family, &((struct sockaddr_in6 *)current->ai_addr)->sin6_addr, buf, sizeof(buf)); - ALOGD(" %s", buf); + LOGD(" %s", buf); foundv6 = 1; } current = current->ai_next; @@ -93,7 +98,7 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas freeaddrinfo(answer); answer = NULL; if (foundv4 == 1 || foundv6 != 1) { - ALOGD("getaddrinfo(ipv6.google.com) didn't find only v6"); + LOGD("getaddrinfo(ipv6.google.com) didn't find only v6"); return JNI_FALSE; } } @@ -116,12 +121,12 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas res = getnameinfo((const struct sockaddr*)&sa4, sizeof(sa4), buf, sizeof(buf), NULL, 0, flags); if (res != 0) { - ALOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV4Address, res, + LOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV4Address, res, gai_strerror(res)); return JNI_FALSE; } if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) { - ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", + LOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", GoogleDNSIpV4Address, buf); return JNI_FALSE; } @@ -129,12 +134,12 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas memset(buf, 0, sizeof(buf)); res = getnameinfo((const struct sockaddr*)&sa6, sizeof(sa6), buf, sizeof(buf), NULL, 0, flags); if (res != 0) { - ALOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV6Address2, + LOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV6Address2, res, gai_strerror(res)); return JNI_FALSE; } if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) { - ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", + LOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s", GoogleDNSIpV6Address2, buf); return JNI_FALSE; } @@ -142,11 +147,11 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas // gethostbyname struct hostent *my_hostent = gethostbyname("www.youtube.com"); if (my_hostent == NULL) { - ALOGD("gethostbyname(www.youtube.com) gave null response"); + LOGD("gethostbyname(www.youtube.com) gave null response"); return JNI_FALSE; } if ((my_hostent->h_addr_list == NULL) || (*my_hostent->h_addr_list == NULL)) { - ALOGD("gethostbyname(www.youtube.com) gave 0 addresses"); + LOGD("gethostbyname(www.youtube.com) gave 0 addresses"); return JNI_FALSE; } { @@ -154,7 +159,7 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas while (*current != NULL) { char buf[256]; inet_ntop(my_hostent->h_addrtype, *current, buf, sizeof(buf)); - ALOGD("gethostbyname(www.youtube.com) gave %s", buf); + LOGD("gethostbyname(www.youtube.com) gave %s", buf); current++; } } @@ -164,11 +169,11 @@ JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclas inet_pton(AF_INET6, GoogleDNSIpV6Address, addr6); my_hostent = gethostbyaddr(addr6, sizeof(addr6), AF_INET6); if (my_hostent == NULL) { - ALOGD("gethostbyaddr(%s (GoogleDNS) ) gave null response", GoogleDNSIpV6Address); + LOGD("gethostbyaddr(%s (GoogleDNS) ) gave null response", GoogleDNSIpV6Address); return JNI_FALSE; } - ALOGD("gethostbyaddr(%s (GoogleDNS) ) gave %s for name", GoogleDNSIpV6Address, + LOGD("gethostbyaddr(%s (GoogleDNS) ) gave %s for name", GoogleDNSIpV6Address, my_hostent->h_name ? my_hostent->h_name : "null"); if (my_hostent->h_name == NULL) return JNI_FALSE; diff --git a/tests/cts/net/jni/NativeMultinetworkJni.cpp b/tests/cts/net/jni/NativeMultinetworkJni.cpp index 2832c3d142..cd94709fd5 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.cpp +++ b/tests/cts/net/jni/NativeMultinetworkJni.cpp @@ -16,7 +16,6 @@ #define LOG_TAG "MultinetworkApiTest" -#include #include #include @@ -34,9 +33,13 @@ #include +#include #include #include +#define LOGD(fmt, ...) \ + __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##__VA_ARGS__) + #define EXPECT_GE(env, actual, expected, msg) \ do { \ if (actual < expected) { \ @@ -138,7 +141,7 @@ int expectAnswersNotValid(JNIEnv* env, int fd, int expectedErrno) { uint8_t buf[MAXPACKET] = {}; int res = getAsyncResponse(env, fd, TIMEOUT_MS, &rcode, buf, MAXPACKET); if (res != expectedErrno) { - ALOGD("res:%d, expectedErrno = %d", res, expectedErrno); + LOGD("res:%d, expectedErrno = %d", res, expectedErrno); return (res > 0) ? -EREMOTEIO : res; } return 0; @@ -326,7 +329,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runGetaddrinfoCheck( const int saved_errno = errno; freeaddrinfo(res); - ALOGD("android_getaddrinfofornetwork(%" PRIu64 ", %s) returned rval=%d errno=%d", + LOGD("android_getaddrinfofornetwork(%" PRIu64 ", %s) returned rval=%d errno=%d", handle, kHostname, rval, saved_errno); return rval == 0 ? 0 : -saved_errno; } @@ -339,7 +342,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runSetprocnetwork( errno = 0; int rval = android_setprocnetwork(handle); const int saved_errno = errno; - ALOGD("android_setprocnetwork(%" PRIu64 ") returned rval=%d errno=%d", + LOGD("android_setprocnetwork(%" PRIu64 ") returned rval=%d errno=%d", handle, rval, saved_errno); return rval == 0 ? 0 : -saved_errno; } @@ -352,14 +355,14 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runSetsocknetwork( errno = 0; int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) { - ALOGD("socket() failed, errno=%d", errno); + LOGD("socket() failed, errno=%d", errno); return -errno; } errno = 0; int rval = android_setsocknetwork(handle, fd); const int saved_errno = errno; - ALOGD("android_setprocnetwork(%" PRIu64 ", %d) returned rval=%d errno=%d", + LOGD("android_setprocnetwork(%" PRIu64 ", %d) returned rval=%d errno=%d", handle, fd, rval, saved_errno); close(fd); return rval == 0 ? 0 : -saved_errno; @@ -404,7 +407,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( static const char kPort[] = "443"; int rval = android_getaddrinfofornetwork(handle, kHostname, kPort, &kHints, &res); if (rval != 0) { - ALOGD("android_getaddrinfofornetwork(%llu, %s) returned rval=%d errno=%d", + LOGD("android_getaddrinfofornetwork(%llu, %s) returned rval=%d errno=%d", handle, kHostname, rval, errno); freeaddrinfo(res); return -errno; @@ -413,14 +416,14 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( // Rely upon getaddrinfo sorting the best destination to the front. int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (fd < 0) { - ALOGD("socket(%d, %d, %d) failed, errno=%d", + LOGD("socket(%d, %d, %d) failed, errno=%d", res->ai_family, res->ai_socktype, res->ai_protocol, errno); freeaddrinfo(res); return -errno; } rval = android_setsocknetwork(handle, fd); - ALOGD("android_setprocnetwork(%llu, %d) returned rval=%d errno=%d", + LOGD("android_setprocnetwork(%llu, %d) returned rval=%d errno=%d", handle, fd, rval, errno); if (rval != 0) { close(fd); @@ -430,7 +433,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( char addrstr[kSockaddrStrLen+1]; sockaddr_ntop(res->ai_addr, res->ai_addrlen, addrstr, sizeof(addrstr)); - ALOGD("Attempting connect() to %s ...", addrstr); + LOGD("Attempting connect() to %s ...", addrstr); rval = connect(fd, res->ai_addr, res->ai_addrlen); if (rval != 0) { @@ -447,7 +450,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( return -errno; } sockaddr_ntop((const struct sockaddr *)&src_addr, sizeof(src_addr), addrstr, sizeof(addrstr)); - ALOGD("... from %s", addrstr); + LOGD("... from %s", addrstr); // Don't let reads or writes block indefinitely. const struct timeval timeo = { 2, 0 }; // 2 seconds @@ -479,7 +482,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( sent = send(fd, quic_packet, sizeof(quic_packet), 0); if (sent < (ssize_t)sizeof(quic_packet)) { errnum = errno; - ALOGD("send(QUIC packet) returned sent=%zd, errno=%d", sent, errnum); + LOGD("send(QUIC packet) returned sent=%zd, errno=%d", sent, errnum); close(fd); return -errnum; } @@ -489,14 +492,14 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( break; } else { errnum = errno; - ALOGD("[%d/%d] recv(QUIC response) returned rcvd=%zd, errno=%d", + LOGD("[%d/%d] recv(QUIC response) returned rcvd=%zd, errno=%d", i + 1, MAX_RETRIES, rcvd, errnum); } } if (rcvd < 9) { - ALOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); + LOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); if (rcvd <= 0) { - ALOGD("Does this network block UDP port %s?", kPort); + LOGD("Does this network block UDP port %s?", kPort); } close(fd); return -EPROTO; @@ -504,7 +507,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( int conn_id_cmp = memcmp(quic_packet + 1, response + 1, 8); if (conn_id_cmp != 0) { - ALOGD("sent and received connection IDs do not match"); + LOGD("sent and received connection IDs do not match"); close(fd); return -EPROTO; } diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index 0a80047fdf..9d357055d1 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -18,15 +18,17 @@ package android.net.cts; import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import android.content.Context; import android.net.ConnectivityDiagnosticsManager; import android.net.NetworkRequest; +import android.os.Build; import androidx.test.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; @@ -34,7 +36,8 @@ import org.junit.runner.RunWith; import java.util.concurrent.Executor; -@RunWith(AndroidJUnit4.class) +@RunWith(DevSdkIgnoreRunner.class) +@IgnoreUpTo(Build.VERSION_CODES.Q) // ConnectivityDiagnosticsManager did not exist in Q public class ConnectivityDiagnosticsManagerTest { private static final Executor INLINE_EXECUTOR = x -> x.run(); private static final NetworkRequest DEFAULT_REQUEST = new NetworkRequest.Builder().build(); diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 89d3dff66c..03b961bc4b 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -180,7 +180,7 @@ class NetworkAgentTest { } private open class TestableNetworkAgent( - val looper: Looper, + looper: Looper, val nc: NetworkCapabilities, val lp: LinkProperties, conf: NetworkAgentConfig From 36e47811817c5036ce7df213da28479a560ee381 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Wed, 22 Apr 2020 16:58:09 +0000 Subject: [PATCH 2/4] Update logic for checking NetworkSpecifier We cannot test using WifiNetworkSpecifier, because the matching behaviour for null WifiNetworkSpecifier changed between Q and R. Replace WifiNetworkSpecifier with MatchAllNetworkSpecifier and TelephonyNetworkSpecifier that behave the same in both Q and R to verify. Bug: 154451660 Test: atest CtsNetTestCasesLatestSdk:android.net.cts.NetworkRequestTest on aosp and internal build Change-Id: I14e2a5e629051e243f3b892b608cb1c6195cd8ed Merged-In: I14e2a5e629051e243f3b892b608cb1c6195cd8ed (cherry picked from commit 902d572ca8a7604a07b8fafb32eb7dce323350f0) --- .../android/net/cts/NetworkRequestTest.java | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java index 6a1d9de6f6..5e92b410f5 100644 --- a/tests/cts/net/src/android/net/cts/NetworkRequestTest.java +++ b/tests/cts/net/src/android/net/cts/NetworkRequestTest.java @@ -29,9 +29,11 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.net.MacAddress; +import android.net.MatchAllNetworkSpecifier; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.NetworkSpecifier; +import android.net.TelephonyNetworkSpecifier; import android.net.wifi.WifiNetworkSpecifier; import android.os.Build; import android.os.Process; @@ -127,39 +129,54 @@ public class NetworkRequestTest { @Test @IgnoreUpTo(Build.VERSION_CODES.Q) public void testCanBeSatisfiedBy() { - final WifiNetworkSpecifier specifier1 = new WifiNetworkSpecifier.Builder() - .setSsidPattern(new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_LITERAL)) - .setBssidPattern(ARBITRARY_ADDRESS, ARBITRARY_ADDRESS) + final TelephonyNetworkSpecifier specifier1 = new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(1234 /* subId */) .build(); - final WifiNetworkSpecifier specifier2 = new WifiNetworkSpecifier.Builder() - .setSsidPattern(new PatternMatcher(OTHER_SSID, PatternMatcher.PATTERN_LITERAL)) - .setBssidPattern(ARBITRARY_ADDRESS, ARBITRARY_ADDRESS) + final TelephonyNetworkSpecifier specifier2 = new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(5678 /* subId */) .build(); final NetworkCapabilities cap = new NetworkCapabilities() - .addTransportType(TRANSPORT_WIFI) - .addCapability(NET_CAPABILITY_INTERNET); - final NetworkCapabilities capWithSp = - new NetworkCapabilities(cap).setNetworkSpecifier(specifier1); - final NetworkCapabilities cellCap = new NetworkCapabilities() .addTransportType(TRANSPORT_CELLULAR) .addCapability(NET_CAPABILITY_MMS) .addCapability(NET_CAPABILITY_INTERNET); - final NetworkRequest request = new NetworkRequest.Builder() - .addTransportType(TRANSPORT_WIFI) + final NetworkCapabilities capDualTransport = new NetworkCapabilities(cap) + .addTransportType(TRANSPORT_VPN); + final NetworkCapabilities capWithSpecifier1 = + new NetworkCapabilities(cap).setNetworkSpecifier(specifier1); + final NetworkCapabilities capDiffTransportWithSpecifier1 = new NetworkCapabilities() + .addCapability(NET_CAPABILITY_INTERNET) + .addTransportType(TRANSPORT_VPN) + .setNetworkSpecifier(specifier1); + + final NetworkRequest requestWithSpecifier1 = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) .addCapability(NET_CAPABILITY_INTERNET) .setNetworkSpecifier(specifier1) .build(); - assertFalse(request.canBeSatisfiedBy(null)); - assertFalse(request.canBeSatisfiedBy(new NetworkCapabilities())); - assertTrue(request.canBeSatisfiedBy(cap)); - assertTrue(request.canBeSatisfiedBy( - new NetworkCapabilities(cap).addTransportType(TRANSPORT_VPN))); - assertTrue(request.canBeSatisfiedBy(capWithSp)); - assertFalse(request.canBeSatisfiedBy( + assertFalse(requestWithSpecifier1.canBeSatisfiedBy(null)); + assertFalse(requestWithSpecifier1.canBeSatisfiedBy(new NetworkCapabilities())); + assertTrue(requestWithSpecifier1.canBeSatisfiedBy(new NetworkCapabilities(cap) + .setNetworkSpecifier(new MatchAllNetworkSpecifier()))); + assertTrue(requestWithSpecifier1.canBeSatisfiedBy(cap)); + assertTrue(requestWithSpecifier1.canBeSatisfiedBy(capWithSpecifier1)); + assertTrue(requestWithSpecifier1.canBeSatisfiedBy(capDualTransport)); + assertFalse(requestWithSpecifier1.canBeSatisfiedBy( new NetworkCapabilities(cap).setNetworkSpecifier(specifier2))); - assertFalse(request.canBeSatisfiedBy(cellCap)); - assertEquals(request.canBeSatisfiedBy(capWithSp), - new NetworkCapabilities(capWithSp).satisfiedByNetworkCapabilities(capWithSp)); + + final NetworkRequest request = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .build(); + assertTrue(request.canBeSatisfiedBy(cap)); + assertTrue(request.canBeSatisfiedBy(capWithSpecifier1)); + assertTrue(request.canBeSatisfiedBy( + new NetworkCapabilities(cap).setNetworkSpecifier(specifier2))); + assertFalse(request.canBeSatisfiedBy(capDiffTransportWithSpecifier1)); + assertTrue(request.canBeSatisfiedBy(capDualTransport)); + + assertEquals(requestWithSpecifier1.canBeSatisfiedBy(capWithSpecifier1), + new NetworkCapabilities(capWithSpecifier1) + .satisfiedByNetworkCapabilities(capWithSpecifier1)); } @Test @IgnoreUpTo(Build.VERSION_CODES.Q) From 11fec376f566569fa182363309a28ed6dd826ae4 Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Thu, 23 Apr 2020 03:48:45 +0000 Subject: [PATCH 3/4] Add TetheringCommonTests to CtsTetheringTest Bug: 153614365 Bug: 153613717 Test: atest CtsTetheringTest Change-Id: I26c06d522ef2935deb2b1abbd3c5b6be97a48a27 Merged-In: I26c06d522ef2935deb2b1abbd3c5b6be97a48a27 (cherry picked from commit 9903c8a61b96fe8773e27e2338c002093f7e4388, aosp/1292434) --- tests/cts/tethering/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp index 63de301d69..37894ec4dc 100644 --- a/tests/cts/tethering/Android.bp +++ b/tests/cts/tethering/Android.bp @@ -25,6 +25,7 @@ android_test { ], static_libs: [ + "TetheringCommonTests", "TetheringIntegrationTestsLib", "compatibility-device-util-axt", "ctstestrunner-axt", From f46d6a1e8d1d059d2b6597ab100786f179e5dafd Mon Sep 17 00:00:00 2001 From: Mark Chien Date: Thu, 23 Apr 2020 13:28:22 +0000 Subject: [PATCH 4/4] Test enable tethering permission and stopAllTethering 1. Test whether start tethering is gated by suitable permission. 2. Test stopAllTethering Bug: 153613718 Test: atest CtsTetheringTest Merged-In: I38702886ea355e1aec8eb8ac404fdd46a44582e3 Change-Id: I38702886ea355e1aec8eb8ac404fdd46a44582e3 --- tests/cts/tethering/Android.bp | 1 + .../tethering/cts/TetheringManagerTest.java | 274 ++++++++++++------ 2 files changed, 189 insertions(+), 86 deletions(-) diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp index 37894ec4dc..9f32403c98 100644 --- a/tests/cts/tethering/Android.bp +++ b/tests/cts/tethering/Android.bp @@ -28,6 +28,7 @@ android_test { "TetheringCommonTests", "TetheringIntegrationTestsLib", "compatibility-device-util-axt", + "net-tests-utils", "ctstestrunner-axt", "junit", "junit-params", diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index ccad14cdd2..60f9400363 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -15,20 +15,24 @@ */ package android.tethering.test; -import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; -import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; -import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHERING_WIFI_P2P; import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; +import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; +import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.app.UiAutomation; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -48,6 +52,8 @@ import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.testutils.ArrayTrackRecord; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -77,11 +83,21 @@ public class TetheringManagerTest { private static final int DEFAULT_TIMEOUT_MS = 60_000; + private void adoptShellPermissionIdentity() { + final UiAutomation uiAutomation = + InstrumentationRegistry.getInstrumentation().getUiAutomation(); + uiAutomation.adoptShellPermissionIdentity(); + } + + private void dropShellPermissionIdentity() { + final UiAutomation uiAutomation = + InstrumentationRegistry.getInstrumentation().getUiAutomation(); + uiAutomation.dropShellPermissionIdentity(); + } + @Before public void setUp() throws Exception { - InstrumentationRegistry.getInstrumentation() - .getUiAutomation() - .adoptShellPermissionIdentity(); + adoptShellPermissionIdentity(); mContext = InstrumentationRegistry.getContext(); mTM = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE); mTetherChangeReceiver = new TetherChangeReceiver(); @@ -93,10 +109,9 @@ public class TetheringManagerTest { @After public void tearDown() throws Exception { + mTM.stopAllTethering(); mContext.unregisterReceiver(mTetherChangeReceiver); - InstrumentationRegistry.getInstrumentation() - .getUiAutomation() - .dropShellPermissionIdentity(); + dropShellPermissionIdentity(); } private class TetherChangeReceiver extends BroadcastReceiver { @@ -202,15 +217,54 @@ public class TetheringManagerTest { } } - private class StartTetheringCallback implements TetheringManager.StartTetheringCallback { + private static class StartTetheringCallback implements TetheringManager.StartTetheringCallback { + private static int TIMEOUT_MS = 30_000; + public static class CallbackValue { + public final int error; + + private CallbackValue(final int e) { + error = e; + } + + public static class OnTetheringStarted extends CallbackValue { + OnTetheringStarted() { super(TETHER_ERROR_NO_ERROR); } + } + + public static class OnTetheringFailed extends CallbackValue { + OnTetheringFailed(final int error) { super(error); } + } + + @Override + public String toString() { + return String.format("%s(%d)", getClass().getSimpleName(), error); + } + } + + private final ArrayTrackRecord.ReadHead mHistory = + new ArrayTrackRecord().newReadHead(); + @Override public void onTetheringStarted() { - // Do nothing, TetherChangeReceiver will wait until it receives the broadcast. + mHistory.add(new CallbackValue.OnTetheringStarted()); } @Override public void onTetheringFailed(final int error) { - fail("startTethering fail: " + error); + mHistory.add(new CallbackValue.OnTetheringFailed(error)); + } + + public void verifyTetheringStarted() { + final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); + assertNotNull("No onTetheringStarted after " + TIMEOUT_MS + " ms", cv); + assertTrue("Fail start tethering:" + cv, + cv instanceof CallbackValue.OnTetheringStarted); + } + + public void expectTetheringFailed(final int expected) throws InterruptedException { + final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); + assertNotNull("No onTetheringFailed after " + TIMEOUT_MS + " ms", cv); + assertTrue("Expect fail with error code " + expected + ", but received: " + cv, + (cv instanceof CallbackValue.OnTetheringFailed) && (cv.error == expected)); } } @@ -244,8 +298,10 @@ public class TetheringManagerTest { mTetherChangeReceiver.expectNoActiveTethering(0 /** timeout */); final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); - mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), c -> c.run(), - startTetheringCallback); + mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), + c -> c.run() /* executor */, startTetheringCallback); + startTetheringCallback.verifyTetheringStarted(); + mTetherChangeReceiver.expectActiveTethering(wifiRegexs); mTM.stopTethering(TETHERING_WIFI); @@ -277,6 +333,7 @@ public class TetheringManagerTest { // Must poll the callback before looking at the member. private static class TestTetheringEventCallback implements TetheringEventCallback { + private static final int TIMEOUT_MS = 30_000; public enum CallbackType { ON_SUPPORTED, ON_UPSTREAM, @@ -299,7 +356,10 @@ public class TetheringManagerTest { this.callbackParam2 = param2; } } - private final LinkedBlockingQueue mCallbacks = new LinkedBlockingQueue<>(); + + private final ArrayTrackRecord.ReadHead mHistory = + new ArrayTrackRecord().newReadHead(); + private TetheringInterfaceRegexps mTetherableRegex; private List mTetherableIfaces; @@ -307,108 +367,96 @@ public class TetheringManagerTest { @Override public void onTetheringSupported(boolean supported) { - mCallbacks.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_SUPPORTED, null, 0)); } @Override public void onUpstreamChanged(Network network) { - mCallbacks.add(new CallbackValue(CallbackType.ON_UPSTREAM, network, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_UPSTREAM, network, 0)); } @Override public void onTetherableInterfaceRegexpsChanged(TetheringInterfaceRegexps reg) { mTetherableRegex = reg; - mCallbacks.add(new CallbackValue(CallbackType.ON_TETHERABLE_REGEX, reg, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_REGEX, reg, 0)); } @Override public void onTetherableInterfacesChanged(List interfaces) { mTetherableIfaces = interfaces; - mCallbacks.add(new CallbackValue(CallbackType.ON_TETHERABLE_IFACES, interfaces, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_TETHERABLE_IFACES, interfaces, 0)); } @Override public void onTetheredInterfacesChanged(List interfaces) { mTetheredIfaces = interfaces; - mCallbacks.add(new CallbackValue(CallbackType.ON_TETHERED_IFACES, interfaces, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_TETHERED_IFACES, interfaces, 0)); } @Override public void onError(String ifName, int error) { - mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, ifName, error)); + mHistory.add(new CallbackValue(CallbackType.ON_ERROR, ifName, error)); } @Override public void onClientsChanged(Collection clients) { - mCallbacks.add(new CallbackValue(CallbackType.ON_CLIENTS, clients, 0)); + mHistory.add(new CallbackValue(CallbackType.ON_CLIENTS, clients, 0)); } @Override public void onOffloadStatusChanged(int status) { - mCallbacks.add(new CallbackValue(CallbackType.ON_OFFLOAD_STATUS, status, 0)); - } - - public CallbackValue pollCallback() { - try { - return mCallbacks.poll(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - fail("Callback not seen"); - } - return null; + mHistory.add(new CallbackValue(CallbackType.ON_OFFLOAD_STATUS, status, 0)); } public void expectTetherableInterfacesChanged(@NonNull List regexs) { - while (true) { - final CallbackValue cv = pollCallback(); - if (cv == null) fail("No expected tetherable ifaces callback"); - if (cv.callbackType != CallbackType.ON_TETHERABLE_IFACES) continue; - - final List interfaces = (List) cv.callbackParam; - if (isIfaceMatch(regexs, interfaces)) break; - } + assertNotNull("No expected tetherable ifaces callback", mHistory.poll(TIMEOUT_MS, + (cv) -> { + if (cv.callbackType != CallbackType.ON_TETHERABLE_IFACES) return false; + final List interfaces = (List) cv.callbackParam; + return isIfaceMatch(regexs, interfaces); + })); } public void expectTetheredInterfacesChanged(@NonNull List regexs) { - while (true) { - final CallbackValue cv = pollCallback(); - if (cv == null) fail("No expected tethered ifaces callback"); - if (cv.callbackType != CallbackType.ON_TETHERED_IFACES) continue; + assertNotNull("No expected tethered ifaces callback", mHistory.poll(TIMEOUT_MS, + (cv) -> { + if (cv.callbackType != CallbackType.ON_TETHERED_IFACES) return false; - final List interfaces = (List) cv.callbackParam; + final List interfaces = (List) cv.callbackParam; - // Null regexs means no active tethering. - if (regexs == null) { - if (interfaces.size() == 0) break; - } else if (isIfaceMatch(regexs, interfaces)) { - break; - } - } + // Null regexs means no active tethering. + if (regexs == null) return interfaces.isEmpty(); + + return isIfaceMatch(regexs, interfaces); + })); } public void expectCallbackStarted() { + int receivedBitMap = 0; // The each bit represent a type from CallbackType.ON_*. // Expect all of callbacks except for ON_ERROR. - final int expectedBitMap = 0x7f ^ (1 << CallbackType.ON_ERROR.ordinal()); - int receivedBitMap = 0; - while (receivedBitMap != expectedBitMap) { - final CallbackValue cv = pollCallback(); + final int expectedBitMap = 0xff ^ (1 << CallbackType.ON_ERROR.ordinal()); + // Receive ON_ERROR on started callback is not matter. It just means tethering is + // failed last time, should able to continue the test this time. + while ((receivedBitMap & expectedBitMap) != expectedBitMap) { + final CallbackValue cv = mHistory.poll(TIMEOUT_MS, c -> true); if (cv == null) { fail("No expected callbacks, " + "expected bitmap: " + expectedBitMap + ", actual: " + receivedBitMap); } - receivedBitMap = receivedBitMap | (1 << cv.callbackType.ordinal()); + receivedBitMap |= (1 << cv.callbackType.ordinal()); } } public void expectOneOfOffloadStatusChanged(int... offloadStatuses) { - while (true) { - final CallbackValue cv = pollCallback(); - if (cv == null) fail("No expected offload status change callback"); - if (cv.callbackType != CallbackType.ON_OFFLOAD_STATUS) continue; + assertNotNull("No offload status changed", mHistory.poll(TIMEOUT_MS, (cv) -> { + if (cv.callbackType != CallbackType.ON_OFFLOAD_STATUS) return false; final int status = (int) cv.callbackParam; - for (int offloadStatus : offloadStatuses) if (offloadStatus == status) return; - } + for (int offloadStatus : offloadStatuses) if (offloadStatus == status) return true; + + return false; + })); } public TetheringInterfaceRegexps getTetheringInterfaceRegexps() { @@ -424,52 +472,78 @@ public class TetheringManagerTest { } } - @Test - public void testRegisterTetheringEventCallback() throws Exception { - if (!mTM.isTetheringSupported()) return; - + private TestTetheringEventCallback registerTetheringEventCallback() { final TestTetheringEventCallback tetherEventCallback = new TestTetheringEventCallback(); - mTM.registerTetheringEventCallback(c -> c.run(), tetherEventCallback); + mTM.registerTetheringEventCallback(c -> c.run() /* executor */, tetherEventCallback); tetherEventCallback.expectCallbackStarted(); - tetherEventCallback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); - final TetheringInterfaceRegexps tetherableRegexs = - tetherEventCallback.getTetheringInterfaceRegexps(); - final List wifiRegexs = tetherableRegexs.getTetherableWifiRegexs(); - if (wifiRegexs.size() == 0) return; + return tetherEventCallback; + } + private void unregisterTetheringEventCallback(final TestTetheringEventCallback callback) { + mTM.unregisterTetheringEventCallback(callback); + } + + private List getWifiTetherableInterfaceRegexps( + final TestTetheringEventCallback callback) { + return callback.getTetheringInterfaceRegexps().getTetherableWifiRegexs(); + } + + private boolean isWifiTetheringSupported(final TestTetheringEventCallback callback) { + return !getWifiTetherableInterfaceRegexps(callback).isEmpty(); + } + + private void startWifiTethering(final TestTetheringEventCallback callback) + throws InterruptedException { + final List wifiRegexs = getWifiTetherableInterfaceRegexps(callback); final boolean isIfaceAvailWhenNoTethering = - isIfaceMatch(wifiRegexs, tetherEventCallback.getTetherableInterfaces()); + isIfaceMatch(wifiRegexs, callback.getTetherableInterfaces()); - mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), c -> c.run(), - new StartTetheringCallback()); + final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); + mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), + c -> c.run() /* executor */, startTetheringCallback); + startTetheringCallback.verifyTetheringStarted(); // If interface is already available before starting tethering, the available callback may // not be sent after tethering enabled. if (!isIfaceAvailWhenNoTethering) { - tetherEventCallback.expectTetherableInterfacesChanged(wifiRegexs); + callback.expectTetherableInterfacesChanged(wifiRegexs); } - tetherEventCallback.expectTetheredInterfacesChanged(wifiRegexs); - tetherEventCallback.expectOneOfOffloadStatusChanged( + callback.expectTetheredInterfacesChanged(wifiRegexs); + + callback.expectOneOfOffloadStatusChanged( TETHER_HARDWARE_OFFLOAD_STARTED, TETHER_HARDWARE_OFFLOAD_FAILED); + } + private void stopWifiTethering(final TestTetheringEventCallback callback) { mTM.stopTethering(TETHERING_WIFI); + callback.expectTetheredInterfacesChanged(null); + callback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); + } - tetherEventCallback.expectTetheredInterfacesChanged(null); - tetherEventCallback.expectOneOfOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); - mTM.unregisterTetheringEventCallback(tetherEventCallback); + @Test + public void testRegisterTetheringEventCallback() throws Exception { + if (!mTM.isTetheringSupported()) return; + + final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + + if (!isWifiTetheringSupported(tetherEventCallback)) return; + + startWifiTethering(tetherEventCallback); + + stopWifiTethering(tetherEventCallback); + + unregisterTetheringEventCallback(tetherEventCallback); } @Test public void testGetTetherableInterfaceRegexps() { if (!mTM.isTetheringSupported()) return; - final TestTetheringEventCallback tetherEventCallback = new TestTetheringEventCallback(); - mTM.registerTetheringEventCallback(c -> c.run(), tetherEventCallback); - tetherEventCallback.expectCallbackStarted(); + final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); final TetheringInterfaceRegexps tetherableRegexs = tetherEventCallback.getTetheringInterfaceRegexps(); @@ -486,7 +560,35 @@ public class TetheringManagerTest { wifiRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); usbRegexs.forEach(s -> assertFalse(btRegexs.contains(s))); - mTM.unregisterTetheringEventCallback(tetherEventCallback); + unregisterTetheringEventCallback(tetherEventCallback); + } + + @Test + public void testStopAllTethering() throws Exception { + if (!mTM.isTetheringSupported()) return; + + final TestTetheringEventCallback tetherEventCallback = registerTetheringEventCallback(); + + if (!isWifiTetheringSupported(tetherEventCallback)) return; + + // TODO: start ethernet tethering here when TetheringManagerTest is moved to + // TetheringIntegrationTest. + + startWifiTethering(tetherEventCallback); + + mTM.stopAllTethering(); + tetherEventCallback.expectTetheredInterfacesChanged(null); + + unregisterTetheringEventCallback(tetherEventCallback); + } + + @Test + public void testEnableTetheringPermission() throws Exception { + dropShellPermissionIdentity(); + final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); + mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), + c -> c.run() /* executor */, startTetheringCallback); + startTetheringCallback.expectTetheringFailed(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); } private class EntitlementResultListener implements OnTetheringEntitlementResultListener {