Home | History | Annotate | Download | only in cts
      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