diff options
author | Dan Egnor <egnor@google.com> | 2010-04-07 17:30:50 -0700 |
---|---|---|
committer | Dan Egnor <egnor@google.com> | 2010-04-07 19:06:29 -0700 |
commit | 2b4abcd0c7c4361af8ab6d5d7b073fb75ac6d219 (patch) | |
tree | 94358e480c3ceb0d9c6afb649cadf748ae82cf5d /core/jni/android_net_TrafficStats.cpp | |
parent | fd998a0caf8cfcd27d1fe73120fbb897ec74af85 (diff) | |
download | frameworks_base-2b4abcd0c7c4361af8ab6d5d7b073fb75ac6d219.zip frameworks_base-2b4abcd0c7c4361af8ab6d5d7b073fb75ac6d219.tar.gz frameworks_base-2b4abcd0c7c4361af8ab6d5d7b073fb75ac6d219.tar.bz2 |
Change TrafficStats to a new JNI implementation.
Also change phone's ConnectionStateTrackers to use it directly,
rather than through the INetStat binder interface.
Bug: 2578938
Change-Id: I8858e2609cbec3be845a0ce5178cb03f67e01b41
Diffstat (limited to 'core/jni/android_net_TrafficStats.cpp')
-rw-r--r-- | core/jni/android_net_TrafficStats.cpp | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp new file mode 100644 index 0000000..db8fdf2 --- /dev/null +++ b/core/jni/android_net_TrafficStats.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2010 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. + */ + +#define LOG_TAG "TrafficStats" + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <android_runtime/AndroidRuntime.h> +#include <cutils/logger.h> +#include <jni.h> +#include <utils/misc.h> +#include <utils/Log.h> + +namespace android { + +// Returns an ASCII decimal number read from the specified file, -1 on error. +static jlong readNumber(char const* filename) { + char buf[80]; + int fd = open(filename, O_RDONLY); + if (fd < 0) { + if (errno != ENOENT) LOGE("Can't open %s: %s", filename, strerror(errno)); + return -1; + } + + int len = read(fd, buf, sizeof(buf) - 1); + if (len < 0) { + LOGE("Can't read %s: %s", filename, strerror(errno)); + close(fd); + return -1; + } + + close(fd); + buf[len] = '\0'; + return atoll(buf); +} + +// Return the number from the first file which exists and contains data +static jlong tryBoth(char const* a, char const* b) { + jlong num = readNumber(a); + return num >= 0 ? num : readNumber(b); +} + +// Returns the sum of numbers from the specified path under /sys/class/net/*, +// -1 if no such file exists. +static jlong readTotal(char const* suffix) { + char filename[PATH_MAX] = "/sys/class/net/"; + DIR *dir = opendir(filename); + if (dir == NULL) { + LOGE("Can't list %s: %s", filename, strerror(errno)); + return -1; + } + + int len = strlen(filename); + jlong total = -1; + while (struct dirent *entry = readdir(dir)) { + // Skip ., .., and localhost interfaces. + if (entry->d_name[0] != '.' && strncmp(entry->d_name, "lo", 2) != 0) { + strlcpy(filename + len, entry->d_name, sizeof(filename) - len); + strlcat(filename, suffix, sizeof(filename)); + jlong num = readNumber(filename); + if (num >= 0) total = total < 0 ? num : total + num; + } + } + + closedir(dir); + return total; +} + +// Mobile stats get accessed a lot more often than total stats. +// Note the individual files can come and go at runtime, so we check +// each file every time (rather than caching which ones exist). + +static jlong getMobileTxPackets(JNIEnv* env, jobject clazz) { + return tryBoth( + "/sys/class/net/rmnet0/statistics/tx_packets", + "/sys/class/net/ppp0/statistics/tx_packets"); +} + +static jlong getMobileRxPackets(JNIEnv* env, jobject clazz) { + return tryBoth( + "/sys/class/net/rmnet0/statistics/rx_packets", + "/sys/class/net/ppp0/statistics/rx_packets"); +} + +static jlong getMobileTxBytes(JNIEnv* env, jobject clazz) { + return tryBoth( + "/sys/class/net/rmnet0/statistics/tx_bytes", + "/sys/class/net/ppp0/statistics/tx_bytes"); +} + +static jlong getMobileRxBytes(JNIEnv* env, jobject clazz) { + return tryBoth( + "/sys/class/net/rmnet0/statistics/rx_bytes", + "/sys/class/net/ppp0/statistics/rx_bytes"); +} + +// Total stats are read less often, so we're willing to put up +// with listing the directory and concatenating filenames. + +static jlong getTotalTxPackets(JNIEnv* env, jobject clazz) { + return readTotal("/statistics/tx_packets"); +} + +static jlong getTotalRxPackets(JNIEnv* env, jobject clazz) { + return readTotal("/statistics/rx_packets"); +} + +static jlong getTotalTxBytes(JNIEnv* env, jobject clazz) { + return readTotal("/statistics/tx_bytes"); +} + +static jlong getTotalRxBytes(JNIEnv* env, jobject clazz) { + return readTotal("/statistics/rx_bytes"); +} + +// Per-UID stats require reading from a constructed filename. + +static jlong getUidRxBytes(JNIEnv* env, jobject clazz, jint uid) { + char filename[80]; + sprintf(filename, "/proc/uid_stat/%d/tcp_rcv", uid); + return readNumber(filename); +} + +static jlong getUidTxBytes(JNIEnv* env, jobject clazz, jint uid) { + char filename[80]; + sprintf(filename, "/proc/uid_stat/%d/tcp_snd", uid); + return readNumber(filename); +} + +static JNINativeMethod gMethods[] = { + {"getMobileTxPackets", "()J", (void*) getMobileTxPackets}, + {"getMobileRxPackets", "()J", (void*) getMobileRxPackets}, + {"getMobileTxBytes", "()J", (void*) getMobileTxBytes}, + {"getMobileRxBytes", "()J", (void*) getMobileRxBytes}, + {"getTotalTxPackets", "()J", (void*) getTotalTxPackets}, + {"getTotalRxPackets", "()J", (void*) getTotalRxPackets}, + {"getTotalTxBytes", "()J", (void*) getTotalTxBytes}, + {"getTotalRxBytes", "()J", (void*) getTotalRxBytes}, + {"getUidTxBytes", "(I)J", (void*) getUidTxBytes}, + {"getUidRxBytes", "(I)J", (void*) getUidRxBytes}, +}; + +int register_android_net_TrafficStats(JNIEnv* env) { + return AndroidRuntime::registerNativeMethods(env, "android/net/TrafficStats", + gMethods, NELEM(gMethods)); +} + +} |