Loading core/java/android/net/NetworkStatsHistory.java +39 −12 Original line number Diff line number Diff line Loading @@ -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. */ Loading Loading @@ -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]; Loading @@ -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; } /** Loading core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java +45 −57 Original line number Diff line number Diff line Loading @@ -55,7 +55,7 @@ public class NetworkStatsHistoryTest extends TestCase { stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 1024L, 2048L); assertEquals(1, stats.size()); assertEntry(stats, 0, 1024L, 2048L); assertValues(stats, 0, 1024L, 2048L); } public void testRecordEqualBuckets() throws Exception { Loading @@ -67,8 +67,8 @@ public class NetworkStatsHistoryTest extends TestCase { stats.recordData(recordStart, recordStart + bucketDuration, 1024L, 128L); assertEquals(2, stats.size()); assertEntry(stats, 0, 512L, 64L); assertEntry(stats, 1, 512L, 64L); assertValues(stats, 0, 512L, 64L); assertValues(stats, 1, 512L, 64L); } public void testRecordTouchingBuckets() throws Exception { Loading @@ -83,11 +83,11 @@ public class NetworkStatsHistoryTest extends TestCase { assertEquals(3, stats.size()); // first bucket should have (1/20 of value) assertEntry(stats, 0, 50L, 250L); assertValues(stats, 0, 50L, 250L); // second bucket should have (15/20 of value) assertEntry(stats, 1, 750L, 3750L); assertValues(stats, 1, 750L, 3750L); // final bucket should have (4/20 of value) assertEntry(stats, 2, 200L, 1000L); assertValues(stats, 2, 200L, 1000L); } public void testRecordGapBuckets() throws Exception { Loading @@ -102,8 +102,8 @@ public class NetworkStatsHistoryTest extends TestCase { // we should have two buckets, far apart from each other assertEquals(2, stats.size()); assertEntry(stats, 0, 128L, 256L); assertEntry(stats, 1, 64L, 512L); assertValues(stats, 0, 128L, 256L); assertValues(stats, 1, 64L, 512L); // now record something in middle, spread across two buckets final long middleStart = TEST_START + DAY_IN_MILLIS; Loading @@ -112,10 +112,10 @@ public class NetworkStatsHistoryTest extends TestCase { // now should have four buckets, with new record in middle two buckets assertEquals(4, stats.size()); assertEntry(stats, 0, 128L, 256L); assertEntry(stats, 1, 1024L, 1024L); assertEntry(stats, 2, 1024L, 1024L); assertEntry(stats, 3, 64L, 512L); assertValues(stats, 0, 128L, 256L); assertValues(stats, 1, 1024L, 1024L); assertValues(stats, 2, 1024L, 1024L); assertValues(stats, 3, 64L, 512L); } public void testRecordOverlapBuckets() throws Exception { Loading @@ -129,13 +129,11 @@ public class NetworkStatsHistoryTest extends TestCase { // should have two buckets, with some data mixed together assertEquals(2, stats.size()); assertEntry(stats, 0, 768L, 768L); assertEntry(stats, 1, 512L, 512L); assertValues(stats, 0, 768L, 768L); assertValues(stats, 1, 512L, 512L); } public void testRecordEntireGapIdentical() throws Exception { final long[] total = new long[2]; // first, create two separate histories far apart final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS); stats1.recordData(TEST_START, TEST_START + 2 * HOUR_IN_MILLIS, 2000L, 1000L); Loading @@ -150,19 +148,16 @@ public class NetworkStatsHistoryTest extends TestCase { stats.recordEntireHistory(stats2); // first verify that totals match up stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total); assertTotalEquals(total, 3000L, 1500L); assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 3000L, 1500L); // now inspect internal buckets assertEntry(stats, 0, 1000L, 500L); assertEntry(stats, 1, 1000L, 500L); assertEntry(stats, 2, 500L, 250L); assertEntry(stats, 3, 500L, 250L); assertValues(stats, 0, 1000L, 500L); assertValues(stats, 1, 1000L, 500L); assertValues(stats, 2, 500L, 250L); assertValues(stats, 3, 500L, 250L); } public void testRecordEntireOverlapVaryingBuckets() throws Exception { final long[] total = new long[2]; // create history just over hour bucket boundary final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS); stats1.recordData(TEST_START, TEST_START + MINUTE_IN_MILLIS * 60, 600L, 600L); Loading @@ -177,17 +172,16 @@ public class NetworkStatsHistoryTest extends TestCase { stats.recordEntireHistory(stats2); // first verify that totals match up stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total); assertTotalEquals(total, 650L, 650L); assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L); // now inspect internal buckets assertEntry(stats, 0, 10L, 10L); assertEntry(stats, 1, 20L, 20L); assertEntry(stats, 2, 20L, 20L); assertEntry(stats, 3, 20L, 20L); assertEntry(stats, 4, 20L, 20L); assertEntry(stats, 5, 20L, 20L); assertEntry(stats, 6, 10L, 10L); assertValues(stats, 0, 10L, 10L); assertValues(stats, 1, 20L, 20L); assertValues(stats, 2, 20L, 20L); assertValues(stats, 3, 20L, 20L); assertValues(stats, 4, 20L, 20L); assertValues(stats, 5, 20L, 20L); assertValues(stats, 6, 10L, 10L); // now combine using 15min buckets stats = new NetworkStatsHistory(HOUR_IN_MILLIS / 4); Loading @@ -195,14 +189,13 @@ public class NetworkStatsHistoryTest extends TestCase { stats.recordEntireHistory(stats2); // first verify that totals match up stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total); assertTotalEquals(total, 650L, 650L); assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L); // and inspect buckets assertEntry(stats, 0, 200L, 200L); assertEntry(stats, 1, 150L, 150L); assertEntry(stats, 2, 150L, 150L); assertEntry(stats, 3, 150L, 150L); assertValues(stats, 0, 200L, 200L); assertValues(stats, 1, 150L, 150L); assertValues(stats, 2, 150L, 150L); assertValues(stats, 3, 150L, 150L); } public void testRemove() throws Exception { Loading Loading @@ -241,27 +234,20 @@ public class NetworkStatsHistoryTest extends TestCase { // record uniform data across day stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 2400L, 4800L); final long[] total = new long[2]; // verify that total outside range is 0 stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, total); assertTotalEquals(total, 0, 0); assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, 0L, 0L); // verify total in first hour stats.getTotalData(TEST_START, TEST_START + HOUR_IN_MILLIS, total); assertTotalEquals(total, 100, 200); assertValues(stats, TEST_START, TEST_START + HOUR_IN_MILLIS, 100L, 200L); // verify total across 1.5 hours stats.getTotalData(TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), total); assertTotalEquals(total, 150, 300); assertValues(stats, TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), 150L, 300L); // verify total beyond end stats.getTotalData(TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, total); assertTotalEquals(total, 100, 200); assertValues(stats, TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, 100L, 200L); // verify everything total stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total); assertTotalEquals(total, 2400, 4800); assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 2400L, 4800L); } Loading Loading @@ -302,16 +288,18 @@ public class NetworkStatsHistoryTest extends TestCase { } } private static void assertTotalEquals(long[] total, long rxBytes, long txBytes) { assertEquals("unexpected rxBytes", rxBytes, total[0]); assertEquals("unexpected txBytes", txBytes, total[1]); } private static void assertEntry( private static void assertValues( NetworkStatsHistory stats, int index, long rxBytes, long txBytes) { final NetworkStatsHistory.Entry entry = stats.getValues(index, null); assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); assertEquals("unexpected txBytes", txBytes, entry.txBytes); } private static void assertValues( NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) { final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null); assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); assertEquals("unexpected txBytes", txBytes, entry.txBytes); } } services/java/com/android/server/net/NetworkStatsService.java +15 −8 Original line number Diff line number Diff line Loading @@ -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); } Loading @@ -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)) { Loading @@ -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); Loading Loading @@ -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); } } Loading services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +18 −20 Original line number Diff line number Diff line Loading @@ -264,7 +264,6 @@ public class NetworkStatsServiceTest extends AndroidTestCase { public void testStatsBucketResize() throws Exception { long elapsedRealtime = 0; NetworkStatsHistory history = null; long[] total = null; assertStatsFilesExist(false); Loading Loading @@ -292,9 +291,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { // verify service recorded history history = mService.getHistoryForNetwork(new NetworkTemplate(MATCH_WIFI, null)); total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); assertEquals(512L, total[0]); assertEquals(512L, total[1]); assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 512L); assertEquals(HOUR_IN_MILLIS, history.getBucketDuration()); assertEquals(2, history.size()); verifyAndReset(); Loading @@ -311,9 +308,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { // verify identical stats, but spread across 4 buckets now history = mService.getHistoryForNetwork(new NetworkTemplate(MATCH_WIFI, null)); total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); assertEquals(512L, total[0]); assertEquals(512L, total[1]); assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 512L); assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration()); assertEquals(4, history.size()); verifyAndReset(); Loading Loading @@ -575,32 +570,28 @@ public class NetworkStatsServiceTest extends AndroidTestCase { NetworkStats stats = mService.getSummaryForAllUid( sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true); assertEquals(3, stats.size()); assertEntry(stats, 0, IFACE_ALL, UID_RED, TAG_NONE, 50L, 5L, 50L, 5L); assertEntry(stats, 1, IFACE_ALL, UID_RED, 0xF00D, 10L, 1L, 10L, 1L); assertEntry(stats, 2, IFACE_ALL, UID_BLUE, TAG_NONE, 2048L, 16L, 1024L, 8L); assertValues(stats, 0, IFACE_ALL, UID_RED, TAG_NONE, 50L, 5L, 50L, 5L); assertValues(stats, 1, IFACE_ALL, UID_RED, 0xF00D, 10L, 1L, 10L, 1L); assertValues(stats, 2, IFACE_ALL, UID_BLUE, TAG_NONE, 2048L, 16L, 1024L, 8L); // now verify that recent history only contains one uid final long currentTime = TEST_START + elapsedRealtime; stats = mService.getSummaryForAllUid( sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true); assertEquals(1, stats.size()); assertEntry(stats, 0, IFACE_ALL, UID_BLUE, TAG_NONE, 1024L, 8L, 512L, 4L); assertValues(stats, 0, IFACE_ALL, UID_BLUE, TAG_NONE, 1024L, 8L, 512L, 4L); verifyAndReset(); } private void assertNetworkTotal(NetworkTemplate template, long rx, long tx) { private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long txBytes) { final NetworkStatsHistory history = mService.getHistoryForNetwork(template); final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); assertEquals(rx, total[0]); assertEquals(tx, total[1]); assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, txBytes); } private void assertUidTotal(NetworkTemplate template, int uid, long rx, long tx) { private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long txBytes) { final NetworkStatsHistory history = mService.getHistoryForUid(template, uid, TAG_NONE); final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); assertEquals(rx, total[0]); assertEquals(tx, total[1]); assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, txBytes); } private void expectSystemReady() throws Exception { Loading Loading @@ -660,7 +651,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { } } private static void assertEntry(NetworkStats stats, int i, String iface, int uid, int tag, private static void assertValues(NetworkStats stats, int i, String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets) { final NetworkStats.Entry entry = stats.getValues(i, null); assertEquals(iface, entry.iface); Loading @@ -673,6 +664,13 @@ public class NetworkStatsServiceTest extends AndroidTestCase { // assertEquals(txPackets, entry.txPackets); } private static void assertValues( NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) { final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null); assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); assertEquals("unexpected txBytes", txBytes, entry.txBytes); } private static NetworkState buildWifiState() { final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null); info.setDetailedState(DetailedState.CONNECTED, null, null); Loading Loading
core/java/android/net/NetworkStatsHistory.java +39 −12 Original line number Diff line number Diff line Loading @@ -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. */ Loading Loading @@ -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]; Loading @@ -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; } /** Loading
core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java +45 −57 Original line number Diff line number Diff line Loading @@ -55,7 +55,7 @@ public class NetworkStatsHistoryTest extends TestCase { stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 1024L, 2048L); assertEquals(1, stats.size()); assertEntry(stats, 0, 1024L, 2048L); assertValues(stats, 0, 1024L, 2048L); } public void testRecordEqualBuckets() throws Exception { Loading @@ -67,8 +67,8 @@ public class NetworkStatsHistoryTest extends TestCase { stats.recordData(recordStart, recordStart + bucketDuration, 1024L, 128L); assertEquals(2, stats.size()); assertEntry(stats, 0, 512L, 64L); assertEntry(stats, 1, 512L, 64L); assertValues(stats, 0, 512L, 64L); assertValues(stats, 1, 512L, 64L); } public void testRecordTouchingBuckets() throws Exception { Loading @@ -83,11 +83,11 @@ public class NetworkStatsHistoryTest extends TestCase { assertEquals(3, stats.size()); // first bucket should have (1/20 of value) assertEntry(stats, 0, 50L, 250L); assertValues(stats, 0, 50L, 250L); // second bucket should have (15/20 of value) assertEntry(stats, 1, 750L, 3750L); assertValues(stats, 1, 750L, 3750L); // final bucket should have (4/20 of value) assertEntry(stats, 2, 200L, 1000L); assertValues(stats, 2, 200L, 1000L); } public void testRecordGapBuckets() throws Exception { Loading @@ -102,8 +102,8 @@ public class NetworkStatsHistoryTest extends TestCase { // we should have two buckets, far apart from each other assertEquals(2, stats.size()); assertEntry(stats, 0, 128L, 256L); assertEntry(stats, 1, 64L, 512L); assertValues(stats, 0, 128L, 256L); assertValues(stats, 1, 64L, 512L); // now record something in middle, spread across two buckets final long middleStart = TEST_START + DAY_IN_MILLIS; Loading @@ -112,10 +112,10 @@ public class NetworkStatsHistoryTest extends TestCase { // now should have four buckets, with new record in middle two buckets assertEquals(4, stats.size()); assertEntry(stats, 0, 128L, 256L); assertEntry(stats, 1, 1024L, 1024L); assertEntry(stats, 2, 1024L, 1024L); assertEntry(stats, 3, 64L, 512L); assertValues(stats, 0, 128L, 256L); assertValues(stats, 1, 1024L, 1024L); assertValues(stats, 2, 1024L, 1024L); assertValues(stats, 3, 64L, 512L); } public void testRecordOverlapBuckets() throws Exception { Loading @@ -129,13 +129,11 @@ public class NetworkStatsHistoryTest extends TestCase { // should have two buckets, with some data mixed together assertEquals(2, stats.size()); assertEntry(stats, 0, 768L, 768L); assertEntry(stats, 1, 512L, 512L); assertValues(stats, 0, 768L, 768L); assertValues(stats, 1, 512L, 512L); } public void testRecordEntireGapIdentical() throws Exception { final long[] total = new long[2]; // first, create two separate histories far apart final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS); stats1.recordData(TEST_START, TEST_START + 2 * HOUR_IN_MILLIS, 2000L, 1000L); Loading @@ -150,19 +148,16 @@ public class NetworkStatsHistoryTest extends TestCase { stats.recordEntireHistory(stats2); // first verify that totals match up stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total); assertTotalEquals(total, 3000L, 1500L); assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 3000L, 1500L); // now inspect internal buckets assertEntry(stats, 0, 1000L, 500L); assertEntry(stats, 1, 1000L, 500L); assertEntry(stats, 2, 500L, 250L); assertEntry(stats, 3, 500L, 250L); assertValues(stats, 0, 1000L, 500L); assertValues(stats, 1, 1000L, 500L); assertValues(stats, 2, 500L, 250L); assertValues(stats, 3, 500L, 250L); } public void testRecordEntireOverlapVaryingBuckets() throws Exception { final long[] total = new long[2]; // create history just over hour bucket boundary final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS); stats1.recordData(TEST_START, TEST_START + MINUTE_IN_MILLIS * 60, 600L, 600L); Loading @@ -177,17 +172,16 @@ public class NetworkStatsHistoryTest extends TestCase { stats.recordEntireHistory(stats2); // first verify that totals match up stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total); assertTotalEquals(total, 650L, 650L); assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L); // now inspect internal buckets assertEntry(stats, 0, 10L, 10L); assertEntry(stats, 1, 20L, 20L); assertEntry(stats, 2, 20L, 20L); assertEntry(stats, 3, 20L, 20L); assertEntry(stats, 4, 20L, 20L); assertEntry(stats, 5, 20L, 20L); assertEntry(stats, 6, 10L, 10L); assertValues(stats, 0, 10L, 10L); assertValues(stats, 1, 20L, 20L); assertValues(stats, 2, 20L, 20L); assertValues(stats, 3, 20L, 20L); assertValues(stats, 4, 20L, 20L); assertValues(stats, 5, 20L, 20L); assertValues(stats, 6, 10L, 10L); // now combine using 15min buckets stats = new NetworkStatsHistory(HOUR_IN_MILLIS / 4); Loading @@ -195,14 +189,13 @@ public class NetworkStatsHistoryTest extends TestCase { stats.recordEntireHistory(stats2); // first verify that totals match up stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total); assertTotalEquals(total, 650L, 650L); assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L); // and inspect buckets assertEntry(stats, 0, 200L, 200L); assertEntry(stats, 1, 150L, 150L); assertEntry(stats, 2, 150L, 150L); assertEntry(stats, 3, 150L, 150L); assertValues(stats, 0, 200L, 200L); assertValues(stats, 1, 150L, 150L); assertValues(stats, 2, 150L, 150L); assertValues(stats, 3, 150L, 150L); } public void testRemove() throws Exception { Loading Loading @@ -241,27 +234,20 @@ public class NetworkStatsHistoryTest extends TestCase { // record uniform data across day stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 2400L, 4800L); final long[] total = new long[2]; // verify that total outside range is 0 stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, total); assertTotalEquals(total, 0, 0); assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, 0L, 0L); // verify total in first hour stats.getTotalData(TEST_START, TEST_START + HOUR_IN_MILLIS, total); assertTotalEquals(total, 100, 200); assertValues(stats, TEST_START, TEST_START + HOUR_IN_MILLIS, 100L, 200L); // verify total across 1.5 hours stats.getTotalData(TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), total); assertTotalEquals(total, 150, 300); assertValues(stats, TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), 150L, 300L); // verify total beyond end stats.getTotalData(TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, total); assertTotalEquals(total, 100, 200); assertValues(stats, TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, 100L, 200L); // verify everything total stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total); assertTotalEquals(total, 2400, 4800); assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 2400L, 4800L); } Loading Loading @@ -302,16 +288,18 @@ public class NetworkStatsHistoryTest extends TestCase { } } private static void assertTotalEquals(long[] total, long rxBytes, long txBytes) { assertEquals("unexpected rxBytes", rxBytes, total[0]); assertEquals("unexpected txBytes", txBytes, total[1]); } private static void assertEntry( private static void assertValues( NetworkStatsHistory stats, int index, long rxBytes, long txBytes) { final NetworkStatsHistory.Entry entry = stats.getValues(index, null); assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); assertEquals("unexpected txBytes", txBytes, entry.txBytes); } private static void assertValues( NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) { final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null); assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); assertEquals("unexpected txBytes", txBytes, entry.txBytes); } }
services/java/com/android/server/net/NetworkStatsService.java +15 −8 Original line number Diff line number Diff line Loading @@ -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); } Loading @@ -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)) { Loading @@ -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); Loading Loading @@ -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); } } Loading
services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +18 −20 Original line number Diff line number Diff line Loading @@ -264,7 +264,6 @@ public class NetworkStatsServiceTest extends AndroidTestCase { public void testStatsBucketResize() throws Exception { long elapsedRealtime = 0; NetworkStatsHistory history = null; long[] total = null; assertStatsFilesExist(false); Loading Loading @@ -292,9 +291,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { // verify service recorded history history = mService.getHistoryForNetwork(new NetworkTemplate(MATCH_WIFI, null)); total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); assertEquals(512L, total[0]); assertEquals(512L, total[1]); assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 512L); assertEquals(HOUR_IN_MILLIS, history.getBucketDuration()); assertEquals(2, history.size()); verifyAndReset(); Loading @@ -311,9 +308,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { // verify identical stats, but spread across 4 buckets now history = mService.getHistoryForNetwork(new NetworkTemplate(MATCH_WIFI, null)); total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); assertEquals(512L, total[0]); assertEquals(512L, total[1]); assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 512L); assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration()); assertEquals(4, history.size()); verifyAndReset(); Loading Loading @@ -575,32 +570,28 @@ public class NetworkStatsServiceTest extends AndroidTestCase { NetworkStats stats = mService.getSummaryForAllUid( sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true); assertEquals(3, stats.size()); assertEntry(stats, 0, IFACE_ALL, UID_RED, TAG_NONE, 50L, 5L, 50L, 5L); assertEntry(stats, 1, IFACE_ALL, UID_RED, 0xF00D, 10L, 1L, 10L, 1L); assertEntry(stats, 2, IFACE_ALL, UID_BLUE, TAG_NONE, 2048L, 16L, 1024L, 8L); assertValues(stats, 0, IFACE_ALL, UID_RED, TAG_NONE, 50L, 5L, 50L, 5L); assertValues(stats, 1, IFACE_ALL, UID_RED, 0xF00D, 10L, 1L, 10L, 1L); assertValues(stats, 2, IFACE_ALL, UID_BLUE, TAG_NONE, 2048L, 16L, 1024L, 8L); // now verify that recent history only contains one uid final long currentTime = TEST_START + elapsedRealtime; stats = mService.getSummaryForAllUid( sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true); assertEquals(1, stats.size()); assertEntry(stats, 0, IFACE_ALL, UID_BLUE, TAG_NONE, 1024L, 8L, 512L, 4L); assertValues(stats, 0, IFACE_ALL, UID_BLUE, TAG_NONE, 1024L, 8L, 512L, 4L); verifyAndReset(); } private void assertNetworkTotal(NetworkTemplate template, long rx, long tx) { private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long txBytes) { final NetworkStatsHistory history = mService.getHistoryForNetwork(template); final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); assertEquals(rx, total[0]); assertEquals(tx, total[1]); assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, txBytes); } private void assertUidTotal(NetworkTemplate template, int uid, long rx, long tx) { private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long txBytes) { final NetworkStatsHistory history = mService.getHistoryForUid(template, uid, TAG_NONE); final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); assertEquals(rx, total[0]); assertEquals(tx, total[1]); assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, txBytes); } private void expectSystemReady() throws Exception { Loading Loading @@ -660,7 +651,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { } } private static void assertEntry(NetworkStats stats, int i, String iface, int uid, int tag, private static void assertValues(NetworkStats stats, int i, String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets) { final NetworkStats.Entry entry = stats.getValues(i, null); assertEquals(iface, entry.iface); Loading @@ -673,6 +664,13 @@ public class NetworkStatsServiceTest extends AndroidTestCase { // assertEquals(txPackets, entry.txPackets); } private static void assertValues( NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) { final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null); assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); assertEquals("unexpected txBytes", txBytes, entry.txBytes); } private static NetworkState buildWifiState() { final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null); info.setDetailedState(DetailedState.CONNECTED, null, null); Loading