Persist UID stats, lazy loading, resize buckets. am: 837b4ebf7e
Original change: undetermined Change-Id: I73b9bc320762b57f31d957132b8740de77ec5923
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user