1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net.cts; 18 19 import android.net.TrafficStats; 20 import android.os.Process; 21 import android.test.AndroidTestCase; 22 import android.util.Log; 23 24 import java.io.BufferedReader; 25 import java.io.FileNotFoundException; 26 import java.io.FileReader; 27 import java.io.IOException; 28 import java.io.InputStream; 29 import java.io.OutputStream; 30 import java.net.ServerSocket; 31 import java.net.Socket; 32 import java.util.concurrent.CountDownLatch; 33 import java.util.concurrent.TimeUnit; 34 35 public class TrafficStatsTest extends AndroidTestCase { 36 private static final String LOG_TAG = "TrafficStatsTest"; 37 38 public void testValidMobileStats() { 39 // We can't assume a mobile network is even present in this test, so 40 // we simply assert that a valid value is returned. 41 42 assertTrue(TrafficStats.getMobileTxPackets() >= 0); 43 assertTrue(TrafficStats.getMobileRxPackets() >= 0); 44 assertTrue(TrafficStats.getMobileTxBytes() >= 0); 45 assertTrue(TrafficStats.getMobileRxBytes() >= 0); 46 } 47 48 public void testValidTotalStats() { 49 assertTrue(TrafficStats.getTotalTxPackets() >= 0); 50 assertTrue(TrafficStats.getTotalRxPackets() >= 0); 51 assertTrue(TrafficStats.getTotalTxBytes() >= 0); 52 assertTrue(TrafficStats.getTotalRxBytes() >= 0); 53 } 54 55 public void testThreadStatsTag() throws Exception { 56 TrafficStats.setThreadStatsTag(0xf00d); 57 assertTrue("Tag didn't stick", TrafficStats.getThreadStatsTag() == 0xf00d); 58 59 final CountDownLatch latch = new CountDownLatch(1); 60 61 new Thread("TrafficStatsTest.testThreadStatsTag") { 62 @Override 63 public void run() { 64 assertTrue("Tag leaked", TrafficStats.getThreadStatsTag() != 0xf00d); 65 TrafficStats.setThreadStatsTag(0xcafe); 66 assertTrue("Tag didn't stick", TrafficStats.getThreadStatsTag() == 0xcafe); 67 latch.countDown(); 68 } 69 }.start(); 70 71 latch.await(5, TimeUnit.SECONDS); 72 assertTrue("Tag lost", TrafficStats.getThreadStatsTag() == 0xf00d); 73 74 TrafficStats.clearThreadStatsTag(); 75 assertTrue("Tag not cleared", TrafficStats.getThreadStatsTag() != 0xf00d); 76 } 77 78 long tcpPacketToIpBytes(long packetCount, long bytes) { 79 // ip header + tcp header + data. 80 // Tcp header is mostly 32. Syn has different tcp options -> 40. Don't care. 81 return packetCount * (20 + 32 + bytes); 82 } 83 84 public void testTrafficStatsForLocalhost() throws IOException { 85 final long mobileTxPacketsBefore = TrafficStats.getMobileTxPackets(); 86 final long mobileRxPacketsBefore = TrafficStats.getMobileRxPackets(); 87 final long mobileTxBytesBefore = TrafficStats.getMobileTxBytes(); 88 final long mobileRxBytesBefore = TrafficStats.getMobileRxBytes(); 89 final long totalTxPacketsBefore = TrafficStats.getTotalTxPackets(); 90 final long totalRxPacketsBefore = TrafficStats.getTotalRxPackets(); 91 final long totalTxBytesBefore = TrafficStats.getTotalTxBytes(); 92 final long totalRxBytesBefore = TrafficStats.getTotalRxBytes(); 93 final long uidTxBytesBefore = TrafficStats.getUidTxBytes(Process.myUid()); 94 final long uidRxBytesBefore = TrafficStats.getUidRxBytes(Process.myUid()); 95 final long uidTxPacketsBefore = TrafficStats.getUidTxPackets(Process.myUid()); 96 final long uidRxPacketsBefore = TrafficStats.getUidRxPackets(Process.myUid()); 97 98 // Transfer 1MB of data across an explicitly localhost socket. 99 final int byteCount = 1024; 100 final int packetCount = 1024; 101 102 final ServerSocket server = new ServerSocket(0); 103 new Thread("TrafficStatsTest.testTrafficStatsForLocalhost") { 104 @Override 105 public void run() { 106 try { 107 Socket socket = new Socket("localhost", server.getLocalPort()); 108 // Make sure that each write()+flush() turns into a packet: 109 // disable Nagle. 110 socket.setTcpNoDelay(true); 111 OutputStream out = socket.getOutputStream(); 112 byte[] buf = new byte[byteCount]; 113 TrafficStats.setThreadStatsTag(0x42); 114 TrafficStats.tagSocket(socket); 115 for (int i = 0; i < packetCount; i++) { 116 out.write(buf); 117 out.flush(); 118 try { 119 // Bug: 10668088, Even with Nagle disabled, and flushing the 1024 bytes 120 // the kernel still regroups data into a larger packet. 121 Thread.sleep(5); 122 } catch (InterruptedException e) { 123 } 124 } 125 out.close(); 126 socket.close(); 127 } catch (IOException e) { 128 Log.i(LOG_TAG, "Badness during writes to socket: " + e); 129 } 130 } 131 }.start(); 132 133 int read = 0; 134 try { 135 Socket socket = server.accept(); 136 socket.setTcpNoDelay(true); 137 TrafficStats.setThreadStatsTag(0x43); 138 TrafficStats.tagSocket(socket); 139 InputStream in = socket.getInputStream(); 140 byte[] buf = new byte[byteCount]; 141 while (read < byteCount * packetCount) { 142 int n = in.read(buf); 143 assertTrue("Unexpected EOF", n > 0); 144 read += n; 145 } 146 } finally { 147 server.close(); 148 } 149 assertTrue("Not all data read back", read >= byteCount * packetCount); 150 151 // It's too fast to call getUidTxBytes function. 152 try { 153 Thread.sleep(1000); 154 } catch (InterruptedException e) { 155 } 156 157 long mobileTxPacketsAfter = TrafficStats.getMobileTxPackets(); 158 long mobileRxPacketsAfter = TrafficStats.getMobileRxPackets(); 159 long mobileTxBytesAfter = TrafficStats.getMobileTxBytes(); 160 long mobileRxBytesAfter = TrafficStats.getMobileRxBytes(); 161 long totalTxPacketsAfter = TrafficStats.getTotalTxPackets(); 162 long totalRxPacketsAfter = TrafficStats.getTotalRxPackets(); 163 long totalTxBytesAfter = TrafficStats.getTotalTxBytes(); 164 long totalRxBytesAfter = TrafficStats.getTotalRxBytes(); 165 long uidTxBytesAfter = TrafficStats.getUidTxBytes(Process.myUid()); 166 long uidRxBytesAfter = TrafficStats.getUidRxBytes(Process.myUid()); 167 long uidTxPacketsAfter = TrafficStats.getUidTxPackets(Process.myUid()); 168 long uidRxPacketsAfter = TrafficStats.getUidRxPackets(Process.myUid()); 169 long uidTxDeltaBytes = uidTxBytesAfter - uidTxBytesBefore; 170 long uidTxDeltaPackets = uidTxPacketsAfter - uidTxPacketsBefore; 171 long uidRxDeltaBytes = uidRxBytesAfter - uidRxBytesBefore; 172 long uidRxDeltaPackets = uidRxPacketsAfter - uidRxPacketsBefore; 173 174 // Localhost traffic *does* count against per-UID stats. 175 /* 176 * Calculations: 177 * - bytes 178 * bytes is approx: packets * data + packets * acks; 179 * but sometimes there are less acks than packets, so we set a lower 180 * limit of 1 ack. 181 * - setup/teardown 182 * + 7 approx.: syn, syn-ack, ack, fin-ack, ack, fin-ack, ack; 183 * but sometimes the last find-acks just vanish, so we set a lower limit of +5. 184 */ 185 final int maxExpectedExtraPackets = 7; 186 final int minExpectedExtraPackets = 5; 187 188 // Some other tests don't cleanup connections correctly. 189 // They have the same UID, so we discount their lingering traffic 190 // which happens only on non-localhost, such as TCP FIN retranmission packets 191 long deltaTxOtherPackets = (totalTxPacketsAfter - totalTxPacketsBefore) - uidTxDeltaPackets; 192 long deltaRxOtherPackets = (totalRxPacketsAfter - totalRxPacketsBefore) - uidRxDeltaPackets; 193 if (deltaTxOtherPackets > 0 || deltaRxOtherPackets > 0) { 194 Log.i(LOG_TAG, "lingering traffic data: " + deltaTxOtherPackets + "/" + deltaRxOtherPackets); 195 } 196 197 assertTrue("uidtxp: " + uidTxPacketsBefore + " -> " + uidTxPacketsAfter + " delta=" + uidTxDeltaPackets + 198 " Wanted: " + uidTxDeltaPackets + ">=" + packetCount + "+" + minExpectedExtraPackets + " && " + 199 uidTxDeltaPackets + "<=" + packetCount + "+" + packetCount + "+" + maxExpectedExtraPackets + "+" + deltaTxOtherPackets, 200 uidTxDeltaPackets >= packetCount + minExpectedExtraPackets && 201 uidTxDeltaPackets <= packetCount + packetCount + maxExpectedExtraPackets + deltaTxOtherPackets); 202 assertTrue("uidrxp: " + uidRxPacketsBefore + " -> " + uidRxPacketsAfter + " delta=" + uidRxDeltaPackets + 203 " Wanted: " + uidRxDeltaPackets + ">=" + packetCount + "+" + minExpectedExtraPackets + " && " + 204 uidRxDeltaPackets + "<=" + packetCount + "+" + packetCount + "+" + maxExpectedExtraPackets, 205 uidRxDeltaPackets >= packetCount + minExpectedExtraPackets && 206 uidRxDeltaPackets <= packetCount + packetCount + maxExpectedExtraPackets + deltaRxOtherPackets); 207 assertTrue("uidtxb: " + uidTxBytesBefore + " -> " + uidTxBytesAfter + " delta=" + uidTxDeltaBytes + 208 " Wanted: " + uidTxDeltaBytes + ">=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(minExpectedExtraPackets, 0) + " && " + 209 uidTxDeltaBytes + "<=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0), 210 uidTxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(minExpectedExtraPackets, 0) && 211 uidTxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets + deltaTxOtherPackets, 0)); 212 assertTrue("uidrxb: " + uidRxBytesBefore + " -> " + uidRxBytesAfter + " delta=" + uidRxDeltaBytes + 213 " Wanted: " + uidRxDeltaBytes + ">=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(minExpectedExtraPackets, 0) + " && " + 214 uidRxDeltaBytes + "<=" + tcpPacketToIpBytes(packetCount, byteCount) + "+" + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets, 0), 215 uidRxDeltaBytes >= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(minExpectedExtraPackets, 0) && 216 uidRxDeltaBytes <= tcpPacketToIpBytes(packetCount, byteCount) + tcpPacketToIpBytes(packetCount + maxExpectedExtraPackets + deltaRxOtherPackets, 0)); 217 218 // Localhost traffic *does* count against total stats. 219 // Fudge by 132 packets of 1500 bytes not related to the test. 220 assertTrue("ttxp: " + totalTxPacketsBefore + " -> " + totalTxPacketsAfter, 221 totalTxPacketsAfter >= totalTxPacketsBefore + uidTxDeltaPackets && 222 totalTxPacketsAfter <= totalTxPacketsBefore + uidTxDeltaPackets + 132); 223 assertTrue("trxp: " + totalRxPacketsBefore + " -> " + totalRxPacketsAfter, 224 totalRxPacketsAfter >= totalRxPacketsBefore + uidRxDeltaPackets && 225 totalRxPacketsAfter <= totalRxPacketsBefore + uidRxDeltaPackets + 132); 226 assertTrue("ttxb: " + totalTxBytesBefore + " -> " + totalTxBytesAfter, 227 totalTxBytesAfter >= totalTxBytesBefore + uidTxDeltaBytes && 228 totalTxBytesAfter <= totalTxBytesBefore + uidTxDeltaBytes + 132 * 1500); 229 assertTrue("trxb: " + totalRxBytesBefore + " -> " + totalRxBytesAfter, 230 totalRxBytesAfter >= totalRxBytesBefore + uidRxDeltaBytes && 231 totalRxBytesAfter <= totalRxBytesBefore + uidRxDeltaBytes + 132 * 1500); 232 233 // Localhost traffic should *not* count against mobile stats, 234 // There might be some other traffic, but nowhere near 1MB. 235 assertTrue("mtxp: " + mobileTxPacketsBefore + " -> " + mobileTxPacketsAfter, 236 mobileTxPacketsAfter >= mobileTxPacketsBefore && 237 mobileTxPacketsAfter <= mobileTxPacketsBefore + 500); 238 assertTrue("mrxp: " + mobileRxPacketsBefore + " -> " + mobileRxPacketsAfter, 239 mobileRxPacketsAfter >= mobileRxPacketsBefore && 240 mobileRxPacketsAfter <= mobileRxPacketsBefore + 500); 241 assertTrue("mtxb: " + mobileTxBytesBefore + " -> " + mobileTxBytesAfter, 242 mobileTxBytesAfter >= mobileTxBytesBefore && 243 mobileTxBytesAfter <= mobileTxBytesBefore + 200000); 244 assertTrue("mrxb: " + mobileRxBytesBefore + " -> " + mobileRxBytesAfter, 245 mobileRxBytesAfter >= mobileRxBytesBefore && 246 mobileRxBytesAfter <= mobileRxBytesBefore + 200000); 247 248 } 249 } 250