diff options
| -rw-r--r-- | core/java/android/net/INetworkStatsService.aidl | 3 | ||||
| -rw-r--r-- | core/java/android/net/NetworkTemplate.java | 46 | ||||
| -rw-r--r-- | core/java/android/net/TrafficStats.java | 106 | ||||
| -rw-r--r-- | core/jni/android_net_TrafficStats.cpp | 198 | ||||
| -rw-r--r-- | services/java/com/android/server/net/NetworkStatsService.java | 27 |
5 files changed, 225 insertions, 155 deletions
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index b4f6367d870b..08d4c6cbf4ab 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -32,6 +32,9 @@ interface INetworkStatsService { /** Return data layer snapshot of UID network usage. */ NetworkStats getDataLayerSnapshotForUid(int uid); + /** Return set of any ifaces associated with mobile networks since boot. */ + String[] getMobileIfaces(); + /** Increment data layer count of operations performed for UID and tag. */ void incrementOperationCount(int uid, int tag, int operationCount); diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 50432a14d0c7..39a4d7bb0d8f 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -48,6 +48,8 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_MOBILE_4G = 3; public static final int MATCH_WIFI = 4; public static final int MATCH_ETHERNET = 5; + public static final int MATCH_MOBILE_WILDCARD = 6; + public static final int MATCH_WIFI_WILDCARD = 7; /** * Set of {@link NetworkInfo#getType()} that reflect data usage. @@ -86,11 +88,19 @@ public class NetworkTemplate implements Parcelable { } /** + * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks, + * regardless of IMSI. + */ + public static NetworkTemplate buildTemplateMobileWildcard() { + return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null); + } + + /** * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks, * regardless of SSID. */ public static NetworkTemplate buildTemplateWifiWildcard() { - return new NetworkTemplate(MATCH_WIFI, null, null); + return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null); } @Deprecated @@ -198,6 +208,10 @@ public class NetworkTemplate implements Parcelable { return matchesWifi(ident); case MATCH_ETHERNET: return matchesEthernet(ident); + case MATCH_MOBILE_WILDCARD: + return matchesMobileWildcard(ident); + case MATCH_WIFI_WILDCARD: + return matchesWifiWildcard(ident); default: throw new IllegalArgumentException("unknown network template"); } @@ -257,13 +271,7 @@ public class NetworkTemplate implements Parcelable { private boolean matchesWifi(NetworkIdentity ident) { switch (ident.mType) { case TYPE_WIFI: - if (mNetworkId == null) { - return true; - } else { - return Objects.equal(mNetworkId, ident.mNetworkId); - } - case TYPE_WIFI_P2P: - return mNetworkId == null; + return Objects.equal(mNetworkId, ident.mNetworkId); default: return false; } @@ -279,6 +287,24 @@ public class NetworkTemplate implements Parcelable { return false; } + private boolean matchesMobileWildcard(NetworkIdentity ident) { + if (ident.mType == TYPE_WIMAX) { + return true; + } else { + return contains(DATA_USAGE_NETWORK_TYPES, ident.mType); + } + } + + private boolean matchesWifiWildcard(NetworkIdentity ident) { + switch (ident.mType) { + case TYPE_WIFI: + case TYPE_WIFI_P2P: + return true; + default: + return false; + } + } + private static String getMatchRuleName(int matchRule) { switch (matchRule) { case MATCH_MOBILE_3G_LOWER: @@ -291,6 +317,10 @@ public class NetworkTemplate implements Parcelable { return "WIFI"; case MATCH_ETHERNET: return "ETHERNET"; + case MATCH_MOBILE_WILDCARD: + return "MOBILE_WILDCARD"; + case MATCH_WIFI_WILDCARD: + return "WIFI_WILDCARD"; default: return "UNKNOWN"; } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index ee3e1650aef8..e437d2e3475b 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -88,6 +88,16 @@ public class TrafficStats { */ public static final int TAG_SYSTEM_BACKUP = 0xFFFFFF03; + private static INetworkStatsService sStatsService; + + private synchronized static INetworkStatsService getStatsService() { + if (sStatsService == null) { + sStatsService = INetworkStatsService.Stub.asInterface( + ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); + } + return sStatsService; + } + /** * Snapshot of {@link NetworkStats} when the currently active profiling * session started, or {@code null} if no session active. @@ -228,11 +238,9 @@ public class TrafficStats { * @param operationCount Number of operations to increment count by. */ public static void incrementOperationCount(int tag, int operationCount) { - final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( - ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); final int uid = android.os.Process.myUid(); try { - statsService.incrementOperationCount(uid, tag, operationCount); + getStatsService().incrementOperationCount(uid, tag, operationCount); } catch (RemoteException e) { throw new RuntimeException(e); } @@ -257,7 +265,13 @@ public class TrafficStats { * @return number of packets. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static native long getMobileTxPackets(); + public static long getMobileTxPackets() { + long total = 0; + for (String iface : getMobileIfaces()) { + total += getTxPackets(iface); + } + return total; + } /** * Get the total number of packets received through the mobile interface. @@ -265,7 +279,13 @@ public class TrafficStats { * @return number of packets. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static native long getMobileRxPackets(); + public static long getMobileRxPackets() { + long total = 0; + for (String iface : getMobileIfaces()) { + total += getRxPackets(iface); + } + return total; + } /** * Get the total number of bytes transmitted through the mobile interface. @@ -273,7 +293,13 @@ public class TrafficStats { * @return number of bytes. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static native long getMobileTxBytes(); + public static long getMobileTxBytes() { + long total = 0; + for (String iface : getMobileIfaces()) { + total += getTxBytes(iface); + } + return total; + } /** * Get the total number of bytes received through the mobile interface. @@ -281,7 +307,13 @@ public class TrafficStats { * @return number of bytes. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static native long getMobileRxBytes(); + public static long getMobileRxBytes() { + long total = 0; + for (String iface : getMobileIfaces()) { + total += getRxBytes(iface); + } + return total; + } /** * Get the total number of packets transmitted through the specified interface. @@ -290,7 +322,9 @@ public class TrafficStats { * {@link #UNSUPPORTED} will be returned. * @hide */ - public static native long getTxPackets(String iface); + public static long getTxPackets(String iface) { + return nativeGetIfaceStat(iface, TYPE_TX_PACKETS); + } /** * Get the total number of packets received through the specified interface. @@ -299,7 +333,9 @@ public class TrafficStats { * {@link #UNSUPPORTED} will be returned. * @hide */ - public static native long getRxPackets(String iface); + public static long getRxPackets(String iface) { + return nativeGetIfaceStat(iface, TYPE_RX_PACKETS); + } /** * Get the total number of bytes transmitted through the specified interface. @@ -308,7 +344,9 @@ public class TrafficStats { * {@link #UNSUPPORTED} will be returned. * @hide */ - public static native long getTxBytes(String iface); + public static long getTxBytes(String iface) { + return nativeGetIfaceStat(iface, TYPE_TX_BYTES); + } /** * Get the total number of bytes received through the specified interface. @@ -317,8 +355,9 @@ public class TrafficStats { * {@link #UNSUPPORTED} will be returned. * @hide */ - public static native long getRxBytes(String iface); - + public static long getRxBytes(String iface) { + return nativeGetIfaceStat(iface, TYPE_RX_BYTES); + } /** * Get the total number of packets sent through all network interfaces. @@ -326,7 +365,9 @@ public class TrafficStats { * @return the number of packets. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static native long getTotalTxPackets(); + public static long getTotalTxPackets() { + return nativeGetTotalStat(TYPE_TX_PACKETS); + } /** * Get the total number of packets received through all network interfaces. @@ -334,7 +375,9 @@ public class TrafficStats { * @return number of packets. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static native long getTotalRxPackets(); + public static long getTotalRxPackets() { + return nativeGetTotalStat(TYPE_RX_PACKETS); + } /** * Get the total number of bytes sent through all network interfaces. @@ -342,7 +385,9 @@ public class TrafficStats { * @return number of bytes. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static native long getTotalTxBytes(); + public static long getTotalTxBytes() { + return nativeGetTotalStat(TYPE_TX_BYTES); + } /** * Get the total number of bytes received through all network interfaces. @@ -350,7 +395,9 @@ public class TrafficStats { * @return number of bytes. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static native long getTotalRxBytes(); + public static long getTotalRxBytes() { + return nativeGetTotalStat(TYPE_RX_BYTES); + } /** * Get the number of bytes sent through the network for this UID. @@ -483,7 +530,6 @@ public class TrafficStats { */ public static native long getUidTcpRxSegments(int uid); - /** * Get the number of UDP packets sent for this UID. * Includes DNS requests. @@ -515,13 +561,33 @@ public class TrafficStats { * special permission. */ private static NetworkStats getDataLayerSnapshotForUid(Context context) { - final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( - ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); final int uid = android.os.Process.myUid(); try { - return statsService.getDataLayerSnapshotForUid(uid); + return getStatsService().getDataLayerSnapshotForUid(uid); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Return set of any ifaces associated with mobile networks since boot. + * Interfaces are never removed from this list, so counters should always be + * monotonic. + */ + private static String[] getMobileIfaces() { + try { + return getStatsService().getMobileIfaces(); } catch (RemoteException e) { throw new RuntimeException(e); } } + + // NOTE: keep these in sync with android_net_TrafficStats.cpp + private static final int TYPE_RX_BYTES = 0; + private static final int TYPE_RX_PACKETS = 1; + private static final int TYPE_TX_BYTES = 2; + private static final int TYPE_TX_PACKETS = 3; + + private static native long nativeGetTotalStat(int type); + private static native long nativeGetIfaceStat(String iface, int type); } diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index 0ab659b2382f..325fe2604117 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -31,6 +31,9 @@ namespace android { +static const uint64_t VALUE_UNKNOWN = -1; +static const char* IFACE_STAT_ALL = "/proc/net/xt_qtaguid/iface_stat_all"; + enum Tx_Rx { TX, RX @@ -42,6 +45,21 @@ enum Tcp_Udp { TCP_AND_UDP }; +// NOTE: keep these in sync with TrafficStats.java +enum IfaceStatType { + RX_BYTES = 0, + RX_PACKETS = 1, + TX_BYTES = 2, + TX_PACKETS = 3 +}; + +struct IfaceStat { + uint64_t rxBytes; + uint64_t rxPackets; + uint64_t txBytes; + uint64_t txPackets; +}; + // Returns an ASCII decimal number read from the specified file, -1 on error. static jlong readNumber(char const* filename) { char buf[80]; @@ -63,130 +81,82 @@ static jlong readNumber(char const* filename) { return atoll(buf); } -static const char* mobile_iface_list[] = { - "rmnet0", - "rmnet1", - "rmnet2", - "rmnet3", - "cdma_rmnet4", - "ppp0", - 0 -}; - -static jlong getAll(const char** iface_list, const char* what) { - - char filename[80]; - int idx = 0; - bool supported = false; - jlong total = 0; - while (iface_list[idx] != 0) { - - snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s", - iface_list[idx], what); - jlong number = readNumber(filename); - if (number >= 0) { - supported = true; - total += number; - } - idx++; +static int parseIfaceStat(const char* iface, struct IfaceStat* stat) { + FILE *fp = fopen(IFACE_STAT_ALL, "r"); + if (!fp) { + return errno; } - if (supported) return total; - return -1; -} - -// 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) { - ALOGE("Can't list %s: %s", filename, strerror(errno)); - return -1; - } + char buffer[256]; + char cur_iface[32]; + int active; + uint64_t rxBytes, rxPackets, txBytes, txPackets, devRxBytes, devRxPackets, devTxBytes, + devTxPackets; + + while (fgets(buffer, 256, fp) != NULL) { + if (sscanf(buffer, "%31s %d %llu %llu %llu %llu %llu %llu %llu %llu", cur_iface, &active, + &rxBytes, &rxPackets, &txBytes, &txPackets, &devRxBytes, &devRxPackets, + &devTxBytes, &devTxPackets) != 10) { + continue; + } - 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; + if (!iface || !strcmp(iface, cur_iface)) { + stat->rxBytes += rxBytes; + stat->rxPackets += rxPackets; + stat->txBytes += txBytes; + stat->txPackets += txPackets; + + if (active) { + stat->rxBytes += devRxBytes; + stat->rxPackets += devRxPackets; + stat->txBytes += devTxBytes; + stat->txPackets += devTxPackets; + } } } - 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 getAll(mobile_iface_list, "tx_packets"); -} - -static jlong getMobileRxPackets(JNIEnv* env, jobject clazz) { - return getAll(mobile_iface_list, "rx_packets"); + fclose(fp); + return 0; } -static jlong getMobileTxBytes(JNIEnv* env, jobject clazz) { - return getAll(mobile_iface_list, "tx_bytes"); -} - -static jlong getMobileRxBytes(JNIEnv* env, jobject clazz) { - return getAll(mobile_iface_list, "rx_bytes"); -} +static uint64_t getIfaceStatType(const char* iface, IfaceStatType type) { + struct IfaceStat stat; + memset(&stat, 0, sizeof(IfaceStat)); -static jlong getData(JNIEnv* env, const char* what, jstring javaInterface) { - ScopedUtfChars interface(env, javaInterface); - if (interface.c_str() == NULL) { - return -1; + if (parseIfaceStat(iface, &stat)) { + return VALUE_UNKNOWN; } - char filename[80]; - snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s", interface.c_str(), what); - return readNumber(filename); -} - -static jlong getTxPackets(JNIEnv* env, jobject clazz, jstring interface) { - return getData(env, "tx_packets", interface); -} - -static jlong getRxPackets(JNIEnv* env, jobject clazz, jstring interface) { - return getData(env, "rx_packets", interface); -} - -static jlong getTxBytes(JNIEnv* env, jobject clazz, jstring interface) { - return getData(env, "tx_bytes", interface); -} - -static jlong getRxBytes(JNIEnv* env, jobject clazz, jstring interface) { - return getData(env, "rx_bytes", interface); -} - - -// 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"); + switch (type) { + case RX_BYTES: + return stat.rxBytes; + case RX_PACKETS: + return stat.rxPackets; + case TX_BYTES: + return stat.txBytes; + case TX_PACKETS: + return stat.txPackets; + default: + return VALUE_UNKNOWN; + } } -static jlong getTotalRxPackets(JNIEnv* env, jobject clazz) { - return readTotal("/statistics/rx_packets"); +static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) { + return getIfaceStatType(NULL, (IfaceStatType) type); } -static jlong getTotalTxBytes(JNIEnv* env, jobject clazz) { - return readTotal("/statistics/tx_bytes"); +static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) { + struct IfaceStat stat; + const char* ifaceChars = env->GetStringUTFChars(iface, NULL); + if (ifaceChars) { + uint64_t stat = getIfaceStatType(ifaceChars, (IfaceStatType) type); + env->ReleaseStringUTFChars(iface, ifaceChars); + return stat; + } else { + return VALUE_UNKNOWN; + } } -static jlong getTotalRxBytes(JNIEnv* env, jobject clazz) { - return readTotal("/statistics/rx_bytes"); -} // Per-UID stats require reading from a constructed filename. @@ -323,18 +293,8 @@ static jlong getUidUdpRxPackets(JNIEnv* env, jobject clazz, jint uid) { } static JNINativeMethod gMethods[] = { - {"getMobileTxPackets", "()J", (void*) getMobileTxPackets}, - {"getMobileRxPackets", "()J", (void*) getMobileRxPackets}, - {"getMobileTxBytes", "()J", (void*) getMobileTxBytes}, - {"getMobileRxBytes", "()J", (void*) getMobileRxBytes}, - {"getTxPackets", "(Ljava/lang/String;)J", (void*) getTxPackets}, - {"getRxPackets", "(Ljava/lang/String;)J", (void*) getRxPackets}, - {"getTxBytes", "(Ljava/lang/String;)J", (void*) getTxBytes}, - {"getRxBytes", "(Ljava/lang/String;)J", (void*) getRxBytes}, - {"getTotalTxPackets", "()J", (void*) getTotalTxPackets}, - {"getTotalRxPackets", "()J", (void*) getTotalRxPackets}, - {"getTotalTxBytes", "()J", (void*) getTotalTxBytes}, - {"getTotalRxBytes", "()J", (void*) getTotalRxBytes}, + {"nativeGetTotalStat", "(I)J", (void*) getTotalStat}, + {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*) getIfaceStat}, /* Per-UID Stats */ {"getUidTxBytes", "(I)J", (void*) getUidTxBytes}, diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 4382a03fa2ac..2a67e02db289 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -26,6 +26,7 @@ import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; +import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; @@ -33,7 +34,7 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; -import static android.net.NetworkTemplate.buildTemplateMobileAll; +import static android.net.NetworkTemplate.buildTemplateMobileWildcard; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; import static android.net.TrafficStats.MB_IN_BYTES; import static android.provider.Settings.Secure.NETSTATS_DEV_BUCKET_DURATION; @@ -54,6 +55,8 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.SECOND_IN_MILLIS; +import static com.android.internal.util.ArrayUtils.appendElement; +import static com.android.internal.util.ArrayUtils.contains; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; @@ -194,6 +197,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private HashMap<String, NetworkIdentitySet> mActiveIfaces = Maps.newHashMap(); /** Current default active iface. */ private String mActiveIface; + /** Set of any ifaces associated with mobile networks since boot. */ + private String[] mMobileIfaces = new String[0]; private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); @@ -517,6 +522,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override + public String[] getMobileIfaces() { + return mMobileIfaces; + } + + @Override public void incrementOperationCount(int uid, int tag, int operationCount) { if (Binder.getCallingUid() != uid) { mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG); @@ -735,6 +745,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state)); + + // remember any ifaces associated with mobile networks + if (isNetworkTypeMobile(state.networkInfo.getType())) { + if (!contains(mMobileIfaces, iface)) { + mMobileIfaces = appendElement(String.class, mMobileIfaces, iface); + } + } } } } @@ -861,7 +878,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStats.Entry uidTotal; // collect mobile sample - template = buildTemplateMobileAll(getActiveSubscriberId(mContext)); + template = buildTemplateMobileWildcard(); devTotal = mDevRecorder.getTotalSinceBootLocked(template); xtTotal = new NetworkStats.Entry(); uidTotal = mUidRecorder.getTotalSinceBootLocked(template); @@ -1022,12 +1039,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; - private static String getActiveSubscriberId(Context context) { - final TelephonyManager telephony = (TelephonyManager) context.getSystemService( - Context.TELEPHONY_SERVICE); - return telephony.getSubscriberId(); - } - private boolean isBandwidthControlEnabled() { try { return mNetworkManager.isBandwidthControlEnabled(); |