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;
22cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansadoimport static android.text.format.DateUtils.YEAR_IN_MILLIS;
23f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
2463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static com.android.internal.util.Preconditions.checkNotNull;
2563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
264ff3bcfa0c143ad14c81d07f90ed6dc375701ab1Jeff Davidsonimport android.annotation.Nullable;
2763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkStats;
2863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkStats.NonMonotonicObserver;
2963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkStatsHistory;
3063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkTemplate;
3163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.TrafficStats;
32f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport android.os.Binder;
336de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkeyimport android.os.DropBoxManager;
34da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onukiimport android.service.NetworkStatsRecorderProto;
3563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.util.Log;
36ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkeyimport android.util.MathUtils;
3763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.util.Slog;
38da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onukiimport android.util.proto.ProtoOutputStream;
3963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
40f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tongimport com.android.internal.net.VpnInfo;
4163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.FileRotator;
4263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter;
43f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
44f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport libcore.io.IoUtils;
45f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
4663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.google.android.collect.Sets;
4763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
486de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkeyimport java.io.ByteArrayOutputStream;
4963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.DataOutputStream;
5063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.File;
5163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.IOException;
5263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.InputStream;
5363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.OutputStream;
5455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkeyimport java.io.PrintWriter;
5563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.lang.ref.WeakReference;
56daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkeyimport java.util.Arrays;
5763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.util.HashSet;
5863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.util.Map;
5963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
6063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey/**
6163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Logic to record deltas between periodic {@link NetworkStats} snapshots into
6263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}.
6363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Keeps pending changes in memory until they pass a specific threshold, in
64cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado * bytes. Uses {@link FileRotator} for persistence logic if present.
6563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * <p>
6663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Not inherently thread safe.
6763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */
6863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeypublic class NetworkStatsRecorder {
6963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static final String TAG = "NetworkStatsRecorder";
70e7bb71d26943fbb053139e1e34203df4c2afaa9bJeff Sharkey    private static final boolean LOGD = false;
711f8ea2dcd1ed3cde4b84fbb27b5a55b3fea7ff2aJeff Sharkey    private static final boolean LOGV = false;
7263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
736de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey    private static final String TAG_NETSTATS_DUMP = "netstats_dump";
746de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey
756de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey    /** Dump before deleting in {@link #recoverFromWtf()}. */
766de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey    private static final boolean DUMP_BEFORE_DELETE = true;
776de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey
7863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private final FileRotator mRotator;
7963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private final NonMonotonicObserver<String> mObserver;
806de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey    private final DropBoxManager mDropBox;
8163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private final String mCookie;
8263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
8363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private final long mBucketDuration;
8463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private final boolean mOnlyTags;
8563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
86ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey    private long mPersistThresholdBytes = 2 * MB_IN_BYTES;
8763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private NetworkStats mLastSnapshot;
8863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
8963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private final NetworkStatsCollection mPending;
9063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private final NetworkStatsCollection mSinceBoot;
9163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
9263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private final CombiningRewriter mPendingRewriter;
9363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
9463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private WeakReference<NetworkStatsCollection> mComplete;
9563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
96cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado    /**
97cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado     * Non-persisted recorder, with only one bucket. Used by {@link NetworkStatsObservers}.
98cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado     */
99cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado    public NetworkStatsRecorder() {
100cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        mRotator = null;
101cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        mObserver = null;
102cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        mDropBox = null;
103cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        mCookie = null;
104cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado
105cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        // set the bucket big enough to have all data in one bucket, but allow some
106cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        // slack to avoid overflow
107cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        mBucketDuration = YEAR_IN_MILLIS;
108cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        mOnlyTags = false;
109cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado
110cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        mPending = null;
111cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        mSinceBoot = new NetworkStatsCollection(mBucketDuration);
112cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado
113cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        mPendingRewriter = null;
114cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado    }
115cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado
116cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado    /**
117cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado     * Persisted recorder.
118cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado     */
11963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
1206de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey            DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) {
12163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mRotator = checkNotNull(rotator, "missing FileRotator");
12263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mObserver = checkNotNull(observer, "missing NonMonotonicObserver");
1236de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey        mDropBox = checkNotNull(dropBox, "missing DropBoxManager");
12463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mCookie = cookie;
12563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
12663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mBucketDuration = bucketDuration;
12763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mOnlyTags = onlyTags;
12863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
12963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mPending = new NetworkStatsCollection(bucketDuration);
13063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mSinceBoot = new NetworkStatsCollection(bucketDuration);
13163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
13263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mPendingRewriter = new CombiningRewriter(mPending);
13363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
13463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
135ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey    public void setPersistThreshold(long thresholdBytes) {
136ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey        if (LOGV) Slog.v(TAG, "setPersistThreshold() with " + thresholdBytes);
137ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey        mPersistThresholdBytes = MathUtils.constrain(
138ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey                thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES);
139ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey    }
140ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey
14163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void resetLocked() {
14263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mLastSnapshot = null;
143cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        if (mPending != null) {
144cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado            mPending.reset();
145cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        }
146cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        if (mSinceBoot != null) {
147cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado            mSinceBoot.reset();
148cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        }
149cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        if (mComplete != null) {
150cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado            mComplete.clear();
151cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        }
15263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
15363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
15463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) {
1551efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson        return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE,
156f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey                NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotal(null);
15763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
15863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
159cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado    public NetworkStatsCollection getSinceBoot() {
160cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        return mSinceBoot;
161cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado    }
162cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado
16363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
16463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Load complete history represented by {@link FileRotator}. Caches
16563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * internally as a {@link WeakReference}, and updated with future
16663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * {@link #recordSnapshotLocked(NetworkStats, Map, long)} snapshots as long
16763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * as reference is valid.
16863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
16963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public NetworkStatsCollection getOrLoadCompleteLocked() {
170cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        checkNotNull(mRotator, "missing FileRotator");
17155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
17255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (res == null) {
17355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE);
17455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            mComplete = new WeakReference<NetworkStatsCollection>(res);
17563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
17655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        return res;
17755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    }
17855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey
17955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) {
180cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        checkNotNull(mRotator, "missing FileRotator");
18155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
18255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (res == null) {
18355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            res = loadLocked(start, end);
18455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        }
18555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        return res;
18655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    }
18755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey
18855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    private NetworkStatsCollection loadLocked(long start, long end) {
18955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (LOGD) Slog.d(TAG, "loadLocked() reading from disk for " + mCookie);
19055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration);
19155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        try {
19255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            mRotator.readMatching(res, start, end);
19355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            res.recordCollection(mPending);
19455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        } catch (IOException e) {
19555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            Log.wtf(TAG, "problem completely reading network stats", e);
19655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            recoverFromWtf();
19755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        } catch (OutOfMemoryError e) {
19855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            Log.wtf(TAG, "problem completely reading network stats", e);
19955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            recoverFromWtf();
20055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        }
20155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        return res;
20263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
20363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
20463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
20563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Record any delta that occurred since last {@link NetworkStats} snapshot,
20663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * using the given {@link Map} to identify network interfaces. First
20763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * snapshot is considered bootstrap, and is not counted as delta.
2084ff3bcfa0c143ad14c81d07f90ed6dc375701ab1Jeff Davidson     *
2094ff3bcfa0c143ad14c81d07f90ed6dc375701ab1Jeff Davidson     * @param vpnArray Optional info about the currently active VPN, if any. This is used to
2104ff3bcfa0c143ad14c81d07f90ed6dc375701ab1Jeff Davidson     *                 redistribute traffic from the VPN app to the underlying responsible apps.
2114ff3bcfa0c143ad14c81d07f90ed6dc375701ab1Jeff Davidson     *                 This should always be set to null if the provided snapshot is aggregated
2124ff3bcfa0c143ad14c81d07f90ed6dc375701ab1Jeff Davidson     *                 across all UIDs (e.g. contains UID_ALL buckets), regardless of VPN state.
21363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
21463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void recordSnapshotLocked(NetworkStats snapshot,
2154ff3bcfa0c143ad14c81d07f90ed6dc375701ab1Jeff Davidson            Map<String, NetworkIdentitySet> ifaceIdent, @Nullable VpnInfo[] vpnArray,
216f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong            long currentTimeMillis) {
21763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final HashSet<String> unknownIfaces = Sets.newHashSet();
21863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
219e8914c36276710de50b347c1e6aecfa45d6a56cdJeff Sharkey        // skip recording when snapshot missing
220e8914c36276710de50b347c1e6aecfa45d6a56cdJeff Sharkey        if (snapshot == null) return;
221e8914c36276710de50b347c1e6aecfa45d6a56cdJeff Sharkey
22263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // assume first snapshot is bootstrap and don't record
22363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (mLastSnapshot == null) {
22463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mLastSnapshot = snapshot;
22563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            return;
22663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
22763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
22863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
22963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
23063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final NetworkStats delta = NetworkStats.subtract(
23163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                snapshot, mLastSnapshot, mObserver, mCookie);
23263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final long end = currentTimeMillis;
23363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final long start = end - delta.getElapsedRealtime();
23463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
235f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong        if (vpnArray != null) {
236f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong            for (VpnInfo info : vpnArray) {
237f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong                delta.migrateTun(info.ownerUid, info.vpnIface, info.primaryUnderlyingIface);
238f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong            }
239f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong        }
240f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong
24163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        NetworkStats.Entry entry = null;
24263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        for (int i = 0; i < delta.size(); i++) {
24363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            entry = delta.getValues(i, entry);
244b5a97e6f63bfe8b828224f606f8cb8585d9f28ecJeff Sharkey
245b5a97e6f63bfe8b828224f606f8cb8585d9f28ecJeff Sharkey            // As a last-ditch sanity check, report any negative values and
246b5a97e6f63bfe8b828224f606f8cb8585d9f28ecJeff Sharkey            // clamp them so recording below doesn't croak.
247b5a97e6f63bfe8b828224f606f8cb8585d9f28ecJeff Sharkey            if (entry.isNegative()) {
248b5a97e6f63bfe8b828224f606f8cb8585d9f28ecJeff Sharkey                if (mObserver != null) {
249b5a97e6f63bfe8b828224f606f8cb8585d9f28ecJeff Sharkey                    mObserver.foundNonMonotonic(delta, i, mCookie);
250b5a97e6f63bfe8b828224f606f8cb8585d9f28ecJeff Sharkey                }
251b5a97e6f63bfe8b828224f606f8cb8585d9f28ecJeff Sharkey                entry.rxBytes = Math.max(entry.rxBytes, 0);
252b5a97e6f63bfe8b828224f606f8cb8585d9f28ecJeff Sharkey                entry.rxPackets = Math.max(entry.rxPackets, 0);
253b5a97e6f63bfe8b828224f606f8cb8585d9f28ecJeff Sharkey                entry.txBytes = Math.max(entry.txBytes, 0);
254b5a97e6f63bfe8b828224f606f8cb8585d9f28ecJeff Sharkey                entry.txPackets = Math.max(entry.txPackets, 0);
255b5a97e6f63bfe8b828224f606f8cb8585d9f28ecJeff Sharkey                entry.operations = Math.max(entry.operations, 0);
256b5a97e6f63bfe8b828224f606f8cb8585d9f28ecJeff Sharkey            }
257b5a97e6f63bfe8b828224f606f8cb8585d9f28ecJeff Sharkey
25863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final NetworkIdentitySet ident = ifaceIdent.get(entry.iface);
25963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            if (ident == null) {
26063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                unknownIfaces.add(entry.iface);
26163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                continue;
26263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
26363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
264ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey            // skip when no delta occurred
26563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            if (entry.isEmpty()) continue;
26663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
26763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // only record tag data when requested
26863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            if ((entry.tag == TAG_NONE) != mOnlyTags) {
269cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado                if (mPending != null) {
270cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado                    mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
271cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado                }
27263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
27363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                // also record against boot stats when present
27463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                if (mSinceBoot != null) {
27563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    mSinceBoot.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
27663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                }
27763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
27863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                // also record against complete dataset when present
27963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                if (complete != null) {
28063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    complete.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
28163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                }
28263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
28363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
28463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
28563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mLastSnapshot = snapshot;
28663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
2871f8ea2dcd1ed3cde4b84fbb27b5a55b3fea7ff2aJeff Sharkey        if (LOGV && unknownIfaces.size() > 0) {
28863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats");
28963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
29063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
29163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
29263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
29363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Consider persisting any pending deltas, if they are beyond
29463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * {@link #mPersistThresholdBytes}.
29563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
29663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void maybePersistLocked(long currentTimeMillis) {
297cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        checkNotNull(mRotator, "missing FileRotator");
29863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final long pendingBytes = mPending.getTotalBytes();
29963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (pendingBytes >= mPersistThresholdBytes) {
30063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            forcePersistLocked(currentTimeMillis);
30163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        } else {
30263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mRotator.maybeRotate(currentTimeMillis);
30363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
30463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
30563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
30663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
30763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Force persisting any pending deltas.
30863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
30963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void forcePersistLocked(long currentTimeMillis) {
310cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        checkNotNull(mRotator, "missing FileRotator");
31163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (mPending.isDirty()) {
31263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
31363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            try {
31463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                mRotator.rewriteActive(mPendingRewriter, currentTimeMillis);
31563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                mRotator.maybeRotate(currentTimeMillis);
31663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                mPending.reset();
31763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            } catch (IOException e) {
31863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                Log.wtf(TAG, "problem persisting pending stats", e);
3196de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey                recoverFromWtf();
320e4984bea95a07dea0ef0259fefa1e52f0bbb1533Jeff Sharkey            } catch (OutOfMemoryError e) {
321e4984bea95a07dea0ef0259fefa1e52f0bbb1533Jeff Sharkey                Log.wtf(TAG, "problem persisting pending stats", e);
322e4984bea95a07dea0ef0259fefa1e52f0bbb1533Jeff Sharkey                recoverFromWtf();
32363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
32463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
32563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
32663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
32763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
32863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Remove the given UID from all {@link FileRotator} history, migrating it
32963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * to {@link TrafficStats#UID_REMOVED}.
33063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
331daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey    public void removeUidsLocked(int[] uids) {
332cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        if (mRotator != null) {
333cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado            try {
334cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado                // Rewrite all persisted data to migrate UID stats
335cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado                mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids));
336cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado            } catch (IOException e) {
337cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado                Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
338cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado                recoverFromWtf();
339cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado            } catch (OutOfMemoryError e) {
340cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado                Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
341cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado                recoverFromWtf();
342cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado            }
34363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
34463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
345daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey        // Remove any pending stats
346cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        if (mPending != null) {
347cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado            mPending.removeUids(uids);
348cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        }
349cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        if (mSinceBoot != null) {
350cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado            mSinceBoot.removeUids(uids);
351cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        }
352daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey
353daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey        // Clear UID from current stats snapshot
35463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (mLastSnapshot != null) {
355daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey            mLastSnapshot = mLastSnapshot.withoutUids(uids);
35663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
357b52e3e55098c4a6e3dbfe19885895411cfb38911Jeff Sharkey
358b52e3e55098c4a6e3dbfe19885895411cfb38911Jeff Sharkey        final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
359b52e3e55098c4a6e3dbfe19885895411cfb38911Jeff Sharkey        if (complete != null) {
360daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey            complete.removeUids(uids);
361b52e3e55098c4a6e3dbfe19885895411cfb38911Jeff Sharkey        }
36263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
36363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
36463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
36563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Rewriter that will combine current {@link NetworkStatsCollection} values
36663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * with anything read from disk, and write combined set to disk. Clears the
36763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * original {@link NetworkStatsCollection} when finished writing.
36863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
36963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static class CombiningRewriter implements FileRotator.Rewriter {
37063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        private final NetworkStatsCollection mCollection;
37163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
37263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public CombiningRewriter(NetworkStatsCollection collection) {
37363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mCollection = checkNotNull(collection, "missing NetworkStatsCollection");
37463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
37563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
376bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
37763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public void reset() {
37863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // ignored
37963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
38063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
381bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
38263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public void read(InputStream in) throws IOException {
38363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mCollection.read(in);
38463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
38563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
386bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
38763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public boolean shouldWrite() {
38863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            return true;
38963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
39063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
391bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
39263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public void write(OutputStream out) throws IOException {
39363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mCollection.write(new DataOutputStream(out));
39463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mCollection.reset();
39563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
39663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
39763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
39863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
39963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Rewriter that will remove any {@link NetworkStatsHistory} attributed to
40063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * the requested UID, only writing data back when modified.
40163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
40263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public static class RemoveUidRewriter implements FileRotator.Rewriter {
40363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        private final NetworkStatsCollection mTemp;
404daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey        private final int[] mUids;
40563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
406daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey        public RemoveUidRewriter(long bucketDuration, int[] uids) {
40763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mTemp = new NetworkStatsCollection(bucketDuration);
408daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey            mUids = uids;
40963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
41063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
411bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
41263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public void reset() {
41363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mTemp.reset();
41463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
41563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
416bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
41763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public void read(InputStream in) throws IOException {
41863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mTemp.read(in);
41963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mTemp.clearDirty();
420daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey            mTemp.removeUids(mUids);
42163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
42263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
423bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
42463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public boolean shouldWrite() {
42563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            return mTemp.isDirty();
42663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
42763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
428bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
42963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public void write(OutputStream out) throws IOException {
43063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mTemp.write(new DataOutputStream(out));
43163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
43263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
43363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
43463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void importLegacyNetworkLocked(File file) throws IOException {
435cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        checkNotNull(mRotator, "missing FileRotator");
436cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado
43763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // legacy file still exists; start empty to avoid double importing
43863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mRotator.deleteAll();
43963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
44063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
44163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        collection.readLegacyNetwork(file);
44263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
44363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final long startMillis = collection.getStartMillis();
44463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final long endMillis = collection.getEndMillis();
44563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
44663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (!collection.isEmpty()) {
44763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // process legacy data, creating active file at starting time, then
44863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // using end time to possibly trigger rotation.
44963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
45063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mRotator.maybeRotate(endMillis);
45163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
45263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
45363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
45463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void importLegacyUidLocked(File file) throws IOException {
455cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        checkNotNull(mRotator, "missing FileRotator");
456cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado
45763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // legacy file still exists; start empty to avoid double importing
45863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mRotator.deleteAll();
45963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
46063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
46163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        collection.readLegacyUid(file, mOnlyTags);
46263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
46363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final long startMillis = collection.getStartMillis();
46463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final long endMillis = collection.getEndMillis();
46563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
46663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (!collection.isEmpty()) {
46763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // process legacy data, creating active file at starting time, then
46863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // using end time to possibly trigger rotation.
46963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
47063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mRotator.maybeRotate(endMillis);
47163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
47263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
47363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
47463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) {
475cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        if (mPending != null) {
476cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado            pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes());
477cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado        }
47863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (fullHistory) {
47963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            pw.println("Complete history:");
48063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            getOrLoadCompleteLocked().dump(pw);
48163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        } else {
48263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            pw.println("History since boot:");
48363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mSinceBoot.dump(pw);
48463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
48563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
4866de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey
487da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki    public void writeToProtoLocked(ProtoOutputStream proto, long tag) {
488da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        final long start = proto.start(tag);
489da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        if (mPending != null) {
490da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes());
491da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        }
492da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        getOrLoadCompleteLocked().writeToProto(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY);
493da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        proto.end(start);
494da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki    }
495da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki
49655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    public void dumpCheckin(PrintWriter pw, long start, long end) {
49755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        // Only load and dump stats from the requested window
49855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end);
49955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    }
50055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey
5016de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey    /**
5026de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey     * Recover from {@link FileRotator} failure by dumping state to
5036de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey     * {@link DropBoxManager} and deleting contents.
5046de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey     */
5056de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey    private void recoverFromWtf() {
5066de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey        if (DUMP_BEFORE_DELETE) {
5076de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey            final ByteArrayOutputStream os = new ByteArrayOutputStream();
5086de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey            try {
5096de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey                mRotator.dumpAll(os);
5106de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey            } catch (IOException e) {
5116de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey                // ignore partial contents
5126de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey                os.reset();
5136de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey            } finally {
5146de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey                IoUtils.closeQuietly(os);
5156de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey            }
5166de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey            mDropBox.addData(TAG_NETSTATS_DUMP, os.toByteArray(), 0);
5176de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey        }
5186de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey
5196de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey        mRotator.deleteAll();
5206de357e4d10fa5977ab9a6c665dc858765e95d34Jeff Sharkey    }
52163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey}
522