TrafficStats.java revision f7d0b01387c10f93bf17981d45087810c80f0902
1/* 2 * Copyright (C) 2007 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 17package android.net; 18 19import android.util.Log; 20 21import java.io.File; 22import java.io.RandomAccessFile; 23import java.io.IOException; 24 25/** 26 * Class that provides network traffic statistics. These statistics include bytes transmitted and 27 * received and network packets transmitted and received, over all interfaces, over the mobile 28 * interface, and on a per-UID basis. 29 * <p> 30 * These statistics may not be available on all platforms. If the statistics are not supported 31 * by this device, {@link #UNSUPPORTED} will be returned. 32 */ 33public class TrafficStats { 34 /** 35 * The return value to indicate that the device does not support the statistic. 36 */ 37 public final static int UNSUPPORTED = -1; 38 39 // Logging tag. 40 private final static String TAG = "trafficstats"; 41 42 // We pre-create all the File objects so we don't spend a lot of 43 // CPU at runtime converting from Java Strings to byte[] for the 44 // kernel calls. 45 private final static File[] MOBILE_TX_PACKETS = mobileFiles("tx_packets"); 46 private final static File[] MOBILE_RX_PACKETS = mobileFiles("rx_packets"); 47 private final static File[] MOBILE_TX_BYTES = mobileFiles("tx_bytes"); 48 private final static File[] MOBILE_RX_BYTES = mobileFiles("rx_bytes"); 49 private final static File SYS_CLASS_NET_DIR = new File("/sys/class/net"); 50 51 /** 52 * Get the total number of packets transmitted through the mobile interface. 53 * 54 * @return number of packets. If the statistics are not supported by this device, 55 * {@link #UNSUPPORTED} will be returned. 56 */ 57 public static long getMobileTxPkts() { 58 return getMobileStat(MOBILE_TX_PACKETS); 59 } 60 61 /** 62 * Get the total number of packets received through the mobile interface. 63 * 64 * @return number of packets. If the statistics are not supported by this device, 65 * {@link #UNSUPPORTED} will be returned. 66 */ 67 public static long getMobileRxPkts() { 68 return getMobileStat(MOBILE_RX_PACKETS); 69 } 70 71 /** 72 * Get the total number of bytes transmitted through the mobile interface. 73 * 74 * @return number of bytes. If the statistics are not supported by this device, 75 * {@link #UNSUPPORTED} will be returned. 76 */ 77 public static long getMobileTxBytes() { 78 return getMobileStat(MOBILE_TX_BYTES); 79 } 80 81 /** 82 * Get the total number of bytes received through the mobile interface. 83 * 84 * @return number of bytes. If the statistics are not supported by this device, 85 * {@link #UNSUPPORTED} will be returned. 86 */ 87 public static long getMobileRxBytes() { 88 return getMobileStat(MOBILE_RX_BYTES); 89 } 90 91 /** 92 * Get the total number of packets sent through all network interfaces. 93 * 94 * @return the number of packets. If the statistics are not supported by this device, 95 * {@link #UNSUPPORTED} will be returned. 96 */ 97 public static long getTotalTxPkts() { 98 return getTotalStat("tx_packets"); 99 } 100 101 /** 102 * Get the total number of packets received through all network interfaces. 103 * 104 * @return number of packets. If the statistics are not supported by this device, 105 * {@link #UNSUPPORTED} will be returned. 106 */ 107 public static long getTotalRxPkts() { 108 return getTotalStat("rx_packets"); 109 } 110 111 /** 112 * Get the total number of bytes sent through all network interfaces. 113 * 114 * @return number of bytes. If the statistics are not supported by this device, 115 * {@link #UNSUPPORTED} will be returned. 116 */ 117 public static long getTotalTxBytes() { 118 return getTotalStat("tx_bytes"); 119 } 120 121 /** 122 * Get the total number of bytes received through all network interfaces. 123 * 124 * @return number of bytes. If the statistics are not supported by this device, 125 * {@link #UNSUPPORTED} will be returned. 126 */ 127 public static long getTotalRxBytes() { 128 return getTotalStat("rx_bytes"); 129 } 130 131 /** 132 * Get the number of bytes sent through the network for this UID. 133 * The statistics are across all interfaces. 134 * 135 * {@see android.os.Process#myUid()}. 136 * 137 * @param uid The UID of the process to examine. 138 * @return number of bytes. If the statistics are not supported by this device, 139 * {@link #UNSUPPORTED} will be returned. 140 */ 141 public static long getUidTxBytes(int uid) { 142 return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_snd"); 143 } 144 145 /** 146 * Get the number of bytes received through the network for this UID. 147 * The statistics are across all interfaces. 148 * 149 * {@see android.os.Process#myUid()}. 150 * 151 * @param uid The UID of the process to examine. 152 * @return number of bytes 153 */ 154 public static long getUidRxBytes(int uid) { 155 return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_rcv"); 156 } 157 158 /** 159 * Returns the array of two possible File locations for a given 160 * statistic. 161 */ 162 private static File[] mobileFiles(String whatStat) { 163 // Note that we stat them at runtime to see which is 164 // available, rather than here, to guard against the files 165 // coming & going later as modules shut down (e.g. airplane 166 // mode) and whatnot. The runtime stat() isn't expensive compared 167 // to the previous charset conversion that happened before we 168 // were reusing File instances. 169 File[] files = new File[2]; 170 files[0] = new File("/sys/class/net/rmnet0/statistics/" + whatStat); 171 files[1] = new File("/sys/class/net/ppp0/statistics/" + whatStat); 172 return files; 173 } 174 175 private static long getTotalStat(String whatStat) { 176 File netdir = new File("/sys/class/net"); 177 178 File[] nets = SYS_CLASS_NET_DIR.listFiles(); 179 if (nets == null) { 180 return UNSUPPORTED; 181 } 182 long total = 0; 183 StringBuffer strbuf = new StringBuffer(); 184 for (File net : nets) { 185 strbuf.append(net.getPath()).append(File.separator).append("statistics") 186 .append(File.separator).append(whatStat); 187 total += getNumberFromFilePath(strbuf.toString()); 188 strbuf.setLength(0); 189 } 190 return total; 191 } 192 193 private static long getMobileStat(File[] files) { 194 for (int i = 0; i < files.length; i++) { 195 File file = files[i]; 196 if (!file.exists()) { 197 continue; 198 } 199 try { 200 RandomAccessFile raf = new RandomAccessFile(file, "r"); 201 return getNumberFromFile(raf, file.getAbsolutePath()); 202 } catch (IOException e) { 203 Log.w(TAG, 204 "Exception opening TCP statistics file " + file.getAbsolutePath(), 205 e); 206 } 207 } 208 return UNSUPPORTED; 209 } 210 211 // File will have format <number><newline> 212 private static long getNumberFromFilePath(String filename) { 213 RandomAccessFile raf = getFile(filename); 214 if (raf == null) { 215 return UNSUPPORTED; 216 } 217 return getNumberFromFile(raf, filename); 218 } 219 220 // Private buffer for getNumberFromFile. Safe for re-use because 221 // getNumberFromFile is synchronized. 222 private final static byte[] buf = new byte[16]; 223 224 private static synchronized long getNumberFromFile(RandomAccessFile raf, String filename) { 225 try { 226 raf.read(buf); 227 raf.close(); 228 } catch (IOException e) { 229 Log.w(TAG, "Exception getting TCP bytes from " + filename, e); 230 return UNSUPPORTED; 231 } finally { 232 if (raf != null) { 233 try { 234 raf.close(); 235 } catch (IOException e) { 236 Log.w(TAG, "Exception closing " + filename, e); 237 } 238 } 239 } 240 241 long num = 0L; 242 for (int i = 0; i < buf.length; i++) { 243 if (buf[i] < '0' || buf[i] > '9') { 244 break; 245 } 246 num *= 10; 247 num += buf[i] - '0'; 248 } 249 return num; 250 } 251 252 private static RandomAccessFile getFile(String filename) { 253 File f = new File(filename); 254 if (!f.canRead()) { 255 return null; 256 } 257 258 try { 259 return new RandomAccessFile(f, "r"); 260 } catch (IOException e) { 261 Log.w(TAG, "Exception opening TCP statistics file " + filename, e); 262 return null; 263 } 264 } 265} 266