Merge master@5406228 into git_qt-dev-plus-aosp.
am: e2fd217b4c
Change-Id: If7519cde0ca214277d6e13627a9dbc6de994ceed
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java
index a4a2956..124c2c3 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/PacketReflector.java
@@ -16,6 +16,11 @@
package com.android.cts.net.hostside;
+import static android.system.OsConstants.ICMP6_ECHO_REPLY;
+import static android.system.OsConstants.ICMP6_ECHO_REQUEST;
+import static android.system.OsConstants.ICMP_ECHO;
+import static android.system.OsConstants.ICMP_ECHOREPLY;
+
import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
@@ -47,8 +52,6 @@
private static final byte ICMP_ECHO = 8;
private static final byte ICMP_ECHOREPLY = 0;
- private static final byte ICMPV6_ECHO_REQUEST = (byte) 128;
- private static final byte ICMPV6_ECHO_REPLY = (byte) 129;
private static String TAG = "PacketReflector";
@@ -125,7 +128,7 @@
byte type = buf[hdrLen];
if (!(version == 4 && type == ICMP_ECHO) &&
- !(version == 6 && type == ICMPV6_ECHO_REQUEST)) {
+ !(version == 6 && type == (byte) ICMP6_ECHO_REQUEST)) {
return;
}
@@ -145,10 +148,18 @@
return;
}
+ byte replyType = buf[hdrLen];
+ if ((type == ICMP_ECHO && replyType != ICMP_ECHOREPLY)
+ || (type == (byte) ICMP6_ECHO_REQUEST && replyType != (byte) ICMP6_ECHO_REPLY)) {
+ Log.i(TAG, "Received unexpected ICMP reply: original " + type
+ + ", reply " + replyType);
+ return;
+ }
+
// Compare the response we got with the original packet.
// The only thing that should have changed are addresses, type and checksum.
// Overwrite them with the received bytes and see if the packet is otherwise identical.
- request[hdrLen] = buf[hdrLen]; // Type.
+ request[hdrLen] = buf[hdrLen]; // Type
request[hdrLen + 2] = buf[hdrLen + 2]; // Checksum byte 1.
request[hdrLen + 3] = buf[hdrLen + 3]; // Checksum byte 2.
diff --git a/tests/cts/net/jni/NativeDnsJni.c b/tests/cts/net/jni/NativeDnsJni.c
index 352c0c5..6d3d1c3 100644
--- a/tests/cts/net/jni/NativeDnsJni.c
+++ b/tests/cts/net/jni/NativeDnsJni.c
@@ -120,8 +120,8 @@
gai_strerror(res));
return JNI_FALSE;
}
- if (strstr(buf, "google.com") == NULL) {
- ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com: %s",
+ if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) {
+ ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s",
GoogleDNSIpV4Address, buf);
return JNI_FALSE;
}
@@ -133,8 +133,9 @@
res, gai_strerror(res));
return JNI_FALSE;
}
- if (strstr(buf, "google.com") == NULL) {
- ALOGD("getnameinfo(%s) didn't return google.com: %s", GoogleDNSIpV6Address2, buf);
+ if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) {
+ ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s",
+ GoogleDNSIpV6Address2, buf);
return JNI_FALSE;
}
diff --git a/tests/cts/net/jni/NativeMultinetworkJni.cpp b/tests/cts/net/jni/NativeMultinetworkJni.cpp
index d1a92a4..a6b5e90 100644
--- a/tests/cts/net/jni/NativeMultinetworkJni.cpp
+++ b/tests/cts/net/jni/NativeMultinetworkJni.cpp
@@ -245,13 +245,12 @@
net_handle_t handle = (net_handle_t) nethandle;
int fd = android_res_nquery(handle, kGoogleName, ns_c_in, ns_t_a, 0);
- int rcode = -1;
- uint8_t buf[MAXPACKET] = {};
+ errno = 0;
android_res_cancel(fd);
- EXPECT_EQ(env, -EBADF, android_res_nresult(fd, &rcode, buf, MAXPACKET), "res_cancel");
-
- android_res_cancel(fd);
- EXPECT_EQ(env, -EBADF, android_res_nresult(fd, &rcode, buf, MAXPACKET), "res_cancel");
+ int err = errno;
+ EXPECT_EQ(env, 0, err, "res_cancel");
+ // DO NOT call cancel or result with the same fd more than once,
+ // otherwise it will hit fdsan double-close fd.
return 0;
}
@@ -288,10 +287,10 @@
fd = android_res_nsend(handle, largeBuf, sizeof(largeBuf), 0);
EXPECT_EQ(env, -EMSGSIZE, fd, "res_nsend buffer larger than 8KB");
- // 1000 bytes filled with 0. This returns EMSGSIZE because FrameworkListener limits the size of
- // commands to 1024 bytes. TODO: b/126307309
- fd = android_res_nsend(handle, largeBuf, 1000, 0);
- EXPECT_EQ(env, -EMSGSIZE, fd, "res_nsend 1000 bytes filled with 0");
+ // 5000 bytes filled with 0. This returns EMSGSIZE because FrameworkListener limits the size of
+ // commands to 4096 bytes.
+ fd = android_res_nsend(handle, largeBuf, 5000, 0);
+ EXPECT_EQ(env, -EMSGSIZE, fd, "res_nsend 5000 bytes filled with 0");
// 500 bytes filled with 0
fd = android_res_nsend(handle, largeBuf, 500, 0);
@@ -299,16 +298,16 @@
EXPECT_EQ(env, 0, expectAnswersNotValid(env, fd, -EINVAL),
"res_nsend 500 bytes filled with 0 check answers");
- // 1000 bytes filled with 0xFF
- uint8_t ffBuf[1001] = {};
+ // 5000 bytes filled with 0xFF
+ uint8_t ffBuf[5001] = {};
memset(ffBuf, 0xFF, sizeof(ffBuf));
- ffBuf[1000] = '\0';
+ ffBuf[5000] = '\0';
fd = android_res_nsend(handle, ffBuf, sizeof(ffBuf), 0);
- EXPECT_EQ(env, -EMSGSIZE, fd, "res_nsend 1000 bytes filled with 0xFF");
+ EXPECT_EQ(env, -EMSGSIZE, fd, "res_nsend 5000 bytes filled with 0xFF");
// 500 bytes filled with 0xFF
- ffBuf[501] = '\0';
- fd = android_res_nsend(handle, ffBuf, 500, 0);
+ ffBuf[500] = '\0';
+ fd = android_res_nsend(handle, ffBuf, 501, 0);
EXPECT_GE(env, fd, 0, "res_nsend 500 bytes filled with 0xFF");
EXPECT_EQ(env, 0, expectAnswersNotValid(env, fd, -EINVAL),
"res_nsend 500 bytes filled with 0xFF check answers");
diff --git a/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp b/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp
index 2fc9ff8..e501475 100644
--- a/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp
+++ b/tests/cts/net/native/dns/NativeDnsAsyncTest.cpp
@@ -194,13 +194,12 @@
TEST (NativeDnsAsyncTest, Async_Cancel) {
int fd = android_res_nquery(
NETWORK_UNSPECIFIED, "www.google.com", ns_c_in, ns_t_a, 0);
- int rcode = -1;
- uint8_t buf[MAXPACKET] = {};
+ errno = 0;
android_res_cancel(fd);
- android_res_cancel(fd);
-
- int res = android_res_nresult(fd, &rcode, buf, MAXPACKET);
- EXPECT_EQ(-EBADF, res);
+ int err = errno;
+ EXPECT_EQ(err, 0);
+ // DO NOT call cancel or result with the same fd more than once,
+ // otherwise it will hit fdsan double-close fd.
}
TEST (NativeDnsAsyncTest, Async_Query_MALFORMED) {
@@ -235,9 +234,9 @@
NETWORK_UNSPECIFIED, largeBuf.data(), largeBuf.size(), 0);
EXPECT_EQ(-EMSGSIZE, fd);
- // 1000 bytes filled with 0. This returns EMSGSIZE because FrameworkListener limits the size of
- // commands to 1024 bytes. TODO: fix this.
- fd = android_res_nsend(NETWORK_UNSPECIFIED, largeBuf.data(), 1000, 0);
+ // 5000 bytes filled with 0. This returns EMSGSIZE because FrameworkListener limits the size of
+ // commands to 4096 bytes.
+ fd = android_res_nsend(NETWORK_UNSPECIFIED, largeBuf.data(), 5000, 0);
EXPECT_EQ(-EMSGSIZE, fd);
// 500 bytes filled with 0
@@ -245,8 +244,8 @@
EXPECT_GE(fd, 0);
expectAnswersNotValid(fd, -EINVAL);
- // 1000 bytes filled with 0xFF
- std::vector<uint8_t> ffBuf(1000, 0xFF);
+ // 5000 bytes filled with 0xFF
+ std::vector<uint8_t> ffBuf(5000, 0xFF);
fd = android_res_nsend(
NETWORK_UNSPECIFIED, ffBuf.data(), ffBuf.size(), 0);
EXPECT_EQ(-EMSGSIZE, fd);
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 5077f55..cb1aa09 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -23,12 +23,17 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.AF_UNSPEC;
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
import android.app.Instrumentation;
import android.app.PendingIntent;
+import android.app.UiAutomation;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -46,8 +51,10 @@
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkInfo.State;
import android.net.NetworkRequest;
+import android.net.SocketKeepalive;
import android.net.wifi.WifiManager;
import android.os.Looper;
+import android.os.MessageQueue;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Settings;
@@ -65,11 +72,13 @@
import libcore.io.Streams;
+import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
+import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -80,6 +89,7 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
@@ -97,7 +107,11 @@
private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1
private static final String TEST_HOST = "connectivitycheck.gstatic.com";
private static final int SOCKET_TIMEOUT_MS = 2000;
+ private static final int CONNECT_TIMEOUT_MS = 2000;
+ private static final int KEEPALIVE_CALLBACK_TIMEOUT_MS = 2000;
+ private static final int KEEPALIVE_SOCKET_TIMEOUT_MS = 5000;
private static final int SEND_BROADCAST_TIMEOUT = 30000;
+ private static final int MIN_KEEPALIVE_INTERVAL = 10;
private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 5000;
private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20;
private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500;
@@ -127,7 +141,8 @@
new HashMap<Integer, NetworkConfig>();
boolean mWifiConnectAttempted;
private TestNetworkCallback mCellNetworkCallback;
-
+ private UiAutomation mUiAutomation;
+ private boolean mShellPermissionIdentityAdopted;
@Override
protected void setUp() throws Exception {
@@ -154,6 +169,8 @@
mNetworks.put(n.type, n);
} catch (Exception e) {}
}
+ mUiAutomation = mInstrumentation.getUiAutomation();
+ mShellPermissionIdentityAdopted = false;
}
@Override
@@ -165,6 +182,7 @@
if (cellConnectAttempted()) {
disconnectFromCell();
}
+ dropShellPermissionIdentity();
super.tearDown();
}
@@ -1038,4 +1056,226 @@
setWifiMeteredStatus(ssid, oldMeteredSetting);
}
}
+
+ // TODO: move the following socket keep alive test to dedicated test class.
+ /**
+ * Callback used in tcp keepalive offload that allows caller to wait callback fires.
+ */
+ private static class TestSocketKeepaliveCallback extends SocketKeepalive.Callback {
+ public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
+
+ public static class CallbackValue {
+ public final CallbackType callbackType;
+ public final int error;
+
+ private CallbackValue(final CallbackType type, final int error) {
+ this.callbackType = type;
+ this.error = error;
+ }
+
+ public static class OnStartedCallback extends CallbackValue {
+ OnStartedCallback() { super(CallbackType.ON_STARTED, 0); }
+ }
+
+ public static class OnStoppedCallback extends CallbackValue {
+ OnStoppedCallback() { super(CallbackType.ON_STOPPED, 0); }
+ }
+
+ public static class OnErrorCallback extends CallbackValue {
+ OnErrorCallback(final int error) { super(CallbackType.ON_ERROR, error); }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o.getClass() == this.getClass()
+ && this.callbackType == ((CallbackValue) o).callbackType
+ && this.error == ((CallbackValue) o).error;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType, error);
+ }
+ }
+
+ private final LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
+
+ @Override
+ public void onStarted() {
+ mCallbacks.add(new CallbackValue.OnStartedCallback());
+ }
+
+ @Override
+ public void onStopped() {
+ mCallbacks.add(new CallbackValue.OnStoppedCallback());
+ }
+
+ @Override
+ public void onError(final int error) {
+ mCallbacks.add(new CallbackValue.OnErrorCallback(error));
+ }
+
+ public CallbackValue pollCallback() {
+ try {
+ return mCallbacks.poll(KEEPALIVE_CALLBACK_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("Callback not seen after " + KEEPALIVE_CALLBACK_TIMEOUT_MS + " ms");
+ }
+ return null;
+ }
+ private void expectCallback(CallbackValue expectedCallback) {
+ final CallbackValue actualCallback = pollCallback();
+ assertEquals(expectedCallback, actualCallback);
+ }
+
+ public void expectStarted() {
+ expectCallback(new CallbackValue.OnStartedCallback());
+ }
+
+ public void expectStopped() {
+ expectCallback(new CallbackValue.OnStoppedCallback());
+ }
+
+ public void expectError(int error) {
+ expectCallback(new CallbackValue.OnErrorCallback(error));
+ }
+ }
+
+ private InetAddress getAddrByName(final String hostname, final int family) throws Exception {
+ final InetAddress[] allAddrs = InetAddress.getAllByName(hostname);
+ for (InetAddress addr : allAddrs) {
+ if (family == AF_INET && addr instanceof Inet4Address) return addr;
+
+ if (family == AF_INET6 && addr instanceof Inet6Address) return addr;
+
+ if (family == AF_UNSPEC) return addr;
+ }
+ return null;
+ }
+
+ private Socket getConnectedSocket(final Network network, final String host, final int port,
+ final int socketTimeOut, final int family) throws Exception {
+ final Socket s = network.getSocketFactory().createSocket();
+ try {
+ final InetAddress addr = getAddrByName(host, family);
+ if (addr == null) fail("Fail to get destination address for " + family);
+
+ final InetSocketAddress sockAddr = new InetSocketAddress(addr, port);
+ s.setSoTimeout(socketTimeOut);
+ s.connect(sockAddr, CONNECT_TIMEOUT_MS);
+ } catch (Exception e) {
+ s.close();
+ throw e;
+ }
+ return s;
+ }
+
+ private boolean isKeepaliveSupported() throws Exception {
+ final Network network = ensureWifiConnected();
+ final Executor executor = mContext.getMainExecutor();
+ final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback();
+ try (Socket s = getConnectedSocket(network, TEST_HOST,
+ HTTP_PORT, KEEPALIVE_SOCKET_TIMEOUT_MS, AF_INET);
+ SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) {
+ sk.start(MIN_KEEPALIVE_INTERVAL);
+ final TestSocketKeepaliveCallback.CallbackValue result = callback.pollCallback();
+ switch (result.callbackType) {
+ case ON_STARTED:
+ sk.stop();
+ callback.expectStopped();
+ return true;
+ case ON_ERROR:
+ if (result.error == SocketKeepalive.ERROR_UNSUPPORTED) return false;
+ // else fallthrough.
+ default:
+ fail("Got unexpected callback: " + result);
+ return false;
+ }
+ }
+ }
+
+ private void adoptShellPermissionIdentity() {
+ mUiAutomation.adoptShellPermissionIdentity();
+ mShellPermissionIdentityAdopted = true;
+ }
+
+ private void dropShellPermissionIdentity() {
+ if (mShellPermissionIdentityAdopted) {
+ mUiAutomation.dropShellPermissionIdentity();
+ mShellPermissionIdentityAdopted = false;
+ }
+ }
+
+ public void testCreateTcpKeepalive() throws Exception {
+ adoptShellPermissionIdentity();
+
+ if (!isKeepaliveSupported()) return;
+
+ final Network network = ensureWifiConnected();
+ final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8");
+ // So far only ipv4 tcp keepalive offload is supported.
+ // TODO: add test case for ipv6 tcp keepalive offload when it is supported.
+ try (Socket s = getConnectedSocket(network, TEST_HOST, HTTP_PORT,
+ KEEPALIVE_SOCKET_TIMEOUT_MS, AF_INET)) {
+
+ // Should able to start keep alive offload when socket is idle.
+ final Executor executor = mContext.getMainExecutor();
+ final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback();
+ try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) {
+ sk.start(MIN_KEEPALIVE_INTERVAL);
+ callback.expectStarted();
+
+ // App should not able to write during keepalive offload.
+ final OutputStream out = s.getOutputStream();
+ try {
+ out.write(requestBytes);
+ fail("Should not able to write");
+ } catch (IOException e) { }
+ // App should not able to read during keepalive offload.
+ final InputStream in = s.getInputStream();
+ byte[] responseBytes = new byte[4096];
+ try {
+ in.read(responseBytes);
+ fail("Should not able to read");
+ } catch (IOException e) { }
+
+ // Stop.
+ sk.stop();
+ callback.expectStopped();
+ }
+
+ // Ensure socket is still connected.
+ assertTrue(s.isConnected());
+ assertFalse(s.isClosed());
+
+ // Let socket be not idle.
+ try {
+ final OutputStream out = s.getOutputStream();
+ out.write(requestBytes);
+ } catch (IOException e) {
+ fail("Failed to write data " + e);
+ }
+ // Make sure response data arrives.
+ final MessageQueue fdHandlerQueue = Looper.getMainLooper().getQueue();
+ final FileDescriptor fd = s.getFileDescriptor$();
+ final CountDownLatch mOnReceiveLatch = new CountDownLatch(1);
+ fdHandlerQueue.addOnFileDescriptorEventListener(fd, EVENT_INPUT, (readyFd, events) -> {
+ mOnReceiveLatch.countDown();
+ return 0; // Unregister listener.
+ });
+ if (!mOnReceiveLatch.await(2, TimeUnit.SECONDS)) {
+ fdHandlerQueue.removeOnFileDescriptorEventListener(fd);
+ fail("Timeout: no response data");
+ }
+
+ // Should get ERROR_SOCKET_NOT_IDLE because there is still data in the receive queue
+ // that has not been read.
+ try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) {
+ sk.start(MIN_KEEPALIVE_INTERVAL);
+ callback.expectError(SocketKeepalive.ERROR_SOCKET_NOT_IDLE);
+ }
+
+ }
+ }
}
diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java
index f6cc768..0ff6cd8 100644
--- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java
+++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java
@@ -370,7 +370,6 @@
@Override
public void onQueryException(@NonNull ErrnoException e) {
- if (mCancelSignal.isCanceled() && e.errno == EBADF) return;
fail(mMsg + e.getMessage());
}
}
@@ -380,7 +379,7 @@
final String msg = "Test cancel query " + dname;
// Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect
// that the query is cancelled before it succeeds. If it is not cancelled before it
- // succeeds, retry the until it is.
+ // succeeds, retry the test until it is.
for (Network network : getTestableNetworks()) {
boolean retry = false;
int round = 0;
@@ -426,7 +425,7 @@
final String msg = "Test cancel raw Query " + byteArrayToHexString(blob);
// Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect
// that the query is cancelled before it succeeds. If it is not cancelled before it
- // succeeds, retry the until it is.
+ // succeeds, retry the test until it is.
for (Network network : getTestableNetworks()) {
boolean retry = false;
int round = 0;
@@ -470,4 +469,108 @@
}
}
}
+
+ /**
+ * A query callback for InetAddress that ensures that the query is
+ * cancelled and that onAnswer is never called. If the query succeeds
+ * before it is cancelled, needRetry will return true so the
+ * test can retry.
+ */
+ class VerifyCancelInetAddressCallback extends DnsResolver.InetAddressAnswerCallback {
+ private static final int CANCEL_TIMEOUT = 3_000;
+
+ private final CountDownLatch mLatch = new CountDownLatch(1);
+ private final String mMsg;
+ private final List<InetAddress> mAnswers;
+ private final CancellationSignal mCancelSignal;
+
+ VerifyCancelInetAddressCallback(@NonNull String msg, @Nullable CancellationSignal cancel) {
+ this.mMsg = msg;
+ this.mCancelSignal = cancel;
+ mAnswers = new ArrayList<>();
+ }
+
+ public boolean waitForAnswer() throws InterruptedException {
+ return mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ }
+
+ public boolean needRetry() throws InterruptedException {
+ return mLatch.await(CANCEL_TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+
+ public boolean isAnswerEmpty() {
+ return mAnswers.isEmpty();
+ }
+
+ @Override
+ public void onAnswer(@NonNull List<InetAddress> answerList) {
+ if (mCancelSignal != null && mCancelSignal.isCanceled()) {
+ fail(mMsg + " should not have returned any answers");
+ }
+ mAnswers.clear();
+ mAnswers.addAll(answerList);
+ mLatch.countDown();
+ }
+
+ @Override
+ public void onParseException(@NonNull ParseException e) {
+ fail(mMsg + e.getMessage());
+ }
+
+ @Override
+ public void onQueryException(@NonNull ErrnoException e) {
+ fail(mMsg + e.getMessage());
+ }
+ }
+
+ public void testQueryForInetAddress() {
+ final String dname = "www.google.com";
+ final String msg = "Test query for InetAddress " + dname;
+ for (Network network : getTestableNetworks()) {
+ final VerifyCancelInetAddressCallback callback =
+ new VerifyCancelInetAddressCallback(msg, null);
+ mDns.query(network, dname, FLAG_NO_CACHE_LOOKUP,
+ mExecutor, null, callback);
+ try {
+ assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
+ callback.waitForAnswer());
+ assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
+ } catch (InterruptedException e) {
+ fail(msg + " Waiting for DNS lookup was interrupted");
+ }
+ }
+ }
+
+ public void testQueryCancelForInetAddress() throws ErrnoException {
+ final String dname = "www.google.com";
+ final String msg = "Test cancel query for InetAddress " + dname;
+ // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect
+ // that the query is cancelled before it succeeds. If it is not cancelled before it
+ // succeeds, retry the test until it is.
+ for (Network network : getTestableNetworks()) {
+ boolean retry = false;
+ int round = 0;
+ do {
+ if (++round > CANCEL_RETRY_TIMES) {
+ fail(msg + " cancel failed " + CANCEL_RETRY_TIMES + " times");
+ }
+ final CountDownLatch latch = new CountDownLatch(1);
+ final CancellationSignal cancelSignal = new CancellationSignal();
+ final VerifyCancelInetAddressCallback callback =
+ new VerifyCancelInetAddressCallback(msg, cancelSignal);
+ mDns.query(network, dname, FLAG_EMPTY, mExecutor, cancelSignal, callback);
+ mExecutor.execute(() -> {
+ cancelSignal.cancel();
+ latch.countDown();
+ });
+ try {
+ retry = callback.needRetry();
+ assertTrue(msg + " query was not cancelled",
+ latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ fail(msg + "Waiting for DNS lookup was interrupted");
+ }
+ } while (retry);
+ }
+ }
}
diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java
index af096da..503ba51 100755
--- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java
+++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java
@@ -16,15 +16,14 @@
package android.net.cts;
+import android.content.pm.PackageManager;
import android.net.NetworkStats;
import android.net.TrafficStats;
import android.os.Process;
+import android.os.SystemProperties;
import android.test.AndroidTestCase;
import android.util.Log;
-import java.io.BufferedReader;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -237,19 +236,37 @@
uidRxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets + deltaRxOtherPackets, 0));
// Localhost traffic *does* count against total stats.
- // Fudge by 132 packets of 1500 bytes not related to the test.
+ // Check the total stats increased after test data transfer over localhost has been made.
assertTrue("ttxp: " + totalTxPacketsBefore + " -> " + totalTxPacketsAfter,
- totalTxPacketsAfter >= totalTxPacketsBefore + uidTxDeltaPackets &&
- totalTxPacketsAfter <= totalTxPacketsBefore + uidTxDeltaPackets + 132);
+ totalTxPacketsAfter >= totalTxPacketsBefore + uidTxDeltaPackets);
assertTrue("trxp: " + totalRxPacketsBefore + " -> " + totalRxPacketsAfter,
- totalRxPacketsAfter >= totalRxPacketsBefore + uidRxDeltaPackets &&
- totalRxPacketsAfter <= totalRxPacketsBefore + uidRxDeltaPackets + 132);
+ totalRxPacketsAfter >= totalRxPacketsBefore + uidRxDeltaPackets);
assertTrue("ttxb: " + totalTxBytesBefore + " -> " + totalTxBytesAfter,
- totalTxBytesAfter >= totalTxBytesBefore + uidTxDeltaBytes &&
- totalTxBytesAfter <= totalTxBytesBefore + uidTxDeltaBytes + 132 * 1500);
+ totalTxBytesAfter >= totalTxBytesBefore + uidTxDeltaBytes);
assertTrue("trxb: " + totalRxBytesBefore + " -> " + totalRxBytesAfter,
- totalRxBytesAfter >= totalRxBytesBefore + uidRxDeltaBytes &&
- totalRxBytesAfter <= totalRxBytesBefore + uidRxDeltaBytes + 132 * 1500);
+ totalRxBytesAfter >= totalRxBytesBefore + uidRxDeltaBytes);
+
+ // If the adb TCP port is opened, this test may be run by adb over network.
+ // Huge amount of data traffic might go through the network and accounted into total packets
+ // stats. The upper bound check would be meaningless.
+ // TODO: Consider precisely calculate the traffic accounted due to adb over network and
+ // subtract it when checking upper bound instead of skip checking.
+ final PackageManager pm = mContext.getPackageManager();
+ if (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1
+ || SystemProperties.getInt("service.adb.tcp.port", -1) > -1
+ || !pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY)) {
+ Log.i(LOG_TAG, "adb is running over the network, skip the upper bound check");
+ } else {
+ // Fudge by 132 packets of 1500 bytes not related to the test.
+ assertTrue("ttxp: " + totalTxPacketsBefore + " -> " + totalTxPacketsAfter,
+ totalTxPacketsAfter <= totalTxPacketsBefore + uidTxDeltaPackets + 132);
+ assertTrue("trxp: " + totalRxPacketsBefore + " -> " + totalRxPacketsAfter,
+ totalRxPacketsAfter <= totalRxPacketsBefore + uidRxDeltaPackets + 132);
+ assertTrue("ttxb: " + totalTxBytesBefore + " -> " + totalTxBytesAfter,
+ totalTxBytesAfter <= totalTxBytesBefore + uidTxDeltaBytes + 132 * 1500);
+ assertTrue("trxb: " + totalRxBytesBefore + " -> " + totalRxBytesAfter,
+ totalRxBytesAfter <= totalRxBytesBefore + uidRxDeltaBytes + 132 * 1500);
+ }
// Localhost traffic should *not* count against mobile stats,
// There might be some other traffic, but nowhere near 1MB.
@@ -265,6 +282,5 @@
assertTrue("mrxb: " + mobileRxBytesBefore + " -> " + mobileRxBytesAfter,
mobileRxBytesAfter >= mobileRxBytesBefore &&
mobileRxBytesAfter <= mobileRxBytesBefore + 200000);
-
}
}
diff --git a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java
index c23ad30..146fd83 100644
--- a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java
+++ b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java
@@ -61,7 +61,7 @@
/** The beginning of an ICMPv6 echo request: type, code, and uninitialized checksum. */
private static final byte[] PING_HEADER = new byte[] {
- (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00
+ (byte) ICMP6_ECHO_REQUEST, (byte) 0x00, (byte) 0x00, (byte) 0x00
};
/**
@@ -135,7 +135,7 @@
byte[] response = new byte[bytesRead];
responseBuffer.flip();
responseBuffer.get(response, 0, bytesRead);
- assertEquals((byte) 0x81, response[0]);
+ assertEquals((byte) ICMP6_ECHO_REPLY, response[0]);
// Find out what ICMP ID was used in the packet that was sent.
int id = ((InetSocketAddress) Os.getsockname(s)).getPort();
diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java
index 93795b2..1d66682 100644
--- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java
@@ -882,6 +882,30 @@
}
/**
+ * Verify that the {@link android.Manifest.permission#NETWORK_CARRIER_PROVISIONING} permission
+ * is held by at most one application.
+ */
+ public void testNetworkCarrierProvisioningPermission() {
+ final PackageManager pm = getContext().getPackageManager();
+
+ final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] {
+ android.Manifest.permission.NETWORK_CARRIER_PROVISIONING
+ }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
+
+ List<String> uniquePackageNames = holding
+ .stream()
+ .map(pi -> pi.packageName)
+ .distinct()
+ .collect(Collectors.toList());
+
+ if (uniquePackageNames.size() > 1) {
+ fail("The NETWORK_CARRIER_PROVISIONING permission must not be held by more than one "
+ + "application, but is held by " + uniquePackageNames.size() + " applications: "
+ + String.join(", ", uniquePackageNames));
+ }
+ }
+
+ /**
* Verify that the {@link android.Manifest.permission#WIFI_UPDATE_USABILITY_STATS_SCORE}
* permission is held by at most one application.
*/