diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index 98463721b5..d6e4b8b701 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -18,10 +18,13 @@ package com.android.server; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.TEMPLATE_WIFI; 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.WEEK_IN_MILLIS; import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL; import static org.easymock.EasyMock.anyLong; import static org.easymock.EasyMock.createMock; @@ -47,6 +50,7 @@ import android.test.suitebuilder.annotation.LargeTest; import android.util.TrustedTime; import com.android.server.net.NetworkStatsService; +import com.android.server.net.NetworkStatsService.NetworkStatsSettings; import org.easymock.EasyMock; @@ -62,12 +66,16 @@ public class NetworkStatsServiceTest extends AndroidTestCase { private static final String TEST_IFACE = "test0"; private static final long TEST_START = 1194220800000L; + private static final int TEST_UID_1 = 1001; + private static final int TEST_UID_2 = 1002; + private BroadcastInterceptingContext mServiceContext; private File mStatsDir; private INetworkManagementService mNetManager; private IAlarmManager mAlarmManager; private TrustedTime mTime; + private NetworkStatsSettings mSettings; private IConnectivityManager mConnManager; private NetworkStatsService mService; @@ -82,12 +90,14 @@ public class NetworkStatsServiceTest extends AndroidTestCase { mNetManager = createMock(INetworkManagementService.class); mAlarmManager = createMock(IAlarmManager.class); mTime = createMock(TrustedTime.class); + mSettings = createMock(NetworkStatsSettings.class); mConnManager = createMock(IConnectivityManager.class); mService = new NetworkStatsService( - mServiceContext, mNetManager, mAlarmManager, mTime, mStatsDir); + mServiceContext, mNetManager, mAlarmManager, mTime, mStatsDir, mSettings); mService.bindConnectivityManager(mConnManager); + expectDefaultSettings(); expectSystemReady(); replay(); @@ -114,115 +124,93 @@ public class NetworkStatsServiceTest extends AndroidTestCase { super.tearDown(); } - private static NetworkState buildWifi() { - final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null); - info.setDetailedState(DetailedState.CONNECTED, null, null); - final LinkProperties prop = new LinkProperties(); - prop.setInterfaceName(TEST_IFACE); - return new NetworkState(info, prop, null); - } - - public void testHistoryForWifi() throws Exception { + public void testSummaryStatsWifi() throws Exception { long elapsedRealtime = 0; - NetworkState[] state = null; - NetworkStats stats = null; - NetworkStats detail = null; // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. - state = new NetworkState[] { buildWifi() }; - stats = new NetworkStats.Builder(elapsedRealtime, 0).build(); - detail = new NetworkStats.Builder(elapsedRealtime, 0).build(); - - expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); - expect(mNetManager.getNetworkStatsSummary()).andReturn(stats).atLeastOnce(); - expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce(); expectTime(TEST_START + elapsedRealtime); + expectDefaultSettings(); + expectNetworkState(buildWifiState()); + expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime)); replay(); mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); - verifyAndReset(); // verify service has empty history for wifi assertNetworkTotal(TEMPLATE_WIFI, 0L, 0L); + verifyAndReset(); // modify some number on wifi, and trigger poll event elapsedRealtime += HOUR_IN_MILLIS; - stats = new NetworkStats.Builder(elapsedRealtime, 1).addEntry( - TEST_IFACE, UID_ALL, 1024L, 2048L).build(); - - expect(mNetManager.getNetworkStatsSummary()).andReturn(stats).atLeastOnce(); - expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce(); expectTime(TEST_START + elapsedRealtime); + expectDefaultSettings(); + expectNetworkStatsSummary(new NetworkStats.Builder(elapsedRealtime, 1) + .addEntry(TEST_IFACE, UID_ALL, 1024L, 2048L).build()); + expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime)); replay(); mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - verifyAndReset(); // verify service recorded history assertNetworkTotal(TEMPLATE_WIFI, 1024L, 2048L); + verifyAndReset(); // and bump forward again, with counters going higher. this is // important, since polling should correctly subtract last snapshot. elapsedRealtime += DAY_IN_MILLIS; - stats = new NetworkStats.Builder(elapsedRealtime, 1).addEntry( - TEST_IFACE, UID_ALL, 4096L, 8192L).build(); - - expect(mNetManager.getNetworkStatsSummary()).andReturn(stats).atLeastOnce(); - expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce(); expectTime(TEST_START + elapsedRealtime); + expectDefaultSettings(); + expectNetworkStatsSummary(new NetworkStats.Builder(elapsedRealtime, 1) + .addEntry(TEST_IFACE, UID_ALL, 4096L, 8192L).build()); + expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime)); replay(); mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - verifyAndReset(); // verify service recorded history assertNetworkTotal(TEMPLATE_WIFI, 4096L, 8192L); + verifyAndReset(); + } - public void testHistoryForRebootPersist() throws Exception { + public void testStatsRebootPersist() throws Exception { long elapsedRealtime = 0; - NetworkState[] state = null; - NetworkStats stats = null; - NetworkStats detail = null; - - // assert that no stats file exists - final File statsFile = new File(mStatsDir, "netstats.bin"); - assertFalse(statsFile.exists()); + assertStatsFilesExist(false); // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. - state = new NetworkState[] { buildWifi() }; - stats = new NetworkStats.Builder(elapsedRealtime, 0).build(); - detail = new NetworkStats.Builder(elapsedRealtime, 0).build(); - - expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); - expect(mNetManager.getNetworkStatsSummary()).andReturn(stats).atLeastOnce(); - expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce(); expectTime(TEST_START + elapsedRealtime); + expectDefaultSettings(); + expectNetworkState(buildWifiState()); + expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime)); replay(); mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); - verifyAndReset(); // verify service has empty history for wifi assertNetworkTotal(TEMPLATE_WIFI, 0L, 0L); + verifyAndReset(); // modify some number on wifi, and trigger poll event elapsedRealtime += HOUR_IN_MILLIS; - stats = new NetworkStats.Builder(elapsedRealtime, 1).addEntry( - TEST_IFACE, UID_ALL, 1024L, 2048L).build(); - - expect(mNetManager.getNetworkStatsSummary()).andReturn(stats).atLeastOnce(); - expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce(); expectTime(TEST_START + elapsedRealtime); + expectDefaultSettings(); + expectNetworkStatsSummary(new NetworkStats.Builder(elapsedRealtime, 1) + .addEntry(TEST_IFACE, UID_ALL, 1024L, 2048L).build()); + // TODO: switch these stats to specific iface + expectNetworkStatsDetail(new NetworkStats.Builder(elapsedRealtime, 2) + .addEntry(IFACE_ALL, TEST_UID_1, 512L, 256L) + .addEntry(IFACE_ALL, TEST_UID_2, 128L, 128L).build()); replay(); mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - verifyAndReset(); // verify service recorded history assertNetworkTotal(TEMPLATE_WIFI, 1024L, 2048L); + assertUidTotal(TEST_UID_1, TEMPLATE_WIFI, 512L, 256L); + assertUidTotal(TEST_UID_2, TEMPLATE_WIFI, 128L, 128L); + verifyAndReset(); // graceful shutdown system, which should trigger persist of stats, and // clear any values in memory. @@ -230,18 +218,84 @@ public class NetworkStatsServiceTest extends AndroidTestCase { // talk with zombie service to assert stats have gone; and assert that // we persisted them to file. + expectDefaultSettings(); + replay(); assertNetworkTotal(TEMPLATE_WIFI, 0L, 0L); - assertTrue(statsFile.exists()); + verifyAndReset(); + + assertStatsFilesExist(true); // boot through serviceReady() again + expectDefaultSettings(); expectSystemReady(); replay(); mService.systemReady(); - verifyAndReset(); // after systemReady(), we should have historical stats loaded again assertNetworkTotal(TEMPLATE_WIFI, 1024L, 2048L); + assertUidTotal(TEST_UID_1, TEMPLATE_WIFI, 512L, 256L); + assertUidTotal(TEST_UID_2, TEMPLATE_WIFI, 128L, 128L); + verifyAndReset(); + + } + + public void testStatsBucketResize() throws Exception { + long elapsedRealtime = 0; + NetworkStatsHistory history = null; + long[] total = null; + + assertStatsFilesExist(false); + + // pretend that wifi network comes online; service should ask about full + // network state, and poll any existing interfaces before updating. + expectTime(TEST_START + elapsedRealtime); + expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS); + expectNetworkState(buildWifiState()); + expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime)); + + replay(); + mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); + verifyAndReset(); + + // modify some number on wifi, and trigger poll event + elapsedRealtime += 2 * HOUR_IN_MILLIS; + expectTime(TEST_START + elapsedRealtime); + expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS); + expectNetworkStatsSummary(new NetworkStats.Builder(elapsedRealtime, 1) + .addEntry(TEST_IFACE, UID_ALL, 512L, 512L).build()); + expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime)); + + replay(); + mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); + + // verify service recorded history + history = mService.getHistoryForNetwork(TEMPLATE_WIFI); + total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); + assertEquals(512L, total[0]); + assertEquals(512L, total[1]); + assertEquals(HOUR_IN_MILLIS, history.bucketDuration); + assertEquals(2, history.bucketCount); + verifyAndReset(); + + // now change bucket duration setting and trigger another poll with + // exact same values, which should resize existing buckets. + expectTime(TEST_START + elapsedRealtime); + expectSettings(0L, 30 * MINUTE_IN_MILLIS, WEEK_IN_MILLIS); + expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime)); + expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime)); + + replay(); + mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); + + // verify identical stats, but spread across 4 buckets now + history = mService.getHistoryForNetwork(TEMPLATE_WIFI); + total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); + assertEquals(512L, total[0]); + assertEquals(512L, total[1]); + assertEquals(30 * MINUTE_IN_MILLIS, history.bucketDuration); + assertEquals(4, history.bucketCount); + verifyAndReset(); } @@ -252,6 +306,13 @@ public class NetworkStatsServiceTest extends AndroidTestCase { assertEquals(tx, total[1]); } + private void assertUidTotal(int uid, int template, long rx, long tx) { + final NetworkStatsHistory history = mService.getHistoryForUid(uid, template); + final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); + assertEquals(rx, total[0]); + assertEquals(tx, total[1]); + } + private void expectSystemReady() throws Exception { mAlarmManager.remove(isA(PendingIntent.class)); expectLastCall().anyTimes(); @@ -261,7 +322,34 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectLastCall().atLeastOnce(); } - public void expectTime(long currentTime) throws Exception { + private void expectNetworkState(NetworkState... state) throws Exception { + expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); + } + + private void expectNetworkStatsSummary(NetworkStats summary) throws Exception { + expect(mNetManager.getNetworkStatsSummary()).andReturn(summary).atLeastOnce(); + } + + private void expectNetworkStatsDetail(NetworkStats detail) throws Exception { + expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce(); + } + + private void expectDefaultSettings() throws Exception { + expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS); + } + + private void expectSettings(long persistThreshold, long bucketDuration, long maxHistory) + throws Exception { + expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes(); + expect(mSettings.getPersistThreshold()).andReturn(persistThreshold).anyTimes(); + expect(mSettings.getNetworkBucketDuration()).andReturn(bucketDuration).anyTimes(); + expect(mSettings.getNetworkMaxHistory()).andReturn(maxHistory).anyTimes(); + expect(mSettings.getUidBucketDuration()).andReturn(bucketDuration).anyTimes(); + expect(mSettings.getUidMaxHistory()).andReturn(maxHistory).anyTimes(); + expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes(); + } + + private void expectTime(long currentTime) throws Exception { expect(mTime.forceRefresh()).andReturn(false).anyTimes(); expect(mTime.hasCache()).andReturn(true).anyTimes(); expect(mTime.currentTimeMillis()).andReturn(currentTime).anyTimes(); @@ -269,12 +357,36 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes(); } + private void assertStatsFilesExist(boolean exist) { + final File summaryFile = new File(mStatsDir, "netstats.bin"); + final File detailFile = new File(mStatsDir, "netstats_uid.bin"); + if (exist) { + assertTrue(summaryFile.exists()); + assertTrue(detailFile.exists()); + } else { + assertFalse(summaryFile.exists()); + assertFalse(detailFile.exists()); + } + } + + private static NetworkState buildWifiState() { + final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null); + info.setDetailedState(DetailedState.CONNECTED, null, null); + final LinkProperties prop = new LinkProperties(); + prop.setInterfaceName(TEST_IFACE); + return new NetworkState(info, prop, null); + } + + private static NetworkStats buildEmptyStats(long elapsedRealtime) { + return new NetworkStats.Builder(elapsedRealtime, 0).build(); + } + private void replay() { - EasyMock.replay(mNetManager, mAlarmManager, mTime, mConnManager); + EasyMock.replay(mNetManager, mAlarmManager, mTime, mSettings, mConnManager); } private void verifyAndReset() { - EasyMock.verify(mNetManager, mAlarmManager, mTime, mConnManager); - EasyMock.reset(mNetManager, mAlarmManager, mTime, mConnManager); + EasyMock.verify(mNetManager, mAlarmManager, mTime, mSettings, mConnManager); + EasyMock.reset(mNetManager, mAlarmManager, mTime, mSettings, mConnManager); } }