diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index b0930b2ae2..8bd1738937 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -124,6 +124,22 @@ public class NetworkStatsHistory implements Parcelable { return bucketDuration; } + public long getStart() { + if (bucketCount > 0) { + return bucketStart[0]; + } else { + return Long.MAX_VALUE; + } + } + + public long getEnd() { + if (bucketCount > 0) { + return bucketStart[bucketCount - 1] + bucketDuration; + } else { + return Long.MIN_VALUE; + } + } + /** * Return specific stats entry. */ @@ -253,9 +269,20 @@ public class NetworkStatsHistory implements Parcelable { * Return interpolated data usage across the requested range. Interpolates * across buckets, so values may be rounded slightly. */ - public long[] getTotalData(long start, long end, long[] outTotal) { - long rx = 0; - long tx = 0; + public Entry getValues(long start, long end, Entry recycle) { + return getValues(start, end, Long.MAX_VALUE, recycle); + } + + /** + * Return interpolated data usage across the requested range. Interpolates + * across buckets, so values may be rounded slightly. + */ + public Entry getValues(long start, long end, long now, Entry recycle) { + final Entry entry = recycle != null ? recycle : new Entry(); + entry.bucketStart = start; + entry.bucketDuration = end - start; + entry.rxBytes = 0; + entry.txBytes = 0; for (int i = bucketCount - 1; i >= 0; i--) { final long curStart = bucketStart[i]; @@ -266,19 +293,19 @@ public class NetworkStatsHistory implements Parcelable { // bucket is newer than record; keep looking if (curStart > end) continue; + // include full value for active buckets, otherwise only fractional + final boolean activeBucket = curStart < now && curEnd > now; final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); - if (overlap > 0) { - rx += this.rxBytes[i] * overlap / bucketDuration; - tx += this.txBytes[i] * overlap / bucketDuration; + if (activeBucket || overlap == bucketDuration) { + entry.rxBytes += rxBytes[i]; + entry.txBytes += txBytes[i]; + } else if (overlap > 0) { + entry.rxBytes += rxBytes[i] * overlap / bucketDuration; + entry.txBytes += txBytes[i] * overlap / bucketDuration; } } - if (outTotal == null || outTotal.length != 2) { - outTotal = new long[2]; - } - outTotal[0] = rx; - outTotal[1] = tx; - return outTotal; + return entry; } /** diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 872438c5e5..54e94db073 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -313,21 +313,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { + // use system clock to be externally consistent + final long now = System.currentTimeMillis(); + final NetworkStats stats = new NetworkStats(end - start, 1); final NetworkStats.Entry entry = new NetworkStats.Entry(); - long[] total = new long[2]; + NetworkStatsHistory.Entry historyEntry = null; // combine total from all interfaces that match template for (NetworkIdentitySet ident : mNetworkStats.keySet()) { if (templateMatches(template, ident)) { final NetworkStatsHistory history = mNetworkStats.get(ident); - total = history.getTotalData(start, end, total); + historyEntry = history.getValues(start, end, now, historyEntry); entry.iface = IFACE_ALL; entry.uid = UID_ALL; entry.tag = TAG_NONE; - entry.rxBytes = total[0]; - entry.txBytes = total[1]; + entry.rxBytes = historyEntry.rxBytes; + entry.txBytes = historyEntry.txBytes; stats.combineValues(entry); } @@ -345,9 +348,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { synchronized (mStatsLock) { ensureUidStatsLoadedLocked(); + // use system clock to be externally consistent + final long now = System.currentTimeMillis(); + final NetworkStats stats = new NetworkStats(end - start, 24); final NetworkStats.Entry entry = new NetworkStats.Entry(); - long[] total = new long[2]; + NetworkStatsHistory.Entry historyEntry = null; for (NetworkIdentitySet ident : mUidStats.keySet()) { if (templateMatches(template, ident)) { @@ -361,13 +367,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // other tags when requested. if (tag == TAG_NONE || includeTags) { final NetworkStatsHistory history = uidStats.valueAt(i); - total = history.getTotalData(start, end, total); + historyEntry = history.getValues(start, end, now, historyEntry); entry.iface = IFACE_ALL; entry.uid = uid; entry.tag = tag; - entry.rxBytes = total[0]; - entry.txBytes = total[1]; + entry.rxBytes = historyEntry.rxBytes; + entry.txBytes = historyEntry.txBytes; if (entry.rxBytes > 0 || entry.txBytes > 0) { stats.combineValues(entry); @@ -425,6 +431,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // broadcast. final int uid = intent.getIntExtra(EXTRA_UID, 0); synchronized (mStatsLock) { + // TODO: perform one last stats poll for UID removeUidLocked(uid); } }