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; 2555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkeyimport static android.text.format.DateUtils.SECOND_IN_MILLIS; 2655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkeyimport static android.text.format.DateUtils.WEEK_IN_MILLIS; 2763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 2855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkeyimport android.net.ConnectivityManager; 2963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkIdentity; 3063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkStats; 3163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkStatsHistory; 3263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkTemplate; 3363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.TrafficStats; 3455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkeyimport android.util.ArrayMap; 3539606a007a5b1309dd000234f2b8cf156c49fd0fDianne Hackbornimport android.util.AtomicFile; 3663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 3755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkeyimport libcore.io.IoUtils; 3855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 39daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkeyimport com.android.internal.util.ArrayUtils; 4063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.FileRotator; 4163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter; 4263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.google.android.collect.Lists; 4363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.google.android.collect.Maps; 4463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 4563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.BufferedInputStream; 4663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.DataInputStream; 4763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.DataOutputStream; 4863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.File; 4963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.FileNotFoundException; 5063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.IOException; 5163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.InputStream; 5255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkeyimport java.io.PrintWriter; 5363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.net.ProtocolException; 5463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.util.ArrayList; 5563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.util.Collections; 5663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.util.HashMap; 57e6585b32ea586743258a5457e2184ffc087f2d2fKenny Rootimport java.util.Objects; 5863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 5963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey/** 6063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Collection of {@link NetworkStatsHistory}, stored based on combined key of 6163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * {@link NetworkIdentitySet}, UID, set, and tag. Knows how to persist itself. 6263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 6363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeypublic class NetworkStatsCollection implements FileRotator.Reader { 6463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** File header magic number: "ANET" */ 6563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static final int FILE_MAGIC = 0x414E4554; 6663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 6763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static final int VERSION_NETWORK_INIT = 1; 6863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 6963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static final int VERSION_UID_INIT = 1; 7063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static final int VERSION_UID_WITH_IDENT = 2; 7163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static final int VERSION_UID_WITH_TAG = 3; 7263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static final int VERSION_UID_WITH_SET = 4; 7363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 7463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static final int VERSION_UNIFIED_INIT = 16; 7563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 7655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey private ArrayMap<Key, NetworkStatsHistory> mStats = new ArrayMap<>(); 7763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 7870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey private final long mBucketDuration; 7963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 8063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private long mStartMillis; 8163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private long mEndMillis; 8263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private long mTotalBytes; 8363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private boolean mDirty; 8463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 8563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public NetworkStatsCollection(long bucketDuration) { 8663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mBucketDuration = bucketDuration; 8763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey reset(); 8863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 8963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 9063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void reset() { 9163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mStats.clear(); 9263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mStartMillis = Long.MAX_VALUE; 9363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mEndMillis = Long.MIN_VALUE; 9463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mTotalBytes = 0; 9563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mDirty = false; 9663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 9763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 9863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public long getStartMillis() { 9963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return mStartMillis; 10063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 10163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 10270c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey /** 10370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey * Return first atomic bucket in this collection, which is more conservative 10470c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey * than {@link #mStartMillis}. 10570c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey */ 10670c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey public long getFirstAtomicBucketMillis() { 10770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey if (mStartMillis == Long.MAX_VALUE) { 10870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey return Long.MAX_VALUE; 10970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey } else { 11070c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey return mStartMillis + mBucketDuration; 11170c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey } 11270c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey } 11370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey 11463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public long getEndMillis() { 11563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return mEndMillis; 11663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 11763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 11863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public long getTotalBytes() { 11963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return mTotalBytes; 12063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 12163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 12263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public boolean isDirty() { 12363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return mDirty; 12463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 12563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 12663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void clearDirty() { 12763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mDirty = false; 12863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 12963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 13063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public boolean isEmpty() { 13163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE; 13263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 13363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 13463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 13563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Combine all {@link NetworkStatsHistory} in this collection which match 13663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * the requested parameters. 13763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 13863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public NetworkStatsHistory getHistory( 13963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey NetworkTemplate template, int uid, int set, int tag, int fields) { 14070c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey return getHistory(template, uid, set, tag, fields, Long.MIN_VALUE, Long.MAX_VALUE); 14170c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey } 14270c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey 14370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey /** 14470c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey * Combine all {@link NetworkStatsHistory} in this collection which match 14570c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey * the requested parameters. 14670c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey */ 14770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey public NetworkStatsHistory getHistory( 14870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) { 14963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory combined = new NetworkStatsHistory( 15063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mBucketDuration, estimateBuckets(), fields); 15155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey for (int i = 0; i < mStats.size(); i++) { 15255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final Key key = mStats.keyAt(i); 15363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final boolean setMatches = set == SET_ALL || key.set == set; 15463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (key.uid == uid && setMatches && key.tag == tag 15563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey && templateMatches(template, key.ident)) { 15655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final NetworkStatsHistory value = mStats.valueAt(i); 15755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey combined.recordHistory(value, start, end); 15863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 15963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 16063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return combined; 16163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 16263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 16363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 16463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Summarize all {@link NetworkStatsHistory} in this collection which match 16563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * the requested parameters. 16663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 16763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public NetworkStats getSummary(NetworkTemplate template, long start, long end) { 16863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final long now = System.currentTimeMillis(); 16963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 17063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStats stats = new NetworkStats(end - start, 24); 17163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStats.Entry entry = new NetworkStats.Entry(); 17263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey NetworkStatsHistory.Entry historyEntry = null; 17363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 17470c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey // shortcut when we know stats will be empty 17570c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey if (start == end) return stats; 17670c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey 17755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey for (int i = 0; i < mStats.size(); i++) { 17855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final Key key = mStats.keyAt(i); 17963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (templateMatches(template, key.ident)) { 18055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final NetworkStatsHistory value = mStats.valueAt(i); 18155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey historyEntry = value.getValues(start, end, now, historyEntry); 18263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 18363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.iface = IFACE_ALL; 18463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.uid = key.uid; 18563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.set = key.set; 18663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.tag = key.tag; 18763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.rxBytes = historyEntry.rxBytes; 18863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.rxPackets = historyEntry.rxPackets; 18963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.txBytes = historyEntry.txBytes; 19063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.txPackets = historyEntry.txPackets; 19163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.operations = historyEntry.operations; 19263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 19363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (!entry.isEmpty()) { 19463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey stats.combineValues(entry); 19563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 19663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 19763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 19863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 19963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return stats; 20063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 20163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 20263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 203bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey * Record given {@link android.net.NetworkStats.Entry} into this collection. 20463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 20563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void recordData(NetworkIdentitySet ident, int uid, int set, int tag, long start, 20663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey long end, NetworkStats.Entry entry) { 20770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey final NetworkStatsHistory history = findOrCreateHistory(ident, uid, set, tag); 20870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey history.recordData(start, end, entry); 20970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey noteRecordedHistory(history.getStart(), history.getEnd(), entry.rxBytes + entry.txBytes); 21063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 21163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 21263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 21363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Record given {@link NetworkStatsHistory} into this collection. 21463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 21563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private void recordHistory(Key key, NetworkStatsHistory history) { 21663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (history.size() == 0) return; 21763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey noteRecordedHistory(history.getStart(), history.getEnd(), history.getTotalBytes()); 21863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 219ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey NetworkStatsHistory target = mStats.get(key); 220ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey if (target == null) { 221ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey target = new NetworkStatsHistory(history.getBucketDuration()); 222ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey mStats.put(key, target); 22363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 224ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey target.recordEntireHistory(history); 22563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 22663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 22763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 22863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Record all {@link NetworkStatsHistory} contained in the given collection 22963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * into this collection. 23063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 23163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void recordCollection(NetworkStatsCollection another) { 23255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey for (int i = 0; i < another.mStats.size(); i++) { 23355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final Key key = another.mStats.keyAt(i); 23455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final NetworkStatsHistory value = another.mStats.valueAt(i); 23555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey recordHistory(key, value); 23663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 23763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 23863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 23963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private NetworkStatsHistory findOrCreateHistory( 24063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey NetworkIdentitySet ident, int uid, int set, int tag) { 24163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final Key key = new Key(ident, uid, set, tag); 24263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory existing = mStats.get(key); 24363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 24463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // update when no existing, or when bucket duration changed 24563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey NetworkStatsHistory updated = null; 24663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (existing == null) { 24763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey updated = new NetworkStatsHistory(mBucketDuration, 10); 24863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } else if (existing.getBucketDuration() != mBucketDuration) { 24963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey updated = new NetworkStatsHistory(existing, mBucketDuration); 25063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 25163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 25263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (updated != null) { 25363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mStats.put(key, updated); 25463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return updated; 25563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } else { 25663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return existing; 25763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 25863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 25963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 260bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey @Override 26163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void read(InputStream in) throws IOException { 26263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey read(new DataInputStream(in)); 26363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 26463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 26563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void read(DataInputStream in) throws IOException { 26663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // verify file magic header intact 26763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int magic = in.readInt(); 26863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (magic != FILE_MAGIC) { 26963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey throw new ProtocolException("unexpected magic: " + magic); 27063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 27163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 27263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int version = in.readInt(); 27363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey switch (version) { 27463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey case VERSION_UNIFIED_INIT: { 27563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory)) 27663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int identSize = in.readInt(); 27763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (int i = 0; i < identSize; i++) { 27863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkIdentitySet ident = new NetworkIdentitySet(in); 27963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 28063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int size = in.readInt(); 28163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (int j = 0; j < size; j++) { 28263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int uid = in.readInt(); 28363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int set = in.readInt(); 28463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int tag = in.readInt(); 28563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 28663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final Key key = new Key(ident, uid, set, tag); 28763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory history = new NetworkStatsHistory(in); 28863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey recordHistory(key, history); 28963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 29063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 29163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey break; 29263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 29363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey default: { 29463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey throw new ProtocolException("unexpected version: " + version); 29563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 29663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 29763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 29863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 29963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void write(DataOutputStream out) throws IOException { 30063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // cluster key lists grouped by ident 30163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final HashMap<NetworkIdentitySet, ArrayList<Key>> keysByIdent = Maps.newHashMap(); 30263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (Key key : mStats.keySet()) { 30363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey ArrayList<Key> keys = keysByIdent.get(key.ident); 30463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (keys == null) { 30563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey keys = Lists.newArrayList(); 30663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey keysByIdent.put(key.ident, keys); 30763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 30863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey keys.add(key); 30963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 31063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 31163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey out.writeInt(FILE_MAGIC); 31263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey out.writeInt(VERSION_UNIFIED_INIT); 31363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 31463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey out.writeInt(keysByIdent.size()); 31563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (NetworkIdentitySet ident : keysByIdent.keySet()) { 31663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final ArrayList<Key> keys = keysByIdent.get(ident); 31763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey ident.writeToStream(out); 31863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 31963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey out.writeInt(keys.size()); 32063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (Key key : keys) { 32163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory history = mStats.get(key); 32263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey out.writeInt(key.uid); 32363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey out.writeInt(key.set); 32463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey out.writeInt(key.tag); 32563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey history.writeToStream(out); 32663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 32763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 32863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 32963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey out.flush(); 33063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 33163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 33263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey @Deprecated 33363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void readLegacyNetwork(File file) throws IOException { 33463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final AtomicFile inputFile = new AtomicFile(file); 33563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 33663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey DataInputStream in = null; 33763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey try { 33863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey in = new DataInputStream(new BufferedInputStream(inputFile.openRead())); 33963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 34063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // verify file magic header intact 34163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int magic = in.readInt(); 34263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (magic != FILE_MAGIC) { 34363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey throw new ProtocolException("unexpected magic: " + magic); 34463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 34563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 34663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int version = in.readInt(); 34763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey switch (version) { 34863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey case VERSION_NETWORK_INIT: { 34963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // network := size *(NetworkIdentitySet NetworkStatsHistory) 35063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int size = in.readInt(); 35163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (int i = 0; i < size; i++) { 35263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkIdentitySet ident = new NetworkIdentitySet(in); 35363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory history = new NetworkStatsHistory(in); 35463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 35563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final Key key = new Key(ident, UID_ALL, SET_ALL, TAG_NONE); 35663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey recordHistory(key, history); 35763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 35863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey break; 35963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 36063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey default: { 36163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey throw new ProtocolException("unexpected version: " + version); 36263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 36363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 36463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } catch (FileNotFoundException e) { 36563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // missing stats is okay, probably first boot 36663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } finally { 36763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey IoUtils.closeQuietly(in); 36863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 36963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 37063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 37163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey @Deprecated 37263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void readLegacyUid(File file, boolean onlyTags) throws IOException { 37363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final AtomicFile inputFile = new AtomicFile(file); 37463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 37563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey DataInputStream in = null; 37663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey try { 37763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey in = new DataInputStream(new BufferedInputStream(inputFile.openRead())); 37863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 37963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // verify file magic header intact 38063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int magic = in.readInt(); 38163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (magic != FILE_MAGIC) { 38263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey throw new ProtocolException("unexpected magic: " + magic); 38363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 38463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 38563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int version = in.readInt(); 38663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey switch (version) { 38763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey case VERSION_UID_INIT: { 38863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // uid := size *(UID NetworkStatsHistory) 38963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 39063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // drop this data version, since we don't have a good 39163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // mapping into NetworkIdentitySet. 39263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey break; 39363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 39463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey case VERSION_UID_WITH_IDENT: { 39563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory)) 39663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 39763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // drop this data version, since this version only existed 39863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // for a short time. 39963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey break; 40063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 40163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey case VERSION_UID_WITH_TAG: 40263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey case VERSION_UID_WITH_SET: { 40363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory)) 40463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int identSize = in.readInt(); 40563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (int i = 0; i < identSize; i++) { 40663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkIdentitySet ident = new NetworkIdentitySet(in); 40763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 40863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int size = in.readInt(); 40963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (int j = 0; j < size; j++) { 41063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int uid = in.readInt(); 41163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt() 41263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey : SET_DEFAULT; 41363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int tag = in.readInt(); 41463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 41563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final Key key = new Key(ident, uid, set, tag); 41663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory history = new NetworkStatsHistory(in); 41763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 41863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if ((tag == TAG_NONE) != onlyTags) { 41963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey recordHistory(key, history); 42063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 42163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 42263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 42363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey break; 42463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 42563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey default: { 42663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey throw new ProtocolException("unexpected version: " + version); 42763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 42863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 42963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } catch (FileNotFoundException e) { 43063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // missing stats is okay, probably first boot 43163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } finally { 43263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey IoUtils.closeQuietly(in); 43363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 43463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 43563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 43663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 43763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Remove any {@link NetworkStatsHistory} attributed to the requested UID, 43863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * moving any {@link NetworkStats#TAG_NONE} series to 43963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * {@link TrafficStats#UID_REMOVED}. 44063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 441daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey public void removeUids(int[] uids) { 44263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final ArrayList<Key> knownKeys = Lists.newArrayList(); 44363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey knownKeys.addAll(mStats.keySet()); 44463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 44563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // migrate all UID stats into special "removed" bucket 44663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (Key key : knownKeys) { 447daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey if (ArrayUtils.contains(uids, key.uid)) { 44863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // only migrate combined TAG_NONE history 44963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (key.tag == TAG_NONE) { 45063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory uidHistory = mStats.get(key); 45163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory removedHistory = findOrCreateHistory( 45263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE); 45363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey removedHistory.recordEntireHistory(uidHistory); 45463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 45563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mStats.remove(key); 45663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mDirty = true; 45763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 45863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 45963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 46063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 46163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private void noteRecordedHistory(long startMillis, long endMillis, long totalBytes) { 46263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (startMillis < mStartMillis) mStartMillis = startMillis; 46363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (endMillis > mEndMillis) mEndMillis = endMillis; 46463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mTotalBytes += totalBytes; 46563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mDirty = true; 46663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 46763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 46863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private int estimateBuckets() { 46955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey return (int) (Math.min(mEndMillis - mStartMillis, WEEK_IN_MILLIS * 5) 47063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey / mBucketDuration); 47163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 47263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 47363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void dump(IndentingPrintWriter pw) { 47463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final ArrayList<Key> keys = Lists.newArrayList(); 47563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey keys.addAll(mStats.keySet()); 47663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey Collections.sort(keys); 47763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 47863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (Key key : keys) { 47963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey pw.print("ident="); pw.print(key.ident.toString()); 48063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey pw.print(" uid="); pw.print(key.uid); 48163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey pw.print(" set="); pw.print(NetworkStats.setToString(key.set)); 48263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag)); 48363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 48463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory history = mStats.get(key); 48563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey pw.increaseIndent(); 48663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey history.dump(pw, true); 48763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey pw.decreaseIndent(); 48863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 48963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 49063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 49155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey public void dumpCheckin(PrintWriter pw, long start, long end) { 49255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateMobileWildcard(), "cell"); 49355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateWifiWildcard(), "wifi"); 49455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateEthernet(), "eth"); 49555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateBluetooth(), "bt"); 49655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 49755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 49855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey /** 49955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey * Dump all contained stats that match requested parameters, but group 50055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey * together all matching {@link NetworkTemplate} under a single prefix. 50155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey */ 50255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey private void dumpCheckin(PrintWriter pw, long start, long end, NetworkTemplate groupTemplate, 50355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey String groupPrefix) { 50455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final ArrayMap<Key, NetworkStatsHistory> grouped = new ArrayMap<>(); 50555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 50655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey // Walk through all history, grouping by matching network templates 50755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey for (int i = 0; i < mStats.size(); i++) { 50855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final Key key = mStats.keyAt(i); 50955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final NetworkStatsHistory value = mStats.valueAt(i); 51055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 51155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey if (!templateMatches(groupTemplate, key.ident)) continue; 51255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 51355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final Key groupKey = new Key(null, key.uid, key.set, key.tag); 51455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey NetworkStatsHistory groupHistory = grouped.get(groupKey); 51555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey if (groupHistory == null) { 51655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey groupHistory = new NetworkStatsHistory(value.getBucketDuration()); 51755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey grouped.put(groupKey, groupHistory); 51855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 51955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey groupHistory.recordHistory(value, start, end); 52055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 52155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 52255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey for (int i = 0; i < grouped.size(); i++) { 52355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final Key key = grouped.keyAt(i); 52455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final NetworkStatsHistory value = grouped.valueAt(i); 52555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 52655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey if (value.size() == 0) continue; 52755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 52855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey pw.print("c,"); 52955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey pw.print(groupPrefix); pw.print(','); 53055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey pw.print(key.uid); pw.print(','); 53155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey pw.print(NetworkStats.setToCheckinString(key.set)); pw.print(','); 53255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey pw.print(key.tag); 53355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey pw.println(); 53455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 53555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey value.dumpCheckin(pw); 53655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 53755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 53855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 53963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 54063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity} 54163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * in the given {@link NetworkIdentitySet}. 54263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 54363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) { 54463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (NetworkIdentity ident : identSet) { 54563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (template.matches(ident)) { 54663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return true; 54763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 54863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 54963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return false; 55063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 55163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 55263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static class Key implements Comparable<Key> { 55363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public final NetworkIdentitySet ident; 55463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public final int uid; 55563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public final int set; 55663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public final int tag; 55763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 55863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private final int hashCode; 55963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 56063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public Key(NetworkIdentitySet ident, int uid, int set, int tag) { 56163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey this.ident = ident; 56263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey this.uid = uid; 56363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey this.set = set; 56463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey this.tag = tag; 565e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root hashCode = Objects.hash(ident, uid, set, tag); 56663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 56763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 56863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey @Override 56963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public int hashCode() { 57063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return hashCode; 57163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 57263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 57363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey @Override 57463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public boolean equals(Object obj) { 57563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (obj instanceof Key) { 57663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final Key key = (Key) obj; 57763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return uid == key.uid && set == key.set && tag == key.tag 578e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root && Objects.equals(ident, key.ident); 57963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 58063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return false; 58163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 58263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 583bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey @Override 58463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public int compareTo(Key another) { 58555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey int res = 0; 58655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey if (ident != null && another.ident != null) { 58755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey res = ident.compareTo(another.ident); 58855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 58955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey if (res == 0) { 59055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey res = Integer.compare(uid, another.uid); 59155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 59255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey if (res == 0) { 59355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey res = Integer.compare(set, another.set); 59455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 59555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey if (res == 0) { 59655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey res = Integer.compare(tag, another.tag); 59755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 59855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey return res; 59963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 60063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 60163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey} 602