android_net_TrafficStats.cpp revision 2b4abcd0c7c4361af8ab6d5d7b073fb75ac6d219
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#define LOG_TAG "TrafficStats" 18 19#include <dirent.h> 20#include <errno.h> 21#include <fcntl.h> 22#include <sys/stat.h> 23#include <sys/types.h> 24 25#include <android_runtime/AndroidRuntime.h> 26#include <cutils/logger.h> 27#include <jni.h> 28#include <utils/misc.h> 29#include <utils/Log.h> 30 31namespace android { 32 33// Returns an ASCII decimal number read from the specified file, -1 on error. 34static jlong readNumber(char const* filename) { 35 char buf[80]; 36 int fd = open(filename, O_RDONLY); 37 if (fd < 0) { 38 if (errno != ENOENT) LOGE("Can't open %s: %s", filename, strerror(errno)); 39 return -1; 40 } 41 42 int len = read(fd, buf, sizeof(buf) - 1); 43 if (len < 0) { 44 LOGE("Can't read %s: %s", filename, strerror(errno)); 45 close(fd); 46 return -1; 47 } 48 49 close(fd); 50 buf[len] = '\0'; 51 return atoll(buf); 52} 53 54// Return the number from the first file which exists and contains data 55static jlong tryBoth(char const* a, char const* b) { 56 jlong num = readNumber(a); 57 return num >= 0 ? num : readNumber(b); 58} 59 60// Returns the sum of numbers from the specified path under /sys/class/net/*, 61// -1 if no such file exists. 62static jlong readTotal(char const* suffix) { 63 char filename[PATH_MAX] = "/sys/class/net/"; 64 DIR *dir = opendir(filename); 65 if (dir == NULL) { 66 LOGE("Can't list %s: %s", filename, strerror(errno)); 67 return -1; 68 } 69 70 int len = strlen(filename); 71 jlong total = -1; 72 while (struct dirent *entry = readdir(dir)) { 73 // Skip ., .., and localhost interfaces. 74 if (entry->d_name[0] != '.' && strncmp(entry->d_name, "lo", 2) != 0) { 75 strlcpy(filename + len, entry->d_name, sizeof(filename) - len); 76 strlcat(filename, suffix, sizeof(filename)); 77 jlong num = readNumber(filename); 78 if (num >= 0) total = total < 0 ? num : total + num; 79 } 80 } 81 82 closedir(dir); 83 return total; 84} 85 86// Mobile stats get accessed a lot more often than total stats. 87// Note the individual files can come and go at runtime, so we check 88// each file every time (rather than caching which ones exist). 89 90static jlong getMobileTxPackets(JNIEnv* env, jobject clazz) { 91 return tryBoth( 92 "/sys/class/net/rmnet0/statistics/tx_packets", 93 "/sys/class/net/ppp0/statistics/tx_packets"); 94} 95 96static jlong getMobileRxPackets(JNIEnv* env, jobject clazz) { 97 return tryBoth( 98 "/sys/class/net/rmnet0/statistics/rx_packets", 99 "/sys/class/net/ppp0/statistics/rx_packets"); 100} 101 102static jlong getMobileTxBytes(JNIEnv* env, jobject clazz) { 103 return tryBoth( 104 "/sys/class/net/rmnet0/statistics/tx_bytes", 105 "/sys/class/net/ppp0/statistics/tx_bytes"); 106} 107 108static jlong getMobileRxBytes(JNIEnv* env, jobject clazz) { 109 return tryBoth( 110 "/sys/class/net/rmnet0/statistics/rx_bytes", 111 "/sys/class/net/ppp0/statistics/rx_bytes"); 112} 113 114// Total stats are read less often, so we're willing to put up 115// with listing the directory and concatenating filenames. 116 117static jlong getTotalTxPackets(JNIEnv* env, jobject clazz) { 118 return readTotal("/statistics/tx_packets"); 119} 120 121static jlong getTotalRxPackets(JNIEnv* env, jobject clazz) { 122 return readTotal("/statistics/rx_packets"); 123} 124 125static jlong getTotalTxBytes(JNIEnv* env, jobject clazz) { 126 return readTotal("/statistics/tx_bytes"); 127} 128 129static jlong getTotalRxBytes(JNIEnv* env, jobject clazz) { 130 return readTotal("/statistics/rx_bytes"); 131} 132 133// Per-UID stats require reading from a constructed filename. 134 135static jlong getUidRxBytes(JNIEnv* env, jobject clazz, jint uid) { 136 char filename[80]; 137 sprintf(filename, "/proc/uid_stat/%d/tcp_rcv", uid); 138 return readNumber(filename); 139} 140 141static jlong getUidTxBytes(JNIEnv* env, jobject clazz, jint uid) { 142 char filename[80]; 143 sprintf(filename, "/proc/uid_stat/%d/tcp_snd", uid); 144 return readNumber(filename); 145} 146 147static JNINativeMethod gMethods[] = { 148 {"getMobileTxPackets", "()J", (void*) getMobileTxPackets}, 149 {"getMobileRxPackets", "()J", (void*) getMobileRxPackets}, 150 {"getMobileTxBytes", "()J", (void*) getMobileTxBytes}, 151 {"getMobileRxBytes", "()J", (void*) getMobileRxBytes}, 152 {"getTotalTxPackets", "()J", (void*) getTotalTxPackets}, 153 {"getTotalRxPackets", "()J", (void*) getTotalRxPackets}, 154 {"getTotalTxBytes", "()J", (void*) getTotalTxBytes}, 155 {"getTotalRxBytes", "()J", (void*) getTotalRxBytes}, 156 {"getUidTxBytes", "(I)J", (void*) getUidTxBytes}, 157 {"getUidRxBytes", "(I)J", (void*) getUidRxBytes}, 158}; 159 160int register_android_net_TrafficStats(JNIEnv* env) { 161 return AndroidRuntime::registerNativeMethods(env, "android/net/TrafficStats", 162 gMethods, NELEM(gMethods)); 163} 164 165} 166