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.IFACE_ALL;
2063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static android.net.NetworkStats.SET_ALL;
2163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static android.net.NetworkStats.SET_DEFAULT;
2263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static android.net.NetworkStats.TAG_NONE;
2363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static android.net.NetworkStats.UID_ALL;
2463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static android.net.TrafficStats.UID_REMOVED;
2563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
2663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkIdentity;
2763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkStats;
2863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkStatsHistory;
2963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkTemplate;
3063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.TrafficStats;
3163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.text.format.DateUtils;
3239606a007a5b1309dd000234f2b8cf156c49fd0fDianne Hackbornimport android.util.AtomicFile;
3363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
34daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkeyimport com.android.internal.util.ArrayUtils;
3563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.FileRotator;
3663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter;
3763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.Objects;
3863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.google.android.collect.Lists;
3963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.google.android.collect.Maps;
4063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
4163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.BufferedInputStream;
4263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.DataInputStream;
4363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.DataOutputStream;
4463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.File;
4563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.FileNotFoundException;
4663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.IOException;
4763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.InputStream;
4863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.net.ProtocolException;
4963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.util.ArrayList;
5063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.util.Collections;
5163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.util.HashMap;
5263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.util.Map;
5363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
5463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport libcore.io.IoUtils;
5563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
5663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey/**
5763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Collection of {@link NetworkStatsHistory}, stored based on combined key of
5863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * {@link NetworkIdentitySet}, UID, set, and tag. Knows how to persist itself.
5963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */
6063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeypublic class NetworkStatsCollection implements FileRotator.Reader {
6163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /** File header magic number: "ANET" */
6263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static final int FILE_MAGIC = 0x414E4554;
6363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
6463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static final int VERSION_NETWORK_INIT = 1;
6563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
6663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static final int VERSION_UID_INIT = 1;
6763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static final int VERSION_UID_WITH_IDENT = 2;
6863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static final int VERSION_UID_WITH_TAG = 3;
6963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static final int VERSION_UID_WITH_SET = 4;
7063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
7163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static final int VERSION_UNIFIED_INIT = 16;
7263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
7363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private HashMap<Key, NetworkStatsHistory> mStats = Maps.newHashMap();
7463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
7570c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    private final long mBucketDuration;
7663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
7763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private long mStartMillis;
7863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private long mEndMillis;
7963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private long mTotalBytes;
8063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private boolean mDirty;
8163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
8263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public NetworkStatsCollection(long bucketDuration) {
8363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mBucketDuration = bucketDuration;
8463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        reset();
8563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
8663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
8763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void reset() {
8863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mStats.clear();
8963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mStartMillis = Long.MAX_VALUE;
9063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mEndMillis = Long.MIN_VALUE;
9163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mTotalBytes = 0;
9263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mDirty = false;
9363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
9463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
9563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public long getStartMillis() {
9663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return mStartMillis;
9763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
9863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
9970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    /**
10070c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     * Return first atomic bucket in this collection, which is more conservative
10170c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     * than {@link #mStartMillis}.
10270c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     */
10370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    public long getFirstAtomicBucketMillis() {
10470c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        if (mStartMillis == Long.MAX_VALUE) {
10570c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            return Long.MAX_VALUE;
10670c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        } else {
10770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            return mStartMillis + mBucketDuration;
10870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        }
10970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    }
11070c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey
11163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public long getEndMillis() {
11263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return mEndMillis;
11363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
11463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
11563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public long getTotalBytes() {
11663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return mTotalBytes;
11763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
11863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
11963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public boolean isDirty() {
12063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return mDirty;
12163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
12263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
12363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void clearDirty() {
12463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mDirty = false;
12563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
12663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
12763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public boolean isEmpty() {
12863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE;
12963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
13063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
13163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
13263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Combine all {@link NetworkStatsHistory} in this collection which match
13363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * the requested parameters.
13463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
13563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public NetworkStatsHistory getHistory(
13663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            NetworkTemplate template, int uid, int set, int tag, int fields) {
13770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        return getHistory(template, uid, set, tag, fields, Long.MIN_VALUE, Long.MAX_VALUE);
13870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    }
13970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey
14070c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    /**
14170c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     * Combine all {@link NetworkStatsHistory} in this collection which match
14270c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     * the requested parameters.
14370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     */
14470c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    public NetworkStatsHistory getHistory(
14570c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) {
14663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final NetworkStatsHistory combined = new NetworkStatsHistory(
14763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                mBucketDuration, estimateBuckets(), fields);
14863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        for (Map.Entry<Key, NetworkStatsHistory> entry : mStats.entrySet()) {
14963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final Key key = entry.getKey();
15063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final boolean setMatches = set == SET_ALL || key.set == set;
15163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            if (key.uid == uid && setMatches && key.tag == tag
15263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    && templateMatches(template, key.ident)) {
15370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey                combined.recordHistory(entry.getValue(), start, end);
15463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
15563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
15663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return combined;
15763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
15863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
15963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
16063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Summarize all {@link NetworkStatsHistory} in this collection which match
16163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * the requested parameters.
16263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
16363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public NetworkStats getSummary(NetworkTemplate template, long start, long end) {
16463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final long now = System.currentTimeMillis();
16563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
16663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final NetworkStats stats = new NetworkStats(end - start, 24);
16763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final NetworkStats.Entry entry = new NetworkStats.Entry();
16863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        NetworkStatsHistory.Entry historyEntry = null;
16963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
17070c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        // shortcut when we know stats will be empty
17170c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        if (start == end) return stats;
17270c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey
17363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        for (Map.Entry<Key, NetworkStatsHistory> mapEntry : mStats.entrySet()) {
17463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final Key key = mapEntry.getKey();
17563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            if (templateMatches(template, key.ident)) {
17663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                final NetworkStatsHistory history = mapEntry.getValue();
17763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                historyEntry = history.getValues(start, end, now, historyEntry);
17863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
17963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                entry.iface = IFACE_ALL;
18063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                entry.uid = key.uid;
18163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                entry.set = key.set;
18263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                entry.tag = key.tag;
18363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                entry.rxBytes = historyEntry.rxBytes;
18463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                entry.rxPackets = historyEntry.rxPackets;
18563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                entry.txBytes = historyEntry.txBytes;
18663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                entry.txPackets = historyEntry.txPackets;
18763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                entry.operations = historyEntry.operations;
18863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
18963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                if (!entry.isEmpty()) {
19063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    stats.combineValues(entry);
19163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                }
19263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
19363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
19463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
19563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return stats;
19663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
19763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
19863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
199bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey     * Record given {@link android.net.NetworkStats.Entry} into this collection.
20063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
20163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void recordData(NetworkIdentitySet ident, int uid, int set, int tag, long start,
20263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            long end, NetworkStats.Entry entry) {
20370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        final NetworkStatsHistory history = findOrCreateHistory(ident, uid, set, tag);
20470c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        history.recordData(start, end, entry);
20570c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        noteRecordedHistory(history.getStart(), history.getEnd(), entry.rxBytes + entry.txBytes);
20663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
20763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
20863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
20963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Record given {@link NetworkStatsHistory} into this collection.
21063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
21163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private void recordHistory(Key key, NetworkStatsHistory history) {
21263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (history.size() == 0) return;
21363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        noteRecordedHistory(history.getStart(), history.getEnd(), history.getTotalBytes());
21463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
215ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey        NetworkStatsHistory target = mStats.get(key);
216ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey        if (target == null) {
217ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey            target = new NetworkStatsHistory(history.getBucketDuration());
218ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey            mStats.put(key, target);
21963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
220ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey        target.recordEntireHistory(history);
22163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
22263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
22363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
22463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Record all {@link NetworkStatsHistory} contained in the given collection
22563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * into this collection.
22663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
22763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void recordCollection(NetworkStatsCollection another) {
22863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        for (Map.Entry<Key, NetworkStatsHistory> entry : another.mStats.entrySet()) {
22963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            recordHistory(entry.getKey(), entry.getValue());
23063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
23163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
23263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
23363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private NetworkStatsHistory findOrCreateHistory(
23463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            NetworkIdentitySet ident, int uid, int set, int tag) {
23563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final Key key = new Key(ident, uid, set, tag);
23663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final NetworkStatsHistory existing = mStats.get(key);
23763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
23863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // update when no existing, or when bucket duration changed
23963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        NetworkStatsHistory updated = null;
24063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (existing == null) {
24163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            updated = new NetworkStatsHistory(mBucketDuration, 10);
24263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        } else if (existing.getBucketDuration() != mBucketDuration) {
24363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            updated = new NetworkStatsHistory(existing, mBucketDuration);
24463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
24563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
24663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (updated != null) {
24763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            mStats.put(key, updated);
24863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            return updated;
24963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        } else {
25063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            return existing;
25163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
25263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
25363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
254bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey    @Override
25563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void read(InputStream in) throws IOException {
25663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        read(new DataInputStream(in));
25763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
25863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
25963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void read(DataInputStream in) throws IOException {
26063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // verify file magic header intact
26163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final int magic = in.readInt();
26263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (magic != FILE_MAGIC) {
26363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            throw new ProtocolException("unexpected magic: " + magic);
26463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
26563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
26663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final int version = in.readInt();
26763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        switch (version) {
26863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            case VERSION_UNIFIED_INIT: {
26963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory))
27063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                final int identSize = in.readInt();
27163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                for (int i = 0; i < identSize; i++) {
27263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    final NetworkIdentitySet ident = new NetworkIdentitySet(in);
27363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
27463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    final int size = in.readInt();
27563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    for (int j = 0; j < size; j++) {
27663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        final int uid = in.readInt();
27763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        final int set = in.readInt();
27863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        final int tag = in.readInt();
27963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
28063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        final Key key = new Key(ident, uid, set, tag);
28163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        final NetworkStatsHistory history = new NetworkStatsHistory(in);
28263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        recordHistory(key, history);
28363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    }
28463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                }
28563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                break;
28663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
28763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            default: {
28863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                throw new ProtocolException("unexpected version: " + version);
28963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
29063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
29163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
29263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
29363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void write(DataOutputStream out) throws IOException {
29463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // cluster key lists grouped by ident
29563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final HashMap<NetworkIdentitySet, ArrayList<Key>> keysByIdent = Maps.newHashMap();
29663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        for (Key key : mStats.keySet()) {
29763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            ArrayList<Key> keys = keysByIdent.get(key.ident);
29863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            if (keys == null) {
29963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                keys = Lists.newArrayList();
30063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                keysByIdent.put(key.ident, keys);
30163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
30263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            keys.add(key);
30363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
30463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
30563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        out.writeInt(FILE_MAGIC);
30663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        out.writeInt(VERSION_UNIFIED_INIT);
30763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
30863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        out.writeInt(keysByIdent.size());
30963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        for (NetworkIdentitySet ident : keysByIdent.keySet()) {
31063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final ArrayList<Key> keys = keysByIdent.get(ident);
31163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            ident.writeToStream(out);
31263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
31363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            out.writeInt(keys.size());
31463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            for (Key key : keys) {
31563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                final NetworkStatsHistory history = mStats.get(key);
31663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                out.writeInt(key.uid);
31763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                out.writeInt(key.set);
31863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                out.writeInt(key.tag);
31963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                history.writeToStream(out);
32063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
32163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
32263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
32363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        out.flush();
32463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
32563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
32663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    @Deprecated
32763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void readLegacyNetwork(File file) throws IOException {
32863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final AtomicFile inputFile = new AtomicFile(file);
32963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
33063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        DataInputStream in = null;
33163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        try {
33263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            in = new DataInputStream(new BufferedInputStream(inputFile.openRead()));
33363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
33463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // verify file magic header intact
33563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final int magic = in.readInt();
33663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            if (magic != FILE_MAGIC) {
33763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                throw new ProtocolException("unexpected magic: " + magic);
33863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
33963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
34063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final int version = in.readInt();
34163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            switch (version) {
34263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                case VERSION_NETWORK_INIT: {
34363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    // network := size *(NetworkIdentitySet NetworkStatsHistory)
34463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    final int size = in.readInt();
34563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    for (int i = 0; i < size; i++) {
34663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        final NetworkIdentitySet ident = new NetworkIdentitySet(in);
34763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        final NetworkStatsHistory history = new NetworkStatsHistory(in);
34863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
34963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        final Key key = new Key(ident, UID_ALL, SET_ALL, TAG_NONE);
35063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        recordHistory(key, history);
35163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    }
35263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    break;
35363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                }
35463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                default: {
35563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    throw new ProtocolException("unexpected version: " + version);
35663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                }
35763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
35863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        } catch (FileNotFoundException e) {
35963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // missing stats is okay, probably first boot
36063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        } finally {
36163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            IoUtils.closeQuietly(in);
36263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
36363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
36463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
36563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    @Deprecated
36663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void readLegacyUid(File file, boolean onlyTags) throws IOException {
36763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final AtomicFile inputFile = new AtomicFile(file);
36863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
36963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        DataInputStream in = null;
37063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        try {
37163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            in = new DataInputStream(new BufferedInputStream(inputFile.openRead()));
37263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
37363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // verify file magic header intact
37463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final int magic = in.readInt();
37563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            if (magic != FILE_MAGIC) {
37663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                throw new ProtocolException("unexpected magic: " + magic);
37763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
37863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
37963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final int version = in.readInt();
38063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            switch (version) {
38163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                case VERSION_UID_INIT: {
38263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    // uid := size *(UID NetworkStatsHistory)
38363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
38463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    // drop this data version, since we don't have a good
38563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    // mapping into NetworkIdentitySet.
38663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    break;
38763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                }
38863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                case VERSION_UID_WITH_IDENT: {
38963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory))
39063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
39163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    // drop this data version, since this version only existed
39263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    // for a short time.
39363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    break;
39463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                }
39563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                case VERSION_UID_WITH_TAG:
39663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                case VERSION_UID_WITH_SET: {
39763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory))
39863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    final int identSize = in.readInt();
39963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    for (int i = 0; i < identSize; i++) {
40063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        final NetworkIdentitySet ident = new NetworkIdentitySet(in);
40163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
40263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        final int size = in.readInt();
40363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        for (int j = 0; j < size; j++) {
40463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                            final int uid = in.readInt();
40563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                            final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt()
40663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                                    : SET_DEFAULT;
40763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                            final int tag = in.readInt();
40863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
40963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                            final Key key = new Key(ident, uid, set, tag);
41063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                            final NetworkStatsHistory history = new NetworkStatsHistory(in);
41163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
41263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                            if ((tag == TAG_NONE) != onlyTags) {
41363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                                recordHistory(key, history);
41463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                            }
41563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        }
41663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    }
41763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    break;
41863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                }
41963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                default: {
42063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    throw new ProtocolException("unexpected version: " + version);
42163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                }
42263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
42363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        } catch (FileNotFoundException e) {
42463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // missing stats is okay, probably first boot
42563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        } finally {
42663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            IoUtils.closeQuietly(in);
42763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
42863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
42963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
43063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
43163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Remove any {@link NetworkStatsHistory} attributed to the requested UID,
43263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * moving any {@link NetworkStats#TAG_NONE} series to
43363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * {@link TrafficStats#UID_REMOVED}.
43463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
435daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey    public void removeUids(int[] uids) {
43663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final ArrayList<Key> knownKeys = Lists.newArrayList();
43763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        knownKeys.addAll(mStats.keySet());
43863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
43963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        // migrate all UID stats into special "removed" bucket
44063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        for (Key key : knownKeys) {
441daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey            if (ArrayUtils.contains(uids, key.uid)) {
44263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                // only migrate combined TAG_NONE history
44363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                if (key.tag == TAG_NONE) {
44463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    final NetworkStatsHistory uidHistory = mStats.get(key);
44563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    final NetworkStatsHistory removedHistory = findOrCreateHistory(
44663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                            key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE);
44763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    removedHistory.recordEntireHistory(uidHistory);
44863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                }
44963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                mStats.remove(key);
45063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                mDirty = true;
45163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
45263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
45363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
45463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
45563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private void noteRecordedHistory(long startMillis, long endMillis, long totalBytes) {
45663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (startMillis < mStartMillis) mStartMillis = startMillis;
45763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (endMillis > mEndMillis) mEndMillis = endMillis;
45863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mTotalBytes += totalBytes;
45963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        mDirty = true;
46063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
46163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
46263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private int estimateBuckets() {
46363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return (int) (Math.min(mEndMillis - mStartMillis, DateUtils.WEEK_IN_MILLIS * 5)
46463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                / mBucketDuration);
46563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
46663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
46763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void dump(IndentingPrintWriter pw) {
46863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        final ArrayList<Key> keys = Lists.newArrayList();
46963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        keys.addAll(mStats.keySet());
47063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        Collections.sort(keys);
47163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
47263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        for (Key key : keys) {
47363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            pw.print("ident="); pw.print(key.ident.toString());
47463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            pw.print(" uid="); pw.print(key.uid);
47563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            pw.print(" set="); pw.print(NetworkStats.setToString(key.set));
47663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag));
47763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
47863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final NetworkStatsHistory history = mStats.get(key);
47963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            pw.increaseIndent();
48063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            history.dump(pw, true);
48163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            pw.decreaseIndent();
48263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
48363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
48463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
48563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
48663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
48763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * in the given {@link NetworkIdentitySet}.
48863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
48963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) {
49063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        for (NetworkIdentity ident : identSet) {
49163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            if (template.matches(ident)) {
49263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                return true;
49363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
49463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
49563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return false;
49663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
49763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
49863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private static class Key implements Comparable<Key> {
49963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public final NetworkIdentitySet ident;
50063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public final int uid;
50163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public final int set;
50263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public final int tag;
50363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
50463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        private final int hashCode;
50563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
50663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public Key(NetworkIdentitySet ident, int uid, int set, int tag) {
50763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            this.ident = ident;
50863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            this.uid = uid;
50963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            this.set = set;
51063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            this.tag = tag;
51163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            hashCode = Objects.hashCode(ident, uid, set, tag);
51263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
51363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
51463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        @Override
51563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public int hashCode() {
51663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            return hashCode;
51763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
51863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
51963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        @Override
52063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public boolean equals(Object obj) {
52163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            if (obj instanceof Key) {
52263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                final Key key = (Key) obj;
52363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                return uid == key.uid && set == key.set && tag == key.tag
52463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        && Objects.equal(ident, key.ident);
52563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            }
52663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            return false;
52763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
52863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
529bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
53063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public int compareTo(Key another) {
53163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            return Integer.compare(uid, another.uid);
53263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
53363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
53463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey}
535