NetworkStatsRecorder.java revision bfdd680ab44da173a4a39fcd6feccdebb9d1f855
163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey/* 263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Copyright (C) 2012 The Android Open Source Project 363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * 463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * you may not use this file except in compliance with the License. 663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * You may obtain a copy of the License at 763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * 863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * 1063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Unless required by applicable law or agreed to in writing, software 1163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 1263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * See the License for the specific language governing permissions and 1463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * limitations under the License. 1563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 1663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 1763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeypackage com.android.server.net; 1863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 1963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static android.net.NetworkStats.TAG_NONE; 2063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static com.android.internal.util.Preconditions.checkNotNull; 2163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 2263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkStats; 2363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkStats.NonMonotonicObserver; 2463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkStatsHistory; 2563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkTemplate; 2663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.TrafficStats; 2763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.util.Log; 2863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.util.Slog; 2963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 3063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.FileRotator; 3163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter; 3263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.google.android.collect.Sets; 3363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 3463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.DataOutputStream; 3563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.File; 3663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.IOException; 3763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.InputStream; 3863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.OutputStream; 3963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.lang.ref.WeakReference; 4063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.util.HashSet; 4163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.util.Map; 4263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 4363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey/** 4463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Logic to record deltas between periodic {@link NetworkStats} snapshots into 4563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}. 4663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Keeps pending changes in memory until they pass a specific threshold, in 4763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * bytes. Uses {@link FileRotator} for persistence logic. 4863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * <p> 4963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Not inherently thread safe. 5063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 5163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeypublic class NetworkStatsRecorder { 5263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static final String TAG = "NetworkStatsRecorder"; 53e7bb71d26943fbb053139e1e34203df4c2afaa9bJeff Sharkey private static final boolean LOGD = false; 541f8ea2dcd1ed3cde4b84fbb27b5a55b3fea7ff2aJeff Sharkey private static final boolean LOGV = false; 5563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 5663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private final FileRotator mRotator; 5763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private final NonMonotonicObserver<String> mObserver; 5863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private final String mCookie; 5963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 6063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private final long mBucketDuration; 6163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private final long mPersistThresholdBytes; 6263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private final boolean mOnlyTags; 6363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 6463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private NetworkStats mLastSnapshot; 6563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 6663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private final NetworkStatsCollection mPending; 6763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private final NetworkStatsCollection mSinceBoot; 6863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 6963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private final CombiningRewriter mPendingRewriter; 7063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 7163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private WeakReference<NetworkStatsCollection> mComplete; 7263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 7363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer, 7463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey String cookie, long bucketDuration, long persistThresholdBytes, boolean onlyTags) { 7563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mRotator = checkNotNull(rotator, "missing FileRotator"); 7663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mObserver = checkNotNull(observer, "missing NonMonotonicObserver"); 7763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mCookie = cookie; 7863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 7963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mBucketDuration = bucketDuration; 8063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mPersistThresholdBytes = persistThresholdBytes; 8163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mOnlyTags = onlyTags; 8263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 8363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mPending = new NetworkStatsCollection(bucketDuration); 8463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mSinceBoot = new NetworkStatsCollection(bucketDuration); 8563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 8663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mPendingRewriter = new CombiningRewriter(mPending); 8763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 8863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 8963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void resetLocked() { 9063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mLastSnapshot = null; 9163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mPending.reset(); 9263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mSinceBoot.reset(); 9363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mComplete.clear(); 9463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 9563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 9663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) { 9763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE).getTotal(null); 9863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 9963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 10063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 10163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Load complete history represented by {@link FileRotator}. Caches 10263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * internally as a {@link WeakReference}, and updated with future 10363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * {@link #recordSnapshotLocked(NetworkStats, Map, long)} snapshots as long 10463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * as reference is valid. 10563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 10663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public NetworkStatsCollection getOrLoadCompleteLocked() { 10763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null; 10863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (complete == null) { 10963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (LOGD) Slog.d(TAG, "getOrLoadCompleteLocked() reading from disk for " + mCookie); 11063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey try { 11163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey complete = new NetworkStatsCollection(mBucketDuration); 11263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mRotator.readMatching(complete, Long.MIN_VALUE, Long.MAX_VALUE); 11363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey complete.recordCollection(mPending); 11463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mComplete = new WeakReference<NetworkStatsCollection>(complete); 11563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } catch (IOException e) { 11663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey Log.wtf(TAG, "problem completely reading network stats", e); 11763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 11863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 11963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return complete; 12063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 12163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 12263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 12363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Record any delta that occurred since last {@link NetworkStats} snapshot, 12463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * using the given {@link Map} to identify network interfaces. First 12563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * snapshot is considered bootstrap, and is not counted as delta. 12663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 12763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void recordSnapshotLocked(NetworkStats snapshot, 12863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey Map<String, NetworkIdentitySet> ifaceIdent, long currentTimeMillis) { 12963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final HashSet<String> unknownIfaces = Sets.newHashSet(); 13063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 13163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // assume first snapshot is bootstrap and don't record 13263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (mLastSnapshot == null) { 13363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mLastSnapshot = snapshot; 13463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return; 13563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 13663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 13763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null; 13863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 13963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStats delta = NetworkStats.subtract( 14063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey snapshot, mLastSnapshot, mObserver, mCookie); 14163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final long end = currentTimeMillis; 14263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final long start = end - delta.getElapsedRealtime(); 14363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 14463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey NetworkStats.Entry entry = null; 14563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (int i = 0; i < delta.size(); i++) { 14663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry = delta.getValues(i, entry); 14763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkIdentitySet ident = ifaceIdent.get(entry.iface); 14863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (ident == null) { 14963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey unknownIfaces.add(entry.iface); 15063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey continue; 15163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 15263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 15363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // skip when no delta occured 15463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (entry.isEmpty()) continue; 15563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 15663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // only record tag data when requested 15763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if ((entry.tag == TAG_NONE) != mOnlyTags) { 15863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry); 15963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 16063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // also record against boot stats when present 16163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (mSinceBoot != null) { 16263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mSinceBoot.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry); 16363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 16463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 16563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // also record against complete dataset when present 16663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (complete != null) { 16763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey complete.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry); 16863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 16963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 17063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 17163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 17263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mLastSnapshot = snapshot; 17363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 1741f8ea2dcd1ed3cde4b84fbb27b5a55b3fea7ff2aJeff Sharkey if (LOGV && unknownIfaces.size() > 0) { 17563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats"); 17663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 17763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 17863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 17963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 18063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Consider persisting any pending deltas, if they are beyond 18163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * {@link #mPersistThresholdBytes}. 18263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 18363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void maybePersistLocked(long currentTimeMillis) { 18463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final long pendingBytes = mPending.getTotalBytes(); 18563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (pendingBytes >= mPersistThresholdBytes) { 18663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey forcePersistLocked(currentTimeMillis); 18763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } else { 18863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mRotator.maybeRotate(currentTimeMillis); 18963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 19063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 19163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 19263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 19363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Force persisting any pending deltas. 19463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 19563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void forcePersistLocked(long currentTimeMillis) { 19663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (mPending.isDirty()) { 19763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie); 19863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey try { 19963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mRotator.rewriteActive(mPendingRewriter, currentTimeMillis); 20063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mRotator.maybeRotate(currentTimeMillis); 20163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mPending.reset(); 20263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } catch (IOException e) { 20363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey Log.wtf(TAG, "problem persisting pending stats", e); 20463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 20563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 20663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 20763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 20863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 20963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Remove the given UID from all {@link FileRotator} history, migrating it 21063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * to {@link TrafficStats#UID_REMOVED}. 21163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 21263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void removeUidLocked(int uid) { 21363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey try { 21463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // process all existing data to migrate uid 21563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uid)); 21663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } catch (IOException e) { 21763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey Log.wtf(TAG, "problem removing UID " + uid, e); 21863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 21963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 22063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // clear UID from current stats snapshot 22163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (mLastSnapshot != null) { 22263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mLastSnapshot = mLastSnapshot.withoutUid(uid); 22363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 224b52e3e55098c4a6e3dbfe19885895411cfb38911Jeff Sharkey 225b52e3e55098c4a6e3dbfe19885895411cfb38911Jeff Sharkey final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null; 226b52e3e55098c4a6e3dbfe19885895411cfb38911Jeff Sharkey if (complete != null) { 227b52e3e55098c4a6e3dbfe19885895411cfb38911Jeff Sharkey complete.removeUid(uid); 228b52e3e55098c4a6e3dbfe19885895411cfb38911Jeff Sharkey } 22963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 23063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 23163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 23263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Rewriter that will combine current {@link NetworkStatsCollection} values 23363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * with anything read from disk, and write combined set to disk. Clears the 23463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * original {@link NetworkStatsCollection} when finished writing. 23563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 23663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static class CombiningRewriter implements FileRotator.Rewriter { 23763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private final NetworkStatsCollection mCollection; 23863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 23963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public CombiningRewriter(NetworkStatsCollection collection) { 24063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mCollection = checkNotNull(collection, "missing NetworkStatsCollection"); 24163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 24263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 243bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey @Override 24463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void reset() { 24563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // ignored 24663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 24763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 248bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey @Override 24963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void read(InputStream in) throws IOException { 25063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mCollection.read(in); 25163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 25263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 253bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey @Override 25463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public boolean shouldWrite() { 25563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return true; 25663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 25763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 258bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey @Override 25963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void write(OutputStream out) throws IOException { 26063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mCollection.write(new DataOutputStream(out)); 26163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mCollection.reset(); 26263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 26363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 26463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 26563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 26663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Rewriter that will remove any {@link NetworkStatsHistory} attributed to 26763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * the requested UID, only writing data back when modified. 26863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 26963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public static class RemoveUidRewriter implements FileRotator.Rewriter { 27063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private final NetworkStatsCollection mTemp; 27163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private final int mUid; 27263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 27363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public RemoveUidRewriter(long bucketDuration, int uid) { 27463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mTemp = new NetworkStatsCollection(bucketDuration); 27563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mUid = uid; 27663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 27763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 278bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey @Override 27963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void reset() { 28063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mTemp.reset(); 28163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 28263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 283bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey @Override 28463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void read(InputStream in) throws IOException { 28563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mTemp.read(in); 28663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mTemp.clearDirty(); 28763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mTemp.removeUid(mUid); 28863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 28963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 290bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey @Override 29163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public boolean shouldWrite() { 29263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return mTemp.isDirty(); 29363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 29463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 295bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey @Override 29663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void write(OutputStream out) throws IOException { 29763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mTemp.write(new DataOutputStream(out)); 29863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 29963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 30063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 30163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void importLegacyNetworkLocked(File file) throws IOException { 30263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // legacy file still exists; start empty to avoid double importing 30363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mRotator.deleteAll(); 30463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 30563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration); 30663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey collection.readLegacyNetwork(file); 30763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 30863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final long startMillis = collection.getStartMillis(); 30963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final long endMillis = collection.getEndMillis(); 31063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 31163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (!collection.isEmpty()) { 31263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // process legacy data, creating active file at starting time, then 31363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // using end time to possibly trigger rotation. 31463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mRotator.rewriteActive(new CombiningRewriter(collection), startMillis); 31563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mRotator.maybeRotate(endMillis); 31663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 31763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 31863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 31963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void importLegacyUidLocked(File file) throws IOException { 32063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // legacy file still exists; start empty to avoid double importing 32163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mRotator.deleteAll(); 32263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 32363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration); 32463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey collection.readLegacyUid(file, mOnlyTags); 32563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 32663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final long startMillis = collection.getStartMillis(); 32763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final long endMillis = collection.getEndMillis(); 32863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 32963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (!collection.isEmpty()) { 33063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // process legacy data, creating active file at starting time, then 33163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // using end time to possibly trigger rotation. 33263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mRotator.rewriteActive(new CombiningRewriter(collection), startMillis); 33363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mRotator.maybeRotate(endMillis); 33463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 33563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 33663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 33763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) { 33863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes()); 33963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (fullHistory) { 34063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey pw.println("Complete history:"); 34163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey getOrLoadCompleteLocked().dump(pw); 34263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } else { 34363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey pw.println("History since boot:"); 34463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mSinceBoot.dump(pw); 34563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 34663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 34763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey} 348