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