summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2011-06-11 17:25:42 -0700
committerJeff Sharkey <jsharkey@android.com>2011-06-11 17:55:56 -0700
commit39ebc2195ed16b9e955dd57f5c95212bb7b934b6 (patch)
tree9ddc7b44606238491b6adc14361c65136875f2fe
parent13010be779ba0ff2496709f15f862166d677b547 (diff)
downloadframeworks_base-39ebc2195ed16b9e955dd57f5c95212bb7b934b6.zip
frameworks_base-39ebc2195ed16b9e955dd57f5c95212bb7b934b6.tar.gz
frameworks_base-39ebc2195ed16b9e955dd57f5c95212bb7b934b6.tar.bz2
Persist UID stats, lazy loading, resize buckets.
Persisting detailed UID stats in separate "netstats_detail.bin" file to enable different schedules for summary and detail polling. Only load detailed UID history on demand, since it's not needed during boot. Add test to verify UID stats are persisted across simulated reboot. Move external settings into well-named interface, which is still backed by Settings.Secure. During periodic poll events, resize any history to match current bucket duration setting. Test to verify. Change-Id: I6366f3583a591f8ba859b0e5987daf8cafa4e95a
-rw-r--r--core/java/android/provider/Settings.java8
-rw-r--r--services/java/com/android/server/net/NetworkStatsService.java435
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java234
3 files changed, 475 insertions, 202 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6ab7738..1025b20 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3800,13 +3800,13 @@ public final class Settings {
/** {@hide} */
public static final String NETSTATS_PERSIST_THRESHOLD = "netstats_persist_threshold";
/** {@hide} */
- public static final String NETSTATS_SUMMARY_BUCKET_DURATION = "netstats_summary_bucket_duration";
+ public static final String NETSTATS_NETWORK_BUCKET_DURATION = "netstats_network_bucket_duration";
/** {@hide} */
- public static final String NETSTATS_SUMMARY_MAX_HISTORY = "netstats_summary_max_history";
+ public static final String NETSTATS_NETWORK_MAX_HISTORY = "netstats_network_max_history";
/** {@hide} */
- public static final String NETSTATS_DETAIL_BUCKET_DURATION = "netstats_detail_bucket_duration";
+ public static final String NETSTATS_UID_BUCKET_DURATION = "netstats_uid_bucket_duration";
/** {@hide} */
- public static final String NETSTATS_DETAIL_MAX_HISTORY = "netstats_detail_max_history";
+ public static final String NETSTATS_UID_MAX_HISTORY = "netstats_uid_max_history";
/**
* @hide
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 161c393..f5d01d6 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -23,12 +23,12 @@ import static android.Manifest.permission.SHUTDOWN;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.UID_ALL;
-import static android.provider.Settings.Secure.NETSTATS_DETAIL_BUCKET_DURATION;
-import static android.provider.Settings.Secure.NETSTATS_DETAIL_MAX_HISTORY;
+import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
+import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD;
import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL;
-import static android.provider.Settings.Secure.NETSTATS_SUMMARY_BUCKET_DURATION;
-import static android.provider.Settings.Secure.NETSTATS_SUMMARY_MAX_HISTORY;
+import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION;
+import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY;
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;
@@ -38,6 +38,7 @@ import android.app.AlarmManager;
import android.app.IAlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -88,6 +89,7 @@ import libcore.io.IoUtils;
public class NetworkStatsService extends INetworkStatsService.Stub {
private static final String TAG = "NetworkStats";
private static final boolean LOGD = true;
+ private static final boolean LOGV = false;
/** File header magic number: "ANET" */
private static final int FILE_MAGIC = 0x414E4554;
@@ -97,6 +99,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private final INetworkManagementService mNetworkManager;
private final IAlarmManager mAlarmManager;
private final TrustedTime mTime;
+ private final NetworkStatsSettings mSettings;
private IConnectivityManager mConnManager;
@@ -112,22 +115,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES;
private static final long GB_IN_BYTES = 1024 * MB_IN_BYTES;
- private LongSecureSetting mPollInterval = new LongSecureSetting(
- NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS);
- private LongSecureSetting mPersistThreshold = new LongSecureSetting(
- NETSTATS_PERSIST_THRESHOLD, 16 * KB_IN_BYTES);
-
- // TODO: adjust these timings for production builds
- private LongSecureSetting mSummaryBucketDuration = new LongSecureSetting(
- NETSTATS_SUMMARY_BUCKET_DURATION, 1 * HOUR_IN_MILLIS);
- private LongSecureSetting mSummaryMaxHistory = new LongSecureSetting(
- NETSTATS_SUMMARY_MAX_HISTORY, 90 * DAY_IN_MILLIS);
- private LongSecureSetting mDetailBucketDuration = new LongSecureSetting(
- NETSTATS_DETAIL_BUCKET_DURATION, 2 * HOUR_IN_MILLIS);
- private LongSecureSetting mDetailMaxHistory = new LongSecureSetting(
- NETSTATS_DETAIL_MAX_HISTORY, 90 * DAY_IN_MILLIS);
-
- private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
+ /**
+ * Settings that can be changed externally.
+ */
+ public interface NetworkStatsSettings {
+ public long getPollInterval();
+ public long getPersistThreshold();
+ public long getNetworkBucketDuration();
+ public long getNetworkMaxHistory();
+ public long getUidBucketDuration();
+ public long getUidMaxHistory();
+ public long getTimeCacheMaxAge();
+ }
private final Object mStatsLock = new Object();
@@ -135,19 +134,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private HashMap<String, InterfaceIdentity> mActiveIface = Maps.newHashMap();
/** Set of historical stats for known ifaces. */
- private HashMap<InterfaceIdentity, NetworkStatsHistory> mSummaryStats = Maps.newHashMap();
+ private HashMap<InterfaceIdentity, NetworkStatsHistory> mNetworkStats = Maps.newHashMap();
/** Set of historical stats for known UIDs. */
- private SparseArray<NetworkStatsHistory> mDetailStats = new SparseArray<NetworkStatsHistory>();
+ private SparseArray<NetworkStatsHistory> mUidStats = new SparseArray<NetworkStatsHistory>();
+
+ /** Flag if {@link #mUidStats} have been loaded from disk. */
+ private boolean mUidStatsLoaded = false;
- private NetworkStats mLastSummaryPoll;
- private NetworkStats mLastSummaryPersist;
+ private NetworkStats mLastNetworkPoll;
+ private NetworkStats mLastNetworkPersist;
- private NetworkStats mLastDetailPoll;
+ private NetworkStats mLastUidPoll;
private final HandlerThread mHandlerThread;
private final Handler mHandler;
- private final AtomicFile mSummaryFile;
+ private final AtomicFile mNetworkFile;
+ private final AtomicFile mUidFile;
// TODO: collect detailed uid stats, storing tag-granularity data until next
// dropbox, and uid summary for a specific bucket count.
@@ -157,7 +160,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public NetworkStatsService(
Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) {
// TODO: move to using cached NtpTrustedTime
- this(context, networkManager, alarmManager, new NtpTrustedTime(), getSystemDir());
+ this(context, networkManager, alarmManager, new NtpTrustedTime(), getSystemDir(),
+ new DefaultNetworkStatsSettings(context));
}
private static File getSystemDir() {
@@ -165,17 +169,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
public NetworkStatsService(Context context, INetworkManagementService networkManager,
- IAlarmManager alarmManager, TrustedTime time, File systemDir) {
+ IAlarmManager alarmManager, TrustedTime time, File systemDir,
+ NetworkStatsSettings settings) {
mContext = checkNotNull(context, "missing Context");
mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService");
mAlarmManager = checkNotNull(alarmManager, "missing IAlarmManager");
mTime = checkNotNull(time, "missing TrustedTime");
+ mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
- mSummaryFile = new AtomicFile(new File(systemDir, "netstats.bin"));
+ mNetworkFile = new AtomicFile(new File(systemDir, "netstats.bin"));
+ mUidFile = new AtomicFile(new File(systemDir, "netstats_uid.bin"));
}
public void bindConnectivityManager(IConnectivityManager connManager) {
@@ -184,8 +191,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public void systemReady() {
synchronized (mStatsLock) {
- // read historical stats from disk
- readStatsLocked();
+ // read historical network stats from disk, since policy service
+ // might need them right away. we delay loading detailed UID stats
+ // until actually needed.
+ readNetworkStatsLocked();
}
// watch for network interfaces to be claimed
@@ -214,14 +223,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mContext.unregisterReceiver(mPollReceiver);
mContext.unregisterReceiver(mShutdownReceiver);
- writeStatsLocked();
- mSummaryStats.clear();
- mDetailStats.clear();
+ writeNetworkStatsLocked();
+ writeUidStatsLocked();
+ mNetworkStats.clear();
+ mUidStats.clear();
+ mUidStatsLoaded = false;
}
/**
* Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and
- * reschedule based on current {@link #mPollInterval} value.
+ * reschedule based on current {@link NetworkStatsSettings#getPollInterval()}.
*/
private void registerPollAlarmLocked() throws RemoteException {
if (mPollIntent != null) {
@@ -232,8 +243,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0);
final long currentRealtime = SystemClock.elapsedRealtime();
- mAlarmManager.setInexactRepeating(
- AlarmManager.ELAPSED_REALTIME, currentRealtime, mPollInterval.get(), mPollIntent);
+ mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime,
+ mSettings.getPollInterval(), mPollIntent);
}
@Override
@@ -244,9 +255,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// combine all interfaces that match template
final String subscriberId = getActiveSubscriberId();
final NetworkStatsHistory combined = new NetworkStatsHistory(
- mSummaryBucketDuration.get());
- for (InterfaceIdentity ident : mSummaryStats.keySet()) {
- final NetworkStatsHistory history = mSummaryStats.get(ident);
+ mSettings.getNetworkBucketDuration());
+ for (InterfaceIdentity ident : mNetworkStats.keySet()) {
+ final NetworkStatsHistory history = mNetworkStats.get(ident);
if (ident.matchesTemplate(networkTemplate, subscriberId)) {
combined.recordEntireHistory(history);
}
@@ -259,8 +270,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate) {
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
- // TODO: return history for requested uid
- return null;
+ synchronized (mStatsLock) {
+ // TODO: combine based on template, if we store that granularity
+ ensureUidStatsLoadedLocked();
+ return mUidStats.get(uid);
+ }
}
@Override
@@ -274,8 +288,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
long[] networkTotal = new long[2];
// combine total from all interfaces that match template
- for (InterfaceIdentity ident : mSummaryStats.keySet()) {
- final NetworkStatsHistory history = mSummaryStats.get(ident);
+ for (InterfaceIdentity ident : mNetworkStats.keySet()) {
+ final NetworkStatsHistory history = mNetworkStats.get(ident);
if (ident.matchesTemplate(networkTemplate, subscriberId)) {
networkTotal = history.getTotalData(start, end, networkTotal);
rx += networkTotal[0];
@@ -296,13 +310,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// TODO: apply networktemplate once granular uid stats are stored.
synchronized (mStatsLock) {
- final int size = mDetailStats.size();
+ ensureUidStatsLoadedLocked();
+
+ final int size = mUidStats.size();
final NetworkStats.Builder stats = new NetworkStats.Builder(end - start, size);
long[] total = new long[2];
for (int i = 0; i < size; i++) {
- final int uid = mDetailStats.keyAt(i);
- final NetworkStatsHistory history = mDetailStats.valueAt(i);
+ final int uid = mUidStats.keyAt(i);
+ final NetworkStatsHistory history = mUidStats.valueAt(i);
total = history.getTotalData(start, end, total);
stats.addEntry(IFACE_ALL, uid, total[0], total[1]);
}
@@ -333,7 +349,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// permission above.
synchronized (mStatsLock) {
// TODO: acquire wakelock while performing poll
- performPollLocked();
+ performPollLocked(true);
}
}
};
@@ -355,13 +371,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
* {@link InterfaceIdentity}.
*/
private void updateIfacesLocked() {
- if (LOGD) Slog.v(TAG, "updateIfacesLocked()");
+ if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
// take one last stats snapshot before updating iface mapping. this
// isn't perfect, since the kernel may already be counting traffic from
// the updated network.
- // TODO: verify that we only poll summary stats, not uid details
- performPollLocked();
+ performPollLocked(false);
final NetworkState[] states;
try {
@@ -384,11 +399,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
}
- private void performPollLocked() {
- if (LOGD) Slog.v(TAG, "performPollLocked()");
+ /**
+ * Periodic poll operation, reading current statistics and recording into
+ * {@link NetworkStatsHistory}.
+ *
+ * @param detailedPoll Indicate if detailed UID stats should be collected
+ * during this poll operation.
+ */
+ private void performPollLocked(boolean detailedPoll) {
+ if (LOGV) Slog.v(TAG, "performPollLocked()");
// try refreshing time source when stale
- if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
+ if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) {
mTime.forceRefresh();
}
@@ -396,42 +418,45 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
: System.currentTimeMillis();
- final NetworkStats summary;
- final NetworkStats detail;
+ final NetworkStats networkStats;
+ final NetworkStats uidStats;
try {
- summary = mNetworkManager.getNetworkStatsSummary();
- detail = mNetworkManager.getNetworkStatsDetail();
+ networkStats = mNetworkManager.getNetworkStatsSummary();
+ uidStats = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null;
} catch (RemoteException e) {
Slog.w(TAG, "problem reading network stats");
return;
}
- performSummaryPollLocked(summary, currentTime);
- performDetailPollLocked(detail, currentTime);
+ performNetworkPollLocked(networkStats, currentTime);
+ if (detailedPoll) {
+ performUidPollLocked(uidStats, currentTime);
+ }
// decide if enough has changed to trigger persist
- final NetworkStats persistDelta = computeStatsDelta(mLastSummaryPersist, summary);
- final long persistThreshold = mPersistThreshold.get();
+ final NetworkStats persistDelta = computeStatsDelta(mLastNetworkPersist, networkStats);
+ final long persistThreshold = mSettings.getPersistThreshold();
for (String iface : persistDelta.getUniqueIfaces()) {
final int index = persistDelta.findIndex(iface, UID_ALL);
if (persistDelta.rx[index] > persistThreshold
|| persistDelta.tx[index] > persistThreshold) {
- writeStatsLocked();
- mLastSummaryPersist = summary;
+ writeNetworkStatsLocked();
+ writeUidStatsLocked();
+ mLastNetworkPersist = networkStats;
break;
}
}
}
/**
- * Update {@link #mSummaryStats} historical usage.
+ * Update {@link #mNetworkStats} historical usage.
*/
- private void performSummaryPollLocked(NetworkStats summary, long currentTime) {
+ private void performNetworkPollLocked(NetworkStats networkStats, long currentTime) {
final ArrayList<String> unknownIface = Lists.newArrayList();
- final NetworkStats delta = computeStatsDelta(mLastSummaryPoll, summary);
+ final NetworkStats delta = computeStatsDelta(mLastNetworkPoll, networkStats);
final long timeStart = currentTime - delta.elapsedRealtime;
- final long maxHistory = mSummaryMaxHistory.get();
+ final long maxHistory = mSettings.getNetworkMaxHistory();
for (String iface : delta.getUniqueIfaces()) {
final InterfaceIdentity ident = mActiveIface.get(iface);
if (ident == null) {
@@ -443,11 +468,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final long rx = delta.rx[index];
final long tx = delta.tx[index];
- final NetworkStatsHistory history = findOrCreateSummaryLocked(ident);
+ final NetworkStatsHistory history = findOrCreateNetworkLocked(ident);
history.recordData(timeStart, currentTime, rx, tx);
history.removeBucketsBefore(currentTime - maxHistory);
}
- mLastSummaryPoll = summary;
+ mLastNetworkPoll = networkStats;
if (LOGD && unknownIface.size() > 0) {
Slog.w(TAG, "unknown interfaces " + unknownIface.toString() + ", ignoring those stats");
@@ -455,40 +480,69 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
/**
- * Update {@link #mDetailStats} historical usage.
+ * Update {@link #mUidStats} historical usage.
*/
- private void performDetailPollLocked(NetworkStats detail, long currentTime) {
- final NetworkStats delta = computeStatsDelta(mLastDetailPoll, detail);
+ private void performUidPollLocked(NetworkStats uidStats, long currentTime) {
+ ensureUidStatsLoadedLocked();
+
+ final NetworkStats delta = computeStatsDelta(mLastUidPoll, uidStats);
final long timeStart = currentTime - delta.elapsedRealtime;
- final long maxHistory = mDetailMaxHistory.get();
+ final long maxHistory = mSettings.getUidMaxHistory();
for (int uid : delta.getUniqueUids()) {
+ // TODO: traverse all ifaces once surfaced in stats
final int index = delta.findIndex(IFACE_ALL, uid);
- final long rx = delta.rx[index];
- final long tx = delta.tx[index];
+ if (index != -1) {
+ final long rx = delta.rx[index];
+ final long tx = delta.tx[index];
- final NetworkStatsHistory history = findOrCreateDetailLocked(uid);
- history.recordData(timeStart, currentTime, rx, tx);
- history.removeBucketsBefore(currentTime - maxHistory);
+ final NetworkStatsHistory history = findOrCreateUidLocked(uid);
+ history.recordData(timeStart, currentTime, rx, tx);
+ history.removeBucketsBefore(currentTime - maxHistory);
+ }
}
- mLastDetailPoll = detail;
+ mLastUidPoll = uidStats;
}
- private NetworkStatsHistory findOrCreateSummaryLocked(InterfaceIdentity ident) {
- NetworkStatsHistory stats = mSummaryStats.get(ident);
- if (stats == null) {
- stats = new NetworkStatsHistory(mSummaryBucketDuration.get());
- mSummaryStats.put(ident, stats);
+ private NetworkStatsHistory findOrCreateNetworkLocked(InterfaceIdentity ident) {
+ final long bucketDuration = mSettings.getNetworkBucketDuration();
+ final NetworkStatsHistory existing = mNetworkStats.get(ident);
+
+ // update when no existing, or when bucket duration changed
+ NetworkStatsHistory updated = null;
+ if (existing == null) {
+ updated = new NetworkStatsHistory(bucketDuration);
+ } else if (existing.bucketDuration != bucketDuration) {
+ updated = new NetworkStatsHistory(bucketDuration);
+ updated.recordEntireHistory(existing);
+ }
+
+ if (updated != null) {
+ mNetworkStats.put(ident, updated);
+ return updated;
+ } else {
+ return existing;
}
- return stats;
}
- private NetworkStatsHistory findOrCreateDetailLocked(int uid) {
- NetworkStatsHistory stats = mDetailStats.get(uid);
- if (stats == null) {
- stats = new NetworkStatsHistory(mDetailBucketDuration.get());
- mDetailStats.put(uid, stats);
+ private NetworkStatsHistory findOrCreateUidLocked(int uid) {
+ final long bucketDuration = mSettings.getUidBucketDuration();
+ final NetworkStatsHistory existing = mUidStats.get(uid);
+
+ // update when no existing, or when bucket duration changed
+ NetworkStatsHistory updated = null;
+ if (existing == null) {
+ updated = new NetworkStatsHistory(bucketDuration);
+ } else if (existing.bucketDuration != bucketDuration) {
+ updated = new NetworkStatsHistory(bucketDuration);
+ updated.recordEntireHistory(existing);
+ }
+
+ if (updated != null) {
+ mUidStats.put(uid, updated);
+ return updated;
+ } else {
+ return existing;
}
- return stats;
}
private InterfaceIdentity findOrCreateInterfaceLocked(String iface) {
@@ -500,15 +554,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return ident;
}
- private void readStatsLocked() {
- if (LOGD) Slog.v(TAG, "readStatsLocked()");
+ private void readNetworkStatsLocked() {
+ if (LOGV) Slog.v(TAG, "readNetworkStatsLocked()");
// clear any existing stats and read from disk
- mSummaryStats.clear();
+ mNetworkStats.clear();
FileInputStream fis = null;
try {
- fis = mSummaryFile.openRead();
+ fis = mNetworkFile.openRead();
final DataInputStream in = new DataInputStream(fis);
// verify file magic header intact
@@ -521,13 +575,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
switch (version) {
case VERSION_CURRENT: {
// file format is pairs of interfaces and stats:
- // summary := size *(InterfaceIdentity NetworkStatsHistory)
+ // network := size *(InterfaceIdentity NetworkStatsHistory)
final int size = in.readInt();
for (int i = 0; i < size; i++) {
final InterfaceIdentity ident = new InterfaceIdentity(in);
final NetworkStatsHistory history = new NetworkStatsHistory(in);
- mSummaryStats.put(ident, history);
+
+ mNetworkStats.put(ident, history);
}
break;
}
@@ -544,30 +599,113 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
}
- private void writeStatsLocked() {
- if (LOGD) Slog.v(TAG, "writeStatsLocked()");
+ private void ensureUidStatsLoadedLocked() {
+ if (!mUidStatsLoaded) {
+ readUidStatsLocked();
+ mUidStatsLoaded = true;
+ }
+ }
+
+ private void readUidStatsLocked() {
+ if (LOGV) Slog.v(TAG, "readUidStatsLocked()");
+
+ // clear any existing stats and read from disk
+ mUidStats.clear();
+
+ FileInputStream fis = null;
+ try {
+ fis = mUidFile.openRead();
+ final DataInputStream in = new DataInputStream(fis);
+
+ // verify file magic header intact
+ final int magic = in.readInt();
+ if (magic != FILE_MAGIC) {
+ throw new ProtocolException("unexpected magic: " + magic);
+ }
+
+ final int version = in.readInt();
+ switch (version) {
+ case VERSION_CURRENT: {
+ // file format is pairs of UIDs and stats:
+ // uid := size *(UID NetworkStatsHistory)
+
+ final int size = in.readInt();
+ for (int i = 0; i < size; i++) {
+ final int uid = in.readInt();
+ final NetworkStatsHistory history = new NetworkStatsHistory(in);
+
+ mUidStats.put(uid, history);
+ }
+ break;
+ }
+ default: {
+ throw new ProtocolException("unexpected version: " + version);
+ }
+ }
+ } catch (FileNotFoundException e) {
+ // missing stats is okay, probably first boot
+ } catch (IOException e) {
+ Slog.e(TAG, "problem reading uid stats", e);
+ } finally {
+ IoUtils.closeQuietly(fis);
+ }
+ }
+
+ private void writeNetworkStatsLocked() {
+ if (LOGV) Slog.v(TAG, "writeNetworkStatsLocked()");
// TODO: consider duplicating stats and releasing lock while writing
FileOutputStream fos = null;
try {
- fos = mSummaryFile.startWrite();
+ fos = mNetworkFile.startWrite();
final DataOutputStream out = new DataOutputStream(fos);
out.writeInt(FILE_MAGIC);
out.writeInt(VERSION_CURRENT);
- out.writeInt(mSummaryStats.size());
- for (InterfaceIdentity ident : mSummaryStats.keySet()) {
- final NetworkStatsHistory history = mSummaryStats.get(ident);
+ out.writeInt(mNetworkStats.size());
+ for (InterfaceIdentity ident : mNetworkStats.keySet()) {
+ final NetworkStatsHistory history = mNetworkStats.get(ident);
ident.writeToStream(out);
history.writeToStream(out);
}
- mSummaryFile.finishWrite(fos);
+ mNetworkFile.finishWrite(fos);
+ } catch (IOException e) {
+ if (fos != null) {
+ mNetworkFile.failWrite(fos);
+ }
+ }
+ }
+
+ private void writeUidStatsLocked() {
+ if (LOGV) Slog.v(TAG, "writeUidStatsLocked()");
+
+ // TODO: consider duplicating stats and releasing lock while writing
+
+ FileOutputStream fos = null;
+ try {
+ fos = mUidFile.startWrite();
+ final DataOutputStream out = new DataOutputStream(fos);
+
+ out.writeInt(FILE_MAGIC);
+ out.writeInt(VERSION_CURRENT);
+
+ final int size = mUidStats.size();
+
+ out.writeInt(size);
+ for (int i = 0; i < size; i++) {
+ final int uid = mUidStats.keyAt(i);
+ final NetworkStatsHistory history = mUidStats.valueAt(i);
+ out.writeInt(uid);
+ history.writeToStream(out);
+ }
+
+ mUidFile.finishWrite(fos);
} catch (IOException e) {
if (fos != null) {
- mSummaryFile.failWrite(fos);
+ mUidFile.failWrite(fos);
}
}
}
@@ -590,7 +728,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
if (argSet.contains("poll")) {
- performPollLocked();
+ performPollLocked(true);
pw.println("Forced poll");
return;
}
@@ -603,17 +741,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
pw.println("Known historical stats:");
- for (InterfaceIdentity ident : mSummaryStats.keySet()) {
- final NetworkStatsHistory stats = mSummaryStats.get(ident);
+ for (InterfaceIdentity ident : mNetworkStats.keySet()) {
+ final NetworkStatsHistory stats = mNetworkStats.get(ident);
pw.print(" ident="); pw.println(ident.toString());
stats.dump(" ", pw);
}
if (argSet.contains("detail")) {
- pw.println("Known detail stats:");
- for (int i = 0; i < mDetailStats.size(); i++) {
- final int uid = mDetailStats.keyAt(i);
- final NetworkStatsHistory stats = mDetailStats.valueAt(i);
+ // since explicitly requested with argument, we're okay to load
+ // from disk if not already in memory.
+ ensureUidStatsLoadedLocked();
+ pw.println("Known UID stats:");
+ for (int i = 0; i < mUidStats.size(); i++) {
+ final int uid = mUidStats.keyAt(i);
+ final NetworkStatsHistory stats = mUidStats.valueAt(i);
pw.print(" UID="); pw.println(uid);
stats.dump(" ", pw);
}
@@ -627,47 +768,29 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Deprecated
private void generateRandomLocked() {
long end = System.currentTimeMillis();
- long start = end - mSummaryMaxHistory.get();
+ long start = end - mSettings.getNetworkMaxHistory();
long rx = 3 * GB_IN_BYTES;
long tx = 2 * GB_IN_BYTES;
- mSummaryStats.clear();
+ mNetworkStats.clear();
for (InterfaceIdentity ident : mActiveIface.values()) {
- final NetworkStatsHistory stats = findOrCreateSummaryLocked(ident);
+ final NetworkStatsHistory stats = findOrCreateNetworkLocked(ident);
stats.generateRandom(start, end, rx, tx);
}
end = System.currentTimeMillis();
- start = end - mDetailMaxHistory.get();
+ start = end - mSettings.getUidMaxHistory();
rx = 500 * MB_IN_BYTES;
tx = 100 * MB_IN_BYTES;
- mDetailStats.clear();
+ mUidStats.clear();
for (ApplicationInfo info : mContext.getPackageManager().getInstalledApplications(0)) {
final int uid = info.uid;
- final NetworkStatsHistory stats = findOrCreateDetailLocked(uid);
+ final NetworkStatsHistory stats = findOrCreateUidLocked(uid);
stats.generateRandom(start, end, rx, tx);
}
}
- private class LongSecureSetting {
- private String mKey;
- private long mDefaultValue;
-
- public LongSecureSetting(String key, long defaultValue) {
- mKey = key;
- mDefaultValue = defaultValue;
- }
-
- public long get() {
- if (mContext != null) {
- return Settings.Secure.getLong(mContext.getContentResolver(), mKey, mDefaultValue);
- } else {
- return mDefaultValue;
- }
- }
- }
-
/**
* Return the delta between two {@link NetworkStats} snapshots, where {@code
* before} can be {@code null}.
@@ -686,4 +809,42 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return telephony.getSubscriberId();
}
+ /**
+ * Default external settings that read from {@link Settings.Secure}.
+ */
+ private static class DefaultNetworkStatsSettings implements NetworkStatsSettings {
+ private final ContentResolver mResolver;
+
+ public DefaultNetworkStatsSettings(Context context) {
+ mResolver = checkNotNull(context.getContentResolver());
+ // TODO: adjust these timings for production builds
+ }
+
+ private long getSecureLong(String name, long def) {
+ return Settings.Secure.getLong(mResolver, name, def);
+ }
+
+ public long getPollInterval() {
+ return getSecureLong(NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS);
+ }
+ public long getPersistThreshold() {
+ return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 16 * KB_IN_BYTES);
+ }
+ public long getNetworkBucketDuration() {
+ return getSecureLong(NETSTATS_NETWORK_BUCKET_DURATION, HOUR_IN_MILLIS);
+ }
+ public long getNetworkMaxHistory() {
+ return getSecureLong(NETSTATS_NETWORK_MAX_HISTORY, 90 * DAY_IN_MILLIS);
+ }
+ public long getUidBucketDuration() {
+ return getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS);
+ }
+ public long getUidMaxHistory() {
+ return getSecureLong(NETSTATS_UID_MAX_HISTORY, 90 * DAY_IN_MILLIS);
+ }
+ public long getTimeCacheMaxAge() {
+ return DAY_IN_MILLIS;
+ }
+ }
+
}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 9846372..d6e4b8b 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);
}
}