Merge "Lookup private resources in run-time"
diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk
index a6543b3..7219fc4 100644
--- a/tests/cts/net/Android.mk
+++ b/tests/cts/net/Android.mk
@@ -30,7 +30,7 @@
LOCAL_PACKAGE_NAME := CtsNetTestCases
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctsutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctsdeviceutil ctstestrunner
# uncomment when dalvik.annotation.Test* are removed or part of SDK
#LOCAL_SDK_VERSION := current
diff --git a/tests/cts/net/jni/NativeDnsJni.c b/tests/cts/net/jni/NativeDnsJni.c
index de9bb67..b975594 100644
--- a/tests/cts/net/jni/NativeDnsJni.c
+++ b/tests/cts/net/jni/NativeDnsJni.c
@@ -20,6 +20,11 @@
#include <stdio.h>
#include <utils/Log.h>
+const char *GoogleDNSIpV4Address="8.8.8.8";
+const char *GoogleDNSIpV4Address2="8.8.4.4";
+const char *GoogleDNSIpV6Address="2001:4860:4860::8888";
+const char *GoogleDNSIpV6Address2="2001:4860:4860::8844";
+
JNIEXPORT jboolean Java_android_net_cts_DnsTest_testNativeDns(JNIEnv* env, jclass class)
{
const char *node = "www.google.com";
@@ -53,8 +58,8 @@
freeaddrinfo(answer);
answer = NULL;
- if (foundv4 != 1 || foundv6 != 1) {
- ALOGD("getaddrinfo(www.google.com) didn't find both v4 and v6");
+ if (foundv4 != 1 && foundv6 != 1) {
+ ALOGD("getaddrinfo(www.google.com) didn't find either v4 or v6 address");
return JNI_FALSE;
}
}
@@ -96,49 +101,50 @@
struct sockaddr_in sa4;
sa4.sin_family = AF_INET;
sa4.sin_port = 0;
- inet_pton(AF_INET, "173.252.110.27", &(sa4.sin_addr));
+ inet_pton(AF_INET, GoogleDNSIpV4Address, &(sa4.sin_addr));
struct sockaddr_in6 sa6;
sa6.sin6_family = AF_INET6;
sa6.sin6_port = 0;
sa6.sin6_flowinfo = 0;
sa6.sin6_scope_id = 0;
- inet_pton(AF_INET6, "2001:4860:4001:802::1008", &(sa6.sin6_addr));
+ inet_pton(AF_INET6, GoogleDNSIpV6Address2, &(sa6.sin6_addr));
char buf[NI_MAXHOST];
int flags = NI_NAMEREQD;
res = getnameinfo((const struct sockaddr*)&sa4, sizeof(sa4), buf, sizeof(buf), NULL, 0, flags);
if (res != 0) {
- ALOGD("getnameinfo(173.252.110.27 (facebook) ) gave error %d (%s)", res, gai_strerror(res));
+ ALOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV4Address, res,
+ gai_strerror(res));
return JNI_FALSE;
}
- if (strstr(buf, "facebook.com") == NULL) {
- ALOGD("getnameinfo(173.252.110.27 (facebook) ) didn't return facebook.com: %s", buf);
+ if (strstr(buf, "google.com") == NULL) {
+ ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com: %s",
+ GoogleDNSIpV4Address, buf);
return JNI_FALSE;
}
memset(buf, sizeof(buf), 0);
- res = getnameinfo((const struct sockaddr*)&sa6, sizeof(sa6), buf, sizeof(buf),
- NULL, 0, flags);
+ res = getnameinfo((const struct sockaddr*)&sa6, sizeof(sa6), buf, sizeof(buf), NULL, 0, flags);
if (res != 0) {
- ALOGD("getnameinfo(2a03:2880:2110:df01:face:b00c::8 (facebook) ) gave error %d (%s)",
- res, gai_strerror(res));
+ ALOGD("getnameinfo(%s (GoogleDNS) ) gave error %d (%s)", GoogleDNSIpV6Address2,
+ res, gai_strerror(res));
return JNI_FALSE;
}
- if (strstr(buf, "1e100.net") == NULL) {
- ALOGD("getnameinfo(2a03:2880:2110:df01:face:b00c::8) didn't return facebook.com: %s", buf);
+ if (strstr(buf, "google.com") == NULL) {
+ ALOGD("getnameinfo(%s) didn't return google.com: %s", GoogleDNSIpV6Address2, buf);
return JNI_FALSE;
}
// gethostbyname
- struct hostent *my_hostent = gethostbyname("www.mit.edu");
+ struct hostent *my_hostent = gethostbyname("www.youtube.com");
if (my_hostent == NULL) {
- ALOGD("gethostbyname(www.mit.edu) gave null response");
+ ALOGD("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.mit.edu) gave 0 addresses");
+ ALOGD("gethostbyname(www.youtube.com) gave 0 addresses");
return JNI_FALSE;
}
{
@@ -146,21 +152,23 @@
while (*current != NULL) {
char buf[256];
inet_ntop(my_hostent->h_addrtype, *current, buf, sizeof(buf));
- ALOGD("gethostbyname(www.mit.edu) gave %s", buf);
+ ALOGD("gethostbyname(www.youtube.com) gave %s", buf);
current++;
}
}
// gethostbyaddr
char addr6[16];
- inet_pton(AF_INET6, "2001:4b10:bbc::2", addr6);
+ inet_pton(AF_INET6, GoogleDNSIpV6Address, addr6);
my_hostent = gethostbyaddr(addr6, sizeof(addr6), AF_INET6);
if (my_hostent == NULL) {
- ALOGD("gethostbyaddr(2001:4b10:bbc::2 (bbc) ) gave null response");
+ ALOGD("gethostbyaddr(%s (GoogleDNS) ) gave null response", GoogleDNSIpV6Address);
return JNI_FALSE;
}
- ALOGD("gethostbyaddr(2001:4b10:bbc::2 (bbc) ) gave %s for name",
- my_hostent->h_name ? my_hostent->h_name : "null");
+
+ ALOGD("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;
return JNI_TRUE;
}
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index b93e115..adb2b3a 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -100,6 +100,7 @@
assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IMS));
assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_CBS));
assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI_P2P));
+ assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IA));
assertFalse(mCm.isNetworkTypeValid(-1));
assertTrue(mCm.isNetworkTypeValid(0));
assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.MAX_NETWORK_TYPE));
diff --git a/tests/cts/net/src/android/net/cts/DnsTest.java b/tests/cts/net/src/android/net/cts/DnsTest.java
new file mode 100644
index 0000000..879a962
--- /dev/null
+++ b/tests/cts/net/src/android/net/cts/DnsTest.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.cts;
+
+import android.os.SystemClock;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+
+public class DnsTest extends AndroidTestCase {
+
+ static {
+ System.loadLibrary("nativedns_jni");
+ }
+
+ private static final boolean DBG = false;
+ private static final String TAG = "DnsTest";
+
+ /**
+ * @return true on success
+ */
+ private static native boolean testNativeDns();
+
+ /**
+ * Verify:
+ * DNS works - forwards and backwards, giving ipv4 and ipv6
+ * Test that DNS work on v4 and v6 networks
+ * Test Native dns calls (4)
+ * Todo:
+ * Cache is flushed when we change networks
+ * have per-network caches
+ * No cache when there's no network
+ * Perf - measure size of first and second tier caches and their effect
+ * Assert requires network permission
+ */
+ public void testDnsWorks() {
+ InetAddress addrs[] = {};
+ try {
+ addrs = InetAddress.getAllByName("www.google.com");
+ } catch (UnknownHostException e) {}
+ assertTrue(addrs.length != 0);
+ boolean foundV4 = false, foundV6 = false;
+ for (InetAddress addr : addrs) {
+ if (addr instanceof Inet4Address) foundV4 = true;
+ else if (addr instanceof Inet6Address) foundV6 = true;
+ if (DBG) Log.e(TAG, "www.google.com gave " + addr.toString());
+ }
+
+ // assertTrue(foundV4);
+ // assertTrue(foundV6);
+
+ // We should have at least one of the addresses to connect!
+ assertTrue(foundV4 || foundV6);
+
+ try {
+ addrs = InetAddress.getAllByName("ipv6.google.com");
+ } catch (UnknownHostException e) {}
+ assertTrue(addrs.length != 0);
+ foundV4 = false;
+ foundV6 = false;
+ for (InetAddress addr : addrs) {
+ if (addr instanceof Inet4Address) foundV4 = true;
+ else if (addr instanceof Inet6Address) foundV6 = true;
+ if (DBG) Log.e(TAG, "ipv6.google.com gave " + addr.toString());
+ }
+
+ assertTrue(foundV4 == false);
+ assertTrue(foundV6 == true);
+
+ assertTrue(testNativeDns());
+ }
+
+ private static final String[] URLS = { "www.google.com", "ipv6.google.com", "www.yahoo.com",
+ "facebook.com", "youtube.com", "blogspot.com", "baidu.com", "wikipedia.org",
+// live.com fails rev lookup.
+ "twitter.com", "qq.com", "msn.com", "yahoo.co.jp", "linkedin.com",
+ "taobao.com", "google.co.in", "sina.com.cn", "amazon.com", "wordpress.com",
+ "google.co.uk", "ebay.com", "yandex.ru", "163.com", "google.co.jp", "google.fr",
+ "microsoft.com", "paypal.com", "google.com.br", "flickr.com",
+ "mail.ru", "craigslist.org", "fc2.com", "google.it",
+// "apple.com", fails rev lookup
+ "google.es",
+ "imdb.com", "google.ru", "soho.com", "bbc.co.uk", "vkontakte.ru", "ask.com",
+ "tumblr.com", "weibo.com", "go.com", "xvideos.com", "livejasmin.com", "cnn.com",
+ "youku.com", "blogspot.com", "soso.com", "google.ca", "aol.com", "tudou.com",
+ "xhamster.com", "megaupload.com", "ifeng.com", "zedo.com", "mediafire.com", "ameblo.jp",
+ "pornhub.com", "google.co.id", "godaddy.com", "adobe.com", "rakuten.co.jp", "about.com",
+ "espn.go.com", "4shared.com", "alibaba.com","ebay.de", "yieldmanager.com",
+ "wordpress.org", "livejournal.com", "google.com.tr", "google.com.mx", "renren.com",
+ "livedoor.com", "google.com.au", "youporn.com", "uol.com.br", "cnet.com", "conduit.com",
+ "google.pl", "myspace.com", "nytimes.com", "ebay.co.uk", "chinaz.com", "hao123.com",
+ "thepiratebay.org", "doubleclick.com", "alipay.com", "netflix.com", "cnzz.com",
+ "huffingtonpost.com", "twitpic.com", "weather.com", "babylon.com", "amazon.de",
+ "dailymotion.com", "orkut.com", "orkut.com.br", "google.com.sa", "odnoklassniki.ru",
+ "amazon.co.jp", "google.nl", "goo.ne.jp", "stumbleupon.com", "tube8.com", "tmall.com",
+ "imgur.com", "globo.com", "secureserver.net", "fileserve.com", "tianya.cn", "badoo.com",
+ "ehow.com", "photobucket.com", "imageshack.us", "xnxx.com", "deviantart.com",
+ "filestube.com", "addthis.com", "douban.com", "vimeo.com", "sogou.com",
+ "stackoverflow.com", "reddit.com", "dailymail.co.uk", "redtube.com", "megavideo.com",
+ "taringa.net", "pengyou.com", "amazon.co.uk", "fbcdn.net", "aweber.com", "spiegel.de",
+ "rapidshare.com", "mixi.jp", "360buy.com", "google.cn", "digg.com", "answers.com",
+ "bit.ly", "indiatimes.com", "skype.com", "yfrog.com", "optmd.com", "google.com.eg",
+ "google.com.pk", "58.com", "hotfile.com", "google.co.th",
+ "bankofamerica.com", "sourceforge.net", "maktoob.com", "warriorforum.com", "rediff.com",
+ "google.co.za", "56.com", "torrentz.eu", "clicksor.com", "avg.com",
+ "download.com", "ku6.com", "statcounter.com", "foxnews.com", "google.com.ar",
+ "nicovideo.jp", "reference.com", "liveinternet.ru", "ucoz.ru", "xinhuanet.com",
+ "xtendmedia.com", "naver.com", "youjizz.com", "domaintools.com", "sparkstudios.com",
+ "rambler.ru", "scribd.com", "kaixin001.com", "mashable.com", "adultfirendfinder.com",
+ "files.wordpress.com", "guardian.co.uk", "bild.de", "yelp.com", "wikimedia.org",
+ "chase.com", "onet.pl", "ameba.jp", "pconline.com.cn", "free.fr", "etsy.com",
+ "typepad.com", "youdao.com", "megaclick.com", "digitalpoint.com", "blogfa.com",
+ "salesforce.com", "adf.ly", "ganji.com", "wikia.com", "archive.org", "terra.com.br",
+ "w3schools.com", "ezinearticles.com", "wjs.com", "google.com.my", "clickbank.com",
+ "squidoo.com", "hulu.com", "repubblica.it", "google.be", "allegro.pl", "comcast.net",
+ "narod.ru", "zol.com.cn", "orange.fr", "soufun.com", "hatena.ne.jp", "google.gr",
+ "in.com", "techcrunch.com", "orkut.co.in", "xunlei.com",
+ "reuters.com", "google.com.vn", "hostgator.com", "kaskus.us", "espncricinfo.com",
+ "hootsuite.com", "qiyi.com", "gmx.net", "xing.com", "php.net", "soku.com", "web.de",
+ "libero.it", "groupon.com", "51.la", "slideshare.net", "booking.com", "seesaa.net",
+ "126.com", "telegraph.co.uk", "wretch.cc", "twimg.com", "rutracker.org", "angege.com",
+ "nba.com", "dell.com", "leboncoin.fr", "people.com", "google.com.tw", "walmart.com",
+ "daum.net", "2ch.net", "constantcontact.com", "nifty.com", "mywebsearch.com",
+ "tripadvisor.com", "google.se", "paipai.com", "google.com.ua", "ning.com", "hp.com",
+ "google.at", "joomla.org", "icio.us", "hudong.com", "csdn.net", "getfirebug.com",
+ "ups.com", "cj.com", "google.ch", "camzap.com", "wordreference.com", "tagged.com",
+ "wp.pl", "mozilla.com", "google.ru", "usps.com", "china.com", "themeforest.net",
+ "search-results.com", "tribalfusion.com", "thefreedictionary.com", "isohunt.com",
+ "linkwithin.com", "cam4.com", "plentyoffish.com", "wellsfargo.com", "metacafe.com",
+ "depositfiles.com", "freelancer.com", "opendns.com", "homeway.com", "engadget.com",
+ "10086.cn", "360.cn", "marca.com", "dropbox.com", "ign.com", "match.com", "google.pt",
+ "facemoods.com", "hardsextube.com", "google.com.ph", "lockerz.com", "istockphoto.com",
+ "partypoker.com", "netlog.com", "outbrain.com", "elpais.com", "fiverr.com",
+ "biglobe.ne.jp", "corriere.it", "love21cn.com", "yesky.com", "spankwire.com",
+ "ig.com.br", "imagevenue.com", "hubpages.com", "google.co.ve"};
+
+// TODO - this works, but is slow and cts doesn't do anything with the result.
+// Maybe require a min performance, a min cache size (detectable) and/or move
+// to perf testing
+ private static final int LOOKUP_COUNT_GOAL = URLS.length;
+ public void skiptestDnsPerf() {
+ ArrayList<String> results = new ArrayList<String>();
+ int failures = 0;
+ try {
+ for (int numberOfUrls = URLS.length; numberOfUrls > 0; numberOfUrls--) {
+ failures = 0;
+ int iterationLimit = LOOKUP_COUNT_GOAL / numberOfUrls;
+ long startTime = SystemClock.elapsedRealtimeNanos();
+ for (int iteration = 0; iteration < iterationLimit; iteration++) {
+ for (int urlIndex = 0; urlIndex < numberOfUrls; urlIndex++) {
+ try {
+ InetAddress addr = InetAddress.getByName(URLS[urlIndex]);
+ } catch (UnknownHostException e) {
+ Log.e(TAG, "failed first lookup of " + URLS[urlIndex]);
+ failures++;
+ try {
+ InetAddress addr = InetAddress.getByName(URLS[urlIndex]);
+ } catch (UnknownHostException ee) {
+ failures++;
+ Log.e(TAG, "failed SECOND lookup of " + URLS[urlIndex]);
+ }
+ }
+ }
+ }
+ long endTime = SystemClock.elapsedRealtimeNanos();
+ float nsPer = ((float)(endTime-startTime) / iterationLimit) / numberOfUrls/ 1000;
+ String thisResult = new String("getByName for " + numberOfUrls + " took " +
+ (endTime - startTime)/1000 + "(" + nsPer + ") with " +
+ failures + " failures\n");
+ Log.d(TAG, thisResult);
+ results.add(thisResult);
+ }
+ // build up a list of addresses
+ ArrayList<byte[]> addressList = new ArrayList<byte[]>();
+ for (String url : URLS) {
+ try {
+ InetAddress addr = InetAddress.getByName(url);
+ addressList.add(addr.getAddress());
+ } catch (UnknownHostException e) {
+ Log.e(TAG, "Exception making reverseDNS list: " + e.toString());
+ }
+ }
+ for (int numberOfAddrs = addressList.size(); numberOfAddrs > 0; numberOfAddrs--) {
+ int iterationLimit = LOOKUP_COUNT_GOAL / numberOfAddrs;
+ failures = 0;
+ long startTime = SystemClock.elapsedRealtimeNanos();
+ for (int iteration = 0; iteration < iterationLimit; iteration++) {
+ for (int addrIndex = 0; addrIndex < numberOfAddrs; addrIndex++) {
+ try {
+ InetAddress addr = InetAddress.getByAddress(addressList.get(addrIndex));
+ String hostname = addr.getHostName();
+ } catch (UnknownHostException e) {
+ failures++;
+ Log.e(TAG, "Failure doing reverse DNS lookup: " + e.toString());
+ try {
+ InetAddress addr =
+ InetAddress.getByAddress(addressList.get(addrIndex));
+ String hostname = addr.getHostName();
+
+ } catch (UnknownHostException ee) {
+ failures++;
+ Log.e(TAG, "Failure doing SECOND reverse DNS lookup: " +
+ ee.toString());
+ }
+ }
+ }
+ }
+ long endTime = SystemClock.elapsedRealtimeNanos();
+ float nsPer = ((endTime-startTime) / iterationLimit) / numberOfAddrs / 1000;
+ String thisResult = new String("getHostName for " + numberOfAddrs + " took " +
+ (endTime - startTime)/1000 + "(" + nsPer + ") with " +
+ failures + " failures\n");
+ Log.d(TAG, thisResult);
+ results.add(thisResult);
+ }
+ for (String result : results) Log.d(TAG, result);
+
+ InetAddress exit = InetAddress.getByName("exitrightnow.com");
+ Log.e(TAG, " exit address= "+exit.toString());
+
+ } catch (Exception e) {
+ Log.e(TAG, "bad URL in testDnsPerf: " + e.toString());
+ }
+ }
+}
diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java
index 180d259..9483bdc 100644
--- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java
+++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java
@@ -19,7 +19,11 @@
import android.net.TrafficStats;
import android.os.Process;
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;
@@ -29,6 +33,8 @@
import java.util.concurrent.TimeUnit;
public class TrafficStatsTest extends AndroidTestCase {
+ private static final String LOG_TAG = "TrafficStatsTest";
+
public void testValidMobileStats() {
// We can't assume a mobile network is even present in this test, so
// we simply assert that a valid value is returned.
@@ -75,19 +81,39 @@
return packetCount * (20 + 32 + bytes);
}
+ private void accessOwnTrafficStats() throws IOException {
+ final int ownAppUid = getContext().getApplicationInfo().uid;
+ Log.d(LOG_TAG, "accesOwnTrafficStatsWithTags(): about to read qtaguid stats for own uid " + ownAppUid);
+
+ boolean foundOwnDetailedStats = false;
+ try {
+ BufferedReader qtaguidReader = new BufferedReader(new FileReader("/proc/net/xt_qtaguid/stats"));
+ String line;
+ while ((line = qtaguidReader.readLine()) != null) {
+ String tokens[] = line.split(" ");
+ if (tokens.length > 3 && tokens[3].equals(String.valueOf(ownAppUid))) {
+ Log.d(LOG_TAG, "accessOwnTrafficStatsWithTags(): got own stats: " + line);
+ }
+ }
+ qtaguidReader.close();
+ } catch (FileNotFoundException e) {
+ fail("Was not able to access qtaguid/stats: " + e);
+ }
+ }
+
public void testTrafficStatsForLocalhost() throws IOException {
- long mobileTxPacketsBefore = TrafficStats.getMobileTxPackets();
- long mobileRxPacketsBefore = TrafficStats.getMobileRxPackets();
- long mobileTxBytesBefore = TrafficStats.getMobileTxBytes();
- long mobileRxBytesBefore = TrafficStats.getMobileRxBytes();
- long totalTxPacketsBefore = TrafficStats.getTotalTxPackets();
- long totalRxPacketsBefore = TrafficStats.getTotalRxPackets();
- long totalTxBytesBefore = TrafficStats.getTotalTxBytes();
- long totalRxBytesBefore = TrafficStats.getTotalRxBytes();
- long uidTxBytesBefore = TrafficStats.getUidTxBytes(Process.myUid());
- long uidRxBytesBefore = TrafficStats.getUidRxBytes(Process.myUid());
- long uidTxPacketsBefore = TrafficStats.getUidTxPackets(Process.myUid());
- long uidRxPacketsBefore = TrafficStats.getUidRxPackets(Process.myUid());
+ final long mobileTxPacketsBefore = TrafficStats.getMobileTxPackets();
+ final long mobileRxPacketsBefore = TrafficStats.getMobileRxPackets();
+ final long mobileTxBytesBefore = TrafficStats.getMobileTxBytes();
+ final long mobileRxBytesBefore = TrafficStats.getMobileRxBytes();
+ final long totalTxPacketsBefore = TrafficStats.getTotalTxPackets();
+ final long totalRxPacketsBefore = TrafficStats.getTotalRxPackets();
+ final long totalTxBytesBefore = TrafficStats.getTotalTxBytes();
+ final long totalRxBytesBefore = TrafficStats.getTotalRxBytes();
+ final long uidTxBytesBefore = TrafficStats.getUidTxBytes(Process.myUid());
+ final long uidRxBytesBefore = TrafficStats.getUidRxBytes(Process.myUid());
+ final long uidTxPacketsBefore = TrafficStats.getUidTxPackets(Process.myUid());
+ final long uidRxPacketsBefore = TrafficStats.getUidRxPackets(Process.myUid());
// Transfer 1MB of data across an explicitly localhost socket.
final int byteCount = 1024;
@@ -104,22 +130,36 @@
socket.setTcpNoDelay(true);
OutputStream out = socket.getOutputStream();
byte[] buf = new byte[byteCount];
+ TrafficStats.setThreadStatsTag(0x42);
+ TrafficStats.tagSocket(socket);
+ accessOwnTrafficStats();
for (int i = 0; i < packetCount; i++) {
out.write(buf);
out.flush();
+ try {
+ // Bug: 10668088, Even with Nagle disabled, and flushing the 1024 bytes
+ // the kernel still regroups data into a larger packet.
+ Thread.sleep(5);
+ } catch (InterruptedException e) {
+ }
}
out.close();
socket.close();
+ accessOwnTrafficStats();
} catch (IOException e) {
+ Log.i(LOG_TAG, "Badness during writes to socket: " + e);
}
}
}.start();
+ int read = 0;
try {
Socket socket = server.accept();
+ socket.setTcpNoDelay(true);
+ TrafficStats.setThreadStatsTag(0x43);
+ TrafficStats.tagSocket(socket);
InputStream in = socket.getInputStream();
byte[] buf = new byte[byteCount];
- int read = 0;
while (read < byteCount * packetCount) {
int n = in.read(buf);
assertTrue("Unexpected EOF", n > 0);
@@ -128,6 +168,7 @@
} finally {
server.close();
}
+ assertTrue("Not all data read back", read >= byteCount * packetCount);
// It's too fast to call getUidTxBytes function.
try {
@@ -163,18 +204,30 @@
* + 7 approx.: syn, syn-ack, ack, fin-ack, ack, fin-ack, ack;
* but sometimes the last find-acks just vanish, so we set a lower limit of +5.
*/
- assertTrue("uidtxp: " + uidTxPacketsBefore + " -> " + uidTxPacketsAfter + " delta=" + uidTxDeltaPackets,
- uidTxDeltaPackets >= packetCount + 5 &&
- uidTxDeltaPackets <= packetCount + packetCount + 7);
- assertTrue("uidrxp: " + uidRxPacketsBefore + " -> " + uidRxPacketsAfter + " delta=" + uidRxDeltaPackets,
- uidRxDeltaPackets >= packetCount + 5 &&
- uidRxDeltaPackets <= packetCount + packetCount + 7);
- assertTrue("uidtxb: " + uidTxBytesBefore + " -> " + uidTxBytesAfter + " delta=" + uidTxDeltaBytes,
- uidTxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(5, 0) &&
- uidTxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + 7, 0));
- assertTrue("uidrxb: " + uidRxBytesBefore + " -> " + uidRxBytesAfter + " delta=" + uidRxDeltaBytes,
- uidRxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(5, 0) &&
- uidRxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + 7, 0));
+ final int maxExpectedExtraPackets = 7;
+ final int minExpectedExtraPackets = 5;
+
+
+ assertTrue("uidtxp: " + uidTxPacketsBefore + " -> " + uidTxPacketsAfter + " delta=" + uidTxDeltaPackets +
+ " Wanted: " + uidTxDeltaPackets + ">=" + packetCount + "+" + minExpectedExtraPackets + " && " +
+ uidTxDeltaPackets + "<=" + packetCount + "+" + packetCount + "+" + maxExpectedExtraPackets,
+ uidTxDeltaPackets >= packetCount + minExpectedExtraPackets &&
+ uidTxDeltaPackets <= packetCount + packetCount + maxExpectedExtraPackets);
+ assertTrue("uidrxp: " + uidRxPacketsBefore + " -> " + uidRxPacketsAfter + " delta=" + uidRxDeltaPackets +
+ " Wanted: " + uidRxDeltaPackets + ">=" + packetCount + "+" + minExpectedExtraPackets + " && " +
+ uidRxDeltaPackets + "<=" + packetCount + "+" + packetCount + "+" + maxExpectedExtraPackets,
+ uidRxDeltaPackets >= packetCount + minExpectedExtraPackets &&
+ uidRxDeltaPackets <= packetCount + packetCount + maxExpectedExtraPackets);
+ assertTrue("uidtxb: " + uidTxBytesBefore + " -> " + uidTxBytesAfter + " delta=" + uidTxDeltaBytes +
+ " Wanted: " + uidTxDeltaBytes + ">=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(minExpectedExtraPackets, 0) + " && " +
+ uidTxDeltaBytes + "<=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0),
+ uidTxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(minExpectedExtraPackets, 0) &&
+ uidTxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0));
+ assertTrue("uidrxb: " + uidRxBytesBefore + " -> " + uidRxBytesAfter + " delta=" + uidRxDeltaBytes +
+ " Wanted: " + uidRxDeltaBytes + ">=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(minExpectedExtraPackets, 0) + " && " +
+ uidRxDeltaBytes + "<=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0),
+ uidRxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(minExpectedExtraPackets, 0) &&
+ uidRxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0));
// Localhost traffic *does* count against total stats.
// Fudge by 132 packets of 1500 bytes not related to the test.
diff --git a/tests/cts/net/src/android/net/http/cts/SslErrorTest.java b/tests/cts/net/src/android/net/http/cts/SslErrorTest.java
old mode 100755
new mode 100644
diff --git a/tests/cts/net/src/android/net/ipv6/cts/PingTest.java b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java
new file mode 100644
index 0000000..41eb03d
--- /dev/null
+++ b/tests/cts/net/src/android/net/ipv6/cts/PingTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ipv6.cts;
+
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+import libcore.io.StructTimeval;
+import static libcore.io.OsConstants.*;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Inet6Address;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Random;
+
+public class PingTest extends AndroidTestCase {
+ /** Maximum size of the packets we're using to test. */
+ private static final int MAX_SIZE = 4096;
+
+ /** Number of packets to test. */
+ private static final int NUM_PACKETS = 10;
+
+ /** 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
+ };
+
+ /**
+ * Returns a byte array containing an ICMPv6 echo request with the specified payload length.
+ */
+ private byte[] pingPacket(int payloadLength) {
+ byte[] packet = new byte[payloadLength + 8];
+ new Random().nextBytes(packet);
+ System.arraycopy(PING_HEADER, 0, packet, 0, PING_HEADER.length);
+ return packet;
+ }
+
+ /**
+ * Checks that the first length bytes of two byte arrays are equal.
+ */
+ private void assertArrayBytesEqual(byte[] expected, byte[] actual, int length) {
+ for (int i = 0; i < length; i++) {
+ assertEquals("Arrays differ at index " + i + ":", expected[i], actual[i]);
+ }
+ }
+
+ /**
+ * Creates an IPv6 ping socket and sets a receive timeout of 100ms.
+ */
+ private FileDescriptor createPingSocket() throws ErrnoException {
+ FileDescriptor s = Libcore.os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
+ Libcore.os.setsockoptTimeval(s, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(100));
+ return s;
+ }
+
+ /**
+ * Sends a ping packet to a random port on the specified address on the specified socket.
+ */
+ private void sendPing(FileDescriptor s,
+ InetAddress address, byte[] packet) throws ErrnoException, IOException {
+ // Pick a random port. Choose a range that gives a reasonable chance of picking a low port.
+ int port = (int) (Math.random() * 2048);
+
+ // Send the packet.
+ int ret = Libcore.os.sendto(s, ByteBuffer.wrap(packet), 0, address, port);
+ assertEquals(packet.length, ret);
+ }
+
+ /**
+ * Checks that a socket has received a response appropriate to the specified packet.
+ */
+ private void checkResponse(FileDescriptor s,
+ InetAddress dest, byte[] sent) throws ErrnoException, IOException {
+ // Receive the response.
+ InetSocketAddress from = new InetSocketAddress();
+ ByteBuffer responseBuffer = ByteBuffer.allocate(MAX_SIZE);
+ int bytesRead = Libcore.os.recvfrom(s, responseBuffer, 0, from);
+
+ // Check the source address and scope ID.
+ assertTrue(from.getAddress() instanceof Inet6Address);
+ Inet6Address fromAddress = (Inet6Address) from.getAddress();
+ assertEquals(0, fromAddress.getScopeId());
+ assertNull(fromAddress.getScopedInterface());
+ assertEquals(dest.getHostAddress(), fromAddress.getHostAddress());
+
+ // Check the packet length.
+ assertEquals(sent.length, bytesRead);
+
+ // Check the response is an echo reply.
+ byte[] response = new byte[bytesRead];
+ responseBuffer.get(response, 0, bytesRead);
+ assertEquals((byte) 0x81, response[0]);
+
+ // Find out what ICMP ID was used in the packet that was sent.
+ int id = ((InetSocketAddress) Libcore.os.getsockname(s)).getPort();
+ sent[4] = (byte) (id / 256);
+ sent[5] = (byte) (id % 256);
+
+ // Ensure the response is the same as the packet, except for the type (which is 0x81)
+ // and the ID and checksum, which are set by the kernel.
+ response[0] = (byte) 0x80; // Type.
+ response[2] = response[3] = (byte) 0x00; // Checksum.
+ assertArrayBytesEqual(response, sent, bytesRead);
+ }
+
+ /**
+ * Sends NUM_PACKETS random ping packets to ::1 and checks the replies.
+ */
+ public void testLoopbackPing() throws ErrnoException, IOException {
+ // Generate a random ping packet and send it to localhost.
+ InetAddress ipv6Loopback = InetAddress.getByName(null);
+ assertEquals("localhost/::1", ipv6Loopback.toString());
+
+ for (int i = 0; i < NUM_PACKETS; i++) {
+ byte[] packet = pingPacket((int) (Math.random() * MAX_SIZE));
+ FileDescriptor s = createPingSocket();
+ sendPing(s, ipv6Loopback, packet);
+ checkResponse(s, ipv6Loopback, packet);
+ // Check closing the socket doesn't raise an exception.
+ Libcore.os.close(s);
+ }
+ }
+}
diff --git a/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java
new file mode 100644
index 0000000..d1e4c44
--- /dev/null
+++ b/tests/cts/net/src/android/net/wifi/cts/NsdManagerTest.java
@@ -0,0 +1,459 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.cts;
+
+import android.content.Context;
+import android.net.nsd.NsdManager;
+import android.net.nsd.NsdServiceInfo;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.Random;
+import java.util.List;
+import java.util.ArrayList;
+
+public class NsdManagerTest extends AndroidTestCase {
+
+ private static final String TAG = "NsdManagerTest";
+ private static final String SERVICE_TYPE = "_nmt._tcp";
+ private static final int TIMEOUT = 2000;
+
+ private static final boolean DBG = false;
+
+ NsdManager mNsdManager;
+
+ NsdManager.RegistrationListener mRegistrationListener;
+ NsdManager.DiscoveryListener mDiscoveryListener;
+ NsdManager.ResolveListener mResolveListener;
+
+ public NsdManagerTest() {
+ initRegistrationListener();
+ initDiscoveryListener();
+ initResolveListener();
+ }
+
+ private void initRegistrationListener() {
+ mRegistrationListener = new NsdManager.RegistrationListener() {
+ @Override
+ public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
+ setEvent("onRegistrationFailed", errorCode);
+ }
+
+ @Override
+ public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
+ setEvent("onUnregistrationFailed", errorCode);
+ }
+
+ @Override
+ public void onServiceRegistered(NsdServiceInfo serviceInfo) {
+ setEvent("onServiceRegistered", serviceInfo);
+ }
+
+ @Override
+ public void onServiceUnregistered(NsdServiceInfo serviceInfo) {
+ setEvent("onServiceUnregistered", serviceInfo);
+ }
+ };
+ }
+
+ private void initDiscoveryListener() {
+ mDiscoveryListener = new NsdManager.DiscoveryListener() {
+ @Override
+ public void onStartDiscoveryFailed(String serviceType, int errorCode) {
+ setEvent("onStartDiscoveryFailed", errorCode);
+ }
+
+ @Override
+ public void onStopDiscoveryFailed(String serviceType, int errorCode) {
+ setEvent("onStopDiscoveryFailed", errorCode);
+ }
+
+ @Override
+ public void onDiscoveryStarted(String serviceType) {
+ NsdServiceInfo info = new NsdServiceInfo();
+ info.setServiceType(serviceType);
+ setEvent("onDiscoveryStarted", info);
+ }
+
+ @Override
+ public void onDiscoveryStopped(String serviceType) {
+ NsdServiceInfo info = new NsdServiceInfo();
+ info.setServiceType(serviceType);
+ setEvent("onDiscoveryStopped", info);
+ }
+
+ @Override
+ public void onServiceFound(NsdServiceInfo serviceInfo) {
+ setEvent("onServiceFound", serviceInfo);
+ }
+
+ @Override
+ public void onServiceLost(NsdServiceInfo serviceInfo) {
+ setEvent("onServiceLost", serviceInfo);
+ }
+ };
+ }
+
+ private void initResolveListener() {
+ mResolveListener = new NsdManager.ResolveListener() {
+ @Override
+ public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
+ setEvent("onResolveFailed", errorCode);
+ }
+
+ @Override
+ public void onServiceResolved(NsdServiceInfo serviceInfo) {
+ setEvent("onServiceResolved", serviceInfo);
+ }
+ };
+ }
+
+
+
+ private final class EventData {
+ EventData(String callbackName, NsdServiceInfo info) {
+ mCallbackName = callbackName;
+ mSucceeded = true;
+ mErrorCode = 0;
+ mInfo = info;
+ }
+ EventData(String callbackName, int errorCode) {
+ mCallbackName = callbackName;
+ mSucceeded = false;
+ mErrorCode = errorCode;
+ mInfo = null;
+ }
+ private final String mCallbackName;
+ private final boolean mSucceeded;
+ private final int mErrorCode;
+ private final NsdServiceInfo mInfo;
+ }
+
+ private final List<EventData> mEventCache = new ArrayList<EventData>();
+
+ private void setEvent(String callbackName, int errorCode) {
+ if (DBG) Log.d(TAG, callbackName + " failed with " + String.valueOf(errorCode));
+ EventData eventData = new EventData(callbackName, errorCode);
+ synchronized (mEventCache) {
+ mEventCache.add(eventData);
+ mEventCache.notify();
+ }
+ }
+
+ private void setEvent(String callbackName, NsdServiceInfo info) {
+ if (DBG) Log.d(TAG, "Received event " + callbackName + " for " + info.getServiceName());
+ EventData eventData = new EventData(callbackName, info);
+ synchronized (mEventCache) {
+ mEventCache.add(eventData);
+ mEventCache.notify();
+ }
+ }
+
+ void clearEventCache() {
+ synchronized(mEventCache) {
+ mEventCache.clear();
+ }
+ }
+
+ int eventCacheSize() {
+ synchronized(mEventCache) {
+ return mEventCache.size();
+ }
+ }
+
+ private int mWaitId = 0;
+ private EventData waitForCallback(String callbackName) {
+
+ synchronized(mEventCache) {
+
+ mWaitId ++;
+ if (DBG) Log.d(TAG, "Waiting for " + callbackName + ", id=" + String.valueOf(mWaitId));
+
+ try {
+ long startTime = android.os.SystemClock.uptimeMillis();
+ long elapsedTime = 0;
+ int index = 0;
+ while (elapsedTime < TIMEOUT ) {
+ // first check if we've received that event
+ for (; index < mEventCache.size(); index++) {
+ EventData e = mEventCache.get(index);
+ if (e.mCallbackName.equals(callbackName)) {
+ if (DBG) Log.d(TAG, "exiting wait id=" + String.valueOf(mWaitId));
+ return e;
+ }
+ }
+
+ // Not yet received, just wait
+ mEventCache.wait(TIMEOUT - elapsedTime);
+ elapsedTime = android.os.SystemClock.uptimeMillis() - startTime;
+ }
+ // we exited the loop because of TIMEOUT; fail the call
+ if (DBG) Log.d(TAG, "timed out waiting id=" + String.valueOf(mWaitId));
+ return null;
+ } catch (InterruptedException e) {
+ return null; // wait timed out!
+ }
+ }
+ }
+
+ private EventData waitForNewEvents() throws InterruptedException {
+ if (DBG) Log.d(TAG, "Waiting for a bit, id=" + String.valueOf(mWaitId));
+
+ long startTime = android.os.SystemClock.uptimeMillis();
+ long elapsedTime = 0;
+ synchronized (mEventCache) {
+ int index = mEventCache.size();
+ while (elapsedTime < TIMEOUT ) {
+ // first check if we've received that event
+ for (; index < mEventCache.size(); index++) {
+ EventData e = mEventCache.get(index);
+ return e;
+ }
+
+ // Not yet received, just wait
+ mEventCache.wait(TIMEOUT - elapsedTime);
+ elapsedTime = android.os.SystemClock.uptimeMillis() - startTime;
+ }
+ }
+
+ return null;
+ }
+
+ private String mServiceName;
+
+ @Override
+ public void setUp() {
+ if (DBG) Log.d(TAG, "Setup test ...");
+ mNsdManager = (NsdManager) getContext().getSystemService(Context.NSD_SERVICE);
+
+ Random rand = new Random();
+ mServiceName = new String("NsdTest");
+ for (int i = 0; i < 4; i++) {
+ mServiceName = mServiceName + String.valueOf(rand.nextInt(10));
+ }
+ }
+
+ @Override
+ public void tearDown() {
+ if (DBG) Log.d(TAG, "Tear down test ...");
+ }
+
+ public void runTest() throws Exception {
+ NsdServiceInfo si = new NsdServiceInfo();
+ si.setServiceType(SERVICE_TYPE);
+ si.setServiceName(mServiceName);
+
+ EventData lastEvent = null;
+
+ if (DBG) Log.d(TAG, "Starting test ...");
+
+ ServerSocket socket;
+ int localPort;
+
+ try {
+ socket = new ServerSocket(0);
+ localPort = socket.getLocalPort();
+ si.setPort(localPort);
+ } catch (IOException e) {
+ if (DBG) Log.d(TAG, "Could not open a local socket");
+ assertTrue(false);
+ return;
+ }
+
+ if (DBG) Log.d(TAG, "Port = " + String.valueOf(localPort));
+
+ clearEventCache();
+
+ mNsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
+ lastEvent = waitForCallback("onServiceRegistered"); // id = 1
+ assertTrue(lastEvent != null);
+ assertTrue(lastEvent.mSucceeded);
+ assertTrue(eventCacheSize() == 1);
+
+ // We may not always get the name that we tried to register;
+ // This events tells us the name that was registered.
+ String registeredName = lastEvent.mInfo.getServiceName();
+ si.setServiceName(registeredName);
+
+ clearEventCache();
+
+ mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD,
+ mDiscoveryListener);
+
+ // Expect discovery started
+ lastEvent = waitForCallback("onDiscoveryStarted"); // id = 2
+
+ assertTrue(lastEvent != null);
+ assertTrue(lastEvent.mSucceeded);
+
+ // Remove this event, so accounting becomes easier later
+ synchronized (mEventCache) {
+ mEventCache.remove(lastEvent);
+ }
+
+ // Expect a service record to be discovered (and filter the ones
+ // that are unrelated to this test)
+ boolean found = false;
+ for (int i = 0; i < 32; i++) {
+
+ lastEvent = waitForCallback("onServiceFound"); // id = 3
+ if (lastEvent == null) {
+ // no more onServiceFound events are being reported!
+ break;
+ }
+
+ assertTrue(lastEvent.mSucceeded);
+
+ if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": ServiceName = " +
+ lastEvent.mInfo.getServiceName());
+
+ if (lastEvent.mInfo.getServiceName().equals(registeredName)) {
+ // Save it, as it will get overwritten with new serviceFound events
+ si = lastEvent.mInfo;
+ found = true;
+ }
+
+ // Remove this event from the event cache, so it won't be found by subsequent
+ // calls to waitForCallback
+ synchronized (mEventCache) {
+ mEventCache.remove(lastEvent);
+ }
+ }
+
+ assertTrue(found);
+
+ // We've removed all serviceFound events, and we've removed the discoveryStarted
+ // event as well, so now the event cache should be empty!
+ assertTrue(eventCacheSize() == 0);
+
+ // Resolve the service
+ clearEventCache();
+ mNsdManager.resolveService(si, mResolveListener);
+ lastEvent = waitForCallback("onServiceResolved"); // id = 4
+
+ assertTrue(lastEvent != null);
+ assertTrue(lastEvent.mSucceeded);
+
+ if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": Port = " +
+ String.valueOf(lastEvent.mInfo.getPort()));
+
+ assertTrue(lastEvent.mInfo.getPort() == localPort);
+ assertTrue(eventCacheSize() == 1);
+
+ assertTrue(checkForAdditionalEvents());
+ clearEventCache();
+
+ // Unregister the service
+ mNsdManager.unregisterService(mRegistrationListener);
+ lastEvent = waitForCallback("onServiceUnregistered"); // id = 5
+
+ assertTrue(lastEvent != null);
+ assertTrue(lastEvent.mSucceeded);
+
+ // Expect a callback for service lost
+ lastEvent = waitForCallback("onServiceLost"); // id = 6
+
+ assertTrue(lastEvent != null);
+ assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName));
+
+ assertTrue(eventCacheSize() == 2);
+
+ // Register service again to see if we discover it
+ checkForAdditionalEvents();
+ clearEventCache();
+
+ si = new NsdServiceInfo();
+ si.setServiceType(SERVICE_TYPE);
+ si.setServiceName(mServiceName);
+ si.setPort(localPort);
+
+ // Create a new registration listener and register same service again
+ initRegistrationListener();
+
+ mNsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
+
+ lastEvent = waitForCallback("onServiceRegistered"); // id = 7
+
+ assertTrue(lastEvent != null);
+ assertTrue(lastEvent.mSucceeded);
+
+ registeredName = lastEvent.mInfo.getServiceName();
+
+ // Expect a record to be discovered
+ lastEvent = waitForCallback("onServiceFound"); // id = 8
+
+ assertTrue(lastEvent != null);
+ assertTrue(lastEvent.mSucceeded);
+
+ if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": ServiceName = " +
+ lastEvent.mInfo.getServiceName());
+
+ assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName));
+ assertTrue(checkCacheSize(2));
+
+ checkForAdditionalEvents();
+ clearEventCache();
+
+ mNsdManager.stopServiceDiscovery(mDiscoveryListener);
+ lastEvent = waitForCallback("onDiscoveryStopped"); // id = 9
+ assertTrue(lastEvent != null);
+ assertTrue(lastEvent.mSucceeded);
+ assertTrue(checkCacheSize(1));
+
+ checkForAdditionalEvents();
+ clearEventCache();
+
+ mNsdManager.unregisterService(mRegistrationListener);
+
+ lastEvent = waitForCallback("onServiceUnregistered"); // id = 10
+ assertTrue(lastEvent != null);
+ assertTrue(lastEvent.mSucceeded);
+ assertTrue(checkCacheSize(1));
+ }
+
+ boolean checkCacheSize(int size) {
+ synchronized (mEventCache) {
+ int cacheSize = mEventCache.size();
+ if (cacheSize != size) {
+ Log.d(TAG, "id = " + mWaitId + ": event cache size = " + cacheSize);
+ for (int i = 0; i < cacheSize; i++) {
+ EventData e = mEventCache.get(i);
+ String sname = (e.mInfo != null) ? "(" + e.mInfo.getServiceName() + ")" : "";
+ Log.d(TAG, "eventName is " + e.mCallbackName + sname);
+ }
+ }
+ return (cacheSize == size);
+ }
+ }
+
+ boolean checkForAdditionalEvents() {
+ try {
+ EventData e = waitForNewEvents();
+ if (e != null) {
+ String sname = (e.mInfo != null) ? "(" + e.mInfo.getServiceName() + ")" : "";
+ Log.d(TAG, "ignoring unexpected event " + e.mCallbackName + sname);
+ }
+ return (e == null);
+ }
+ catch (InterruptedException ex) {
+ return false;
+ }
+ }
+}
+