NetworkStatsRecorder.java revision 1efb1335814aea8ee0696144ca0ab24159b86e54
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;
20ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkeyimport static android.net.TrafficStats.KB_IN_BYTES;
21ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkeyimport static android.net.TrafficStats.MB_IN_BYTES;
2263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static com.android.internal.util.Preconditions.checkNotNull;
2363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
2463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkStats;
2563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkStats.NonMonotonicObserver;
2663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkStatsHistory;
2763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkTemplate;
2863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.TrafficStats;
296de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkeyimport android.os.DropBoxManager;
3063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.util.Log;
31ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkeyimport android.util.MathUtils;
3263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.util.Slog;
3363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
34f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tongimport com.android.internal.net.VpnInfo;
3563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.FileRotator;
3663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter;
3763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.google.android.collect.Sets;
3863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
396de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkeyimport java.io.ByteArrayOutputStream;
4063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.DataOutputStream;
4163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.File;
4263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.IOException;
4363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.InputStream;
4463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.OutputStream;
4555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkeyimport java.io.PrintWriter;
4663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.lang.ref.WeakReference;
47daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkeyimport java.util.Arrays;
4863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.util.HashSet;
4963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.util.Map;
5063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
516de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkeyimport libcore.io.IoUtils;
526de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey
5363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey/**
5463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Logic to record deltas between periodic {@link NetworkStats} snapshots into
5563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}.
5663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Keeps pending changes in memory until they pass a specific threshold, in
5763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * bytes. Uses {@link FileRotator} for persistence logic.
5863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * <p>
5963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Not inherently thread safe.
6063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */
6163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeypublic class NetworkStatsRecorder {
6263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static final String TAG = "NetworkStatsRecorder";
63e7bb71d26943fbb053139e1e34203df4c2afaa9bJeff Sharkey    private static final boolean LOGD = false;
641f8ea2dcd1ed3cde4b84fbb27b5a55b3fea7ff2aJeff Sharkey    private static final boolean LOGV = false;
6563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
666de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey    private static final String TAG_NETSTATS_DUMP = "netstats_dump";
676de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey
686de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey    /** Dump before deleting in {@link #recoverFromWtf()}. */
696de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey    private static final boolean DUMP_BEFORE_DELETE = true;
706de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey
7163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private final FileRotator mRotator;
7263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private final NonMonotonicObserver<String> mObserver;
736de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey    private final DropBoxManager mDropBox;
7463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private final String mCookie;
7563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
7663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private final long mBucketDuration;
7763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private final boolean mOnlyTags;
7863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
79ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey    private long mPersistThresholdBytes = 2 * MB_IN_BYTES;
8063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private NetworkStats mLastSnapshot;
8163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
8263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private final NetworkStatsCollection mPending;
8363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private final NetworkStatsCollection mSinceBoot;
8463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
8563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private final CombiningRewriter mPendingRewriter;
8663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
8763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private WeakReference<NetworkStatsCollection> mComplete;
8863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
8963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
906de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey            DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) {
9163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mRotator = checkNotNull(rotator, "missing FileRotator");
9263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mObserver = checkNotNull(observer, "missing NonMonotonicObserver");
936de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey        mDropBox = checkNotNull(dropBox, "missing DropBoxManager");
9463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mCookie = cookie;
9563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
9663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mBucketDuration = bucketDuration;
9763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mOnlyTags = onlyTags;
9863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
9963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mPending = new NetworkStatsCollection(bucketDuration);
10063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mSinceBoot = new NetworkStatsCollection(bucketDuration);
10163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
10263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mPendingRewriter = new CombiningRewriter(mPending);
10363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
10463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
105ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey    public void setPersistThreshold(long thresholdBytes) {
106ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey        if (LOGV) Slog.v(TAG, "setPersistThreshold() with " + thresholdBytes);
107ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey        mPersistThresholdBytes = MathUtils.constrain(
108ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey                thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES);
109ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey    }
110ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey
11163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void resetLocked() {
11263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mLastSnapshot = null;
11363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mPending.reset();
11463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mSinceBoot.reset();
11563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mComplete.clear();
11663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
11763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
11863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) {
1191efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE,
1201efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson                NetworkStatsAccess.Level.DEVICE).getTotal(null);
12163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
12263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
12363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
12463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Load complete history represented by {@link FileRotator}. Caches
12563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * internally as a {@link WeakReference}, and updated with future
12663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * {@link #recordSnapshotLocked(NetworkStats, Map, long)} snapshots as long
12763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * as reference is valid.
12863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
12963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public NetworkStatsCollection getOrLoadCompleteLocked() {
13055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
13155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (res == null) {
13255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE);
13355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            mComplete = new WeakReference<NetworkStatsCollection>(res);
13463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
13555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        return res;
13655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    }
13755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey
13855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) {
13955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
14055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (res == null) {
14155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            res = loadLocked(start, end);
14255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        }
14355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        return res;
14455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    }
14555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey
14655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    private NetworkStatsCollection loadLocked(long start, long end) {
14755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (LOGD) Slog.d(TAG, "loadLocked() reading from disk for " + mCookie);
14855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration);
14955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        try {
15055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            mRotator.readMatching(res, start, end);
15155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            res.recordCollection(mPending);
15255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        } catch (IOException e) {
15355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            Log.wtf(TAG, "problem completely reading network stats", e);
15455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            recoverFromWtf();
15555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        } catch (OutOfMemoryError e) {
15655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            Log.wtf(TAG, "problem completely reading network stats", e);
15755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            recoverFromWtf();
15855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        }
15955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        return res;
16063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
16163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
16263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
16363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Record any delta that occurred since last {@link NetworkStats} snapshot,
16463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * using the given {@link Map} to identify network interfaces. First
16563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * snapshot is considered bootstrap, and is not counted as delta.
16663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
16763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void recordSnapshotLocked(NetworkStats snapshot,
168f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong            Map<String, NetworkIdentitySet> ifaceIdent, VpnInfo[] vpnArray,
169f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong            long currentTimeMillis) {
17063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final HashSet<String> unknownIfaces = Sets.newHashSet();
17163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
172e8914c36276710de50b347c1e6aecfa45d6a56cdJeff Sharkey        // skip recording when snapshot missing
173e8914c36276710de50b347c1e6aecfa45d6a56cdJeff Sharkey        if (snapshot == null) return;
174e8914c36276710de50b347c1e6aecfa45d6a56cdJeff Sharkey
17563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // assume first snapshot is bootstrap and don't record
17663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (mLastSnapshot == null) {
17763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mLastSnapshot = snapshot;
17863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            return;
17963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
18063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
18163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
18263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
18363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final NetworkStats delta = NetworkStats.subtract(
18463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                snapshot, mLastSnapshot, mObserver, mCookie);
18563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final long end = currentTimeMillis;
18663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final long start = end - delta.getElapsedRealtime();
18763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
188f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong        if (vpnArray != null) {
189f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong            for (VpnInfo info : vpnArray) {
190f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong                delta.migrateTun(info.ownerUid, info.vpnIface, info.primaryUnderlyingIface);
191f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong            }
192f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong        }
193f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong
19463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        NetworkStats.Entry entry = null;
19563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        for (int i = 0; i < delta.size(); i++) {
19663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            entry = delta.getValues(i, entry);
19763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final NetworkIdentitySet ident = ifaceIdent.get(entry.iface);
19863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            if (ident == null) {
19963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                unknownIfaces.add(entry.iface);
20063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                continue;
20163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
20263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
203ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey            // skip when no delta occurred
20463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            if (entry.isEmpty()) continue;
20563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
20663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // only record tag data when requested
20763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            if ((entry.tag == TAG_NONE) != mOnlyTags) {
20863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
20963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
21063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                // also record against boot stats when present
21163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                if (mSinceBoot != null) {
21263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    mSinceBoot.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
21363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                }
21463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
21563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                // also record against complete dataset when present
21663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                if (complete != null) {
21763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    complete.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
21863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                }
21963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
22063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
22163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
22263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mLastSnapshot = snapshot;
22363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
2241f8ea2dcd1ed3cde4b84fbb27b5a55b3fea7ff2aJeff Sharkey        if (LOGV && unknownIfaces.size() > 0) {
22563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats");
22663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
22763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
22863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
22963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
23063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Consider persisting any pending deltas, if they are beyond
23163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * {@link #mPersistThresholdBytes}.
23263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
23363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void maybePersistLocked(long currentTimeMillis) {
23463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final long pendingBytes = mPending.getTotalBytes();
23563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (pendingBytes >= mPersistThresholdBytes) {
23663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            forcePersistLocked(currentTimeMillis);
23763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        } else {
23863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mRotator.maybeRotate(currentTimeMillis);
23963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
24063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
24163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
24263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
24363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Force persisting any pending deltas.
24463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
24563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void forcePersistLocked(long currentTimeMillis) {
24663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (mPending.isDirty()) {
24763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
24863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            try {
24963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                mRotator.rewriteActive(mPendingRewriter, currentTimeMillis);
25063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                mRotator.maybeRotate(currentTimeMillis);
25163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                mPending.reset();
25263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            } catch (IOException e) {
25363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                Log.wtf(TAG, "problem persisting pending stats", e);
2546de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey                recoverFromWtf();
255e4984bea95a07dea0ef0259fefa1e52f0bbb1533Jeff Sharkey            } catch (OutOfMemoryError e) {
256e4984bea95a07dea0ef0259fefa1e52f0bbb1533Jeff Sharkey                Log.wtf(TAG, "problem persisting pending stats", e);
257e4984bea95a07dea0ef0259fefa1e52f0bbb1533Jeff Sharkey                recoverFromWtf();
25863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
25963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
26063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
26163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
26263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
26363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Remove the given UID from all {@link FileRotator} history, migrating it
26463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * to {@link TrafficStats#UID_REMOVED}.
26563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
266daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey    public void removeUidsLocked(int[] uids) {
26763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        try {
268daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey            // Rewrite all persisted data to migrate UID stats
269daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey            mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids));
27063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        } catch (IOException e) {
271daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey            Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
272e4984bea95a07dea0ef0259fefa1e52f0bbb1533Jeff Sharkey            recoverFromWtf();
273e4984bea95a07dea0ef0259fefa1e52f0bbb1533Jeff Sharkey        } catch (OutOfMemoryError e) {
274e4984bea95a07dea0ef0259fefa1e52f0bbb1533Jeff Sharkey            Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
2756de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey            recoverFromWtf();
27663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
27763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
278daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey        // Remove any pending stats
279daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey        mPending.removeUids(uids);
280daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey        mSinceBoot.removeUids(uids);
281daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey
282daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey        // Clear UID from current stats snapshot
28363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (mLastSnapshot != null) {
284daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey            mLastSnapshot = mLastSnapshot.withoutUids(uids);
28563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
286b52e3e55098c4a6e3dbfe19885895411cfb38911Jeff Sharkey
287b52e3e55098c4a6e3dbfe19885895411cfb38911Jeff Sharkey        final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
288b52e3e55098c4a6e3dbfe19885895411cfb38911Jeff Sharkey        if (complete != null) {
289daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey            complete.removeUids(uids);
290b52e3e55098c4a6e3dbfe19885895411cfb38911Jeff Sharkey        }
29163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
29263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
29363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
29463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Rewriter that will combine current {@link NetworkStatsCollection} values
29563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * with anything read from disk, and write combined set to disk. Clears the
29663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * original {@link NetworkStatsCollection} when finished writing.
29763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
29863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static class CombiningRewriter implements FileRotator.Rewriter {
29963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        private final NetworkStatsCollection mCollection;
30063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
30163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public CombiningRewriter(NetworkStatsCollection collection) {
30263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mCollection = checkNotNull(collection, "missing NetworkStatsCollection");
30363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
30463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
305bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
30663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public void reset() {
30763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // ignored
30863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
30963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
310bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
31163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public void read(InputStream in) throws IOException {
31263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mCollection.read(in);
31363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
31463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
315bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
31663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public boolean shouldWrite() {
31763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            return true;
31863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
31963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
320bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
32163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public void write(OutputStream out) throws IOException {
32263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mCollection.write(new DataOutputStream(out));
32363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mCollection.reset();
32463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
32563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
32663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
32763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
32863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Rewriter that will remove any {@link NetworkStatsHistory} attributed to
32963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * the requested UID, only writing data back when modified.
33063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
33163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public static class RemoveUidRewriter implements FileRotator.Rewriter {
33263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        private final NetworkStatsCollection mTemp;
333daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey        private final int[] mUids;
33463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
335daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey        public RemoveUidRewriter(long bucketDuration, int[] uids) {
33663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mTemp = new NetworkStatsCollection(bucketDuration);
337daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey            mUids = uids;
33863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
33963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
340bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
34163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public void reset() {
34263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mTemp.reset();
34363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
34463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
345bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
34663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public void read(InputStream in) throws IOException {
34763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mTemp.read(in);
34863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mTemp.clearDirty();
349daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey            mTemp.removeUids(mUids);
35063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
35163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
352bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
35363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public boolean shouldWrite() {
35463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            return mTemp.isDirty();
35563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
35663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
357bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
35863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public void write(OutputStream out) throws IOException {
35963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mTemp.write(new DataOutputStream(out));
36063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
36163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
36263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
36363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void importLegacyNetworkLocked(File file) throws IOException {
36463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // legacy file still exists; start empty to avoid double importing
36563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mRotator.deleteAll();
36663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
36763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
36863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        collection.readLegacyNetwork(file);
36963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
37063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final long startMillis = collection.getStartMillis();
37163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final long endMillis = collection.getEndMillis();
37263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
37363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (!collection.isEmpty()) {
37463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // process legacy data, creating active file at starting time, then
37563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // using end time to possibly trigger rotation.
37663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
37763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mRotator.maybeRotate(endMillis);
37863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
37963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
38063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
38163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void importLegacyUidLocked(File file) throws IOException {
38263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // legacy file still exists; start empty to avoid double importing
38363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mRotator.deleteAll();
38463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
38563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
38663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        collection.readLegacyUid(file, mOnlyTags);
38763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
38863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final long startMillis = collection.getStartMillis();
38963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final long endMillis = collection.getEndMillis();
39063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
39163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (!collection.isEmpty()) {
39263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // process legacy data, creating active file at starting time, then
39363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // using end time to possibly trigger rotation.
39463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
39563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mRotator.maybeRotate(endMillis);
39663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
39763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
39863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
39963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) {
40063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes());
40163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (fullHistory) {
40263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            pw.println("Complete history:");
40363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            getOrLoadCompleteLocked().dump(pw);
40463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        } else {
40563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            pw.println("History since boot:");
40663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mSinceBoot.dump(pw);
40763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
40863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
4096de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey
41055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    public void dumpCheckin(PrintWriter pw, long start, long end) {
41155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        // Only load and dump stats from the requested window
41255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end);
41355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    }
41455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey
4156de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey    /**
4166de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey     * Recover from {@link FileRotator} failure by dumping state to
4176de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey     * {@link DropBoxManager} and deleting contents.
4186de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey     */
4196de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey    private void recoverFromWtf() {
4206de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey        if (DUMP_BEFORE_DELETE) {
4216de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey            final ByteArrayOutputStream os = new ByteArrayOutputStream();
4226de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey            try {
4236de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey                mRotator.dumpAll(os);
4246de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey            } catch (IOException e) {
4256de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey                // ignore partial contents
4266de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey                os.reset();
4276de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey            } finally {
4286de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey                IoUtils.closeQuietly(os);
4296de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey            }
4306de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey            mDropBox.addData(TAG_NETSTATS_DUMP, os.toByteArray(), 0);
4316de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey        }
4326de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey
4336de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey        mRotator.deleteAll();
4346de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey    }
43563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey}
436