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 19d3e4a1e250194bbf59b1e04b60711f97001f61f8Lorenzo Colittiimport static android.net.NetworkStats.DEFAULT_NETWORK_NO; 20ada23ed56addb7c06a489c7464ae228a46588b95Lorenzo Colittiimport static android.net.NetworkStats.DEFAULT_NETWORK_YES; 21090c462be959aff120498828f82df8732bf319beJeff Sharkeyimport static android.net.NetworkStats.IFACE_ALL; 2225147878974f82f875062e99cdee85dd33f3f078Stephen Chenimport static android.net.NetworkStats.METERED_NO; 2325147878974f82f875062e99cdee85dd33f3f078Stephen Chenimport static android.net.NetworkStats.METERED_YES; 241f7e05eda687279ac9deb894f42ac927bd471ad2Jeff Davidsonimport static android.net.NetworkStats.ROAMING_NO; 251f7e05eda687279ac9deb894f42ac927bd471ad2Jeff Davidsonimport static android.net.NetworkStats.ROAMING_YES; 2663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static android.net.NetworkStats.SET_ALL; 2763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static android.net.NetworkStats.SET_DEFAULT; 2863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static android.net.NetworkStats.TAG_NONE; 2963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static android.net.NetworkStats.UID_ALL; 3063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static android.net.TrafficStats.UID_REMOVED; 3155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkeyimport static android.text.format.DateUtils.WEEK_IN_MILLIS; 3263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 33f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport static com.android.server.net.NetworkStatsService.TAG; 34f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey 3563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkIdentity; 3663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkStats; 3763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkStatsHistory; 3863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.NetworkTemplate; 3963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport android.net.TrafficStats; 409c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Banimport android.os.Binder; 41da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onukiimport android.service.NetworkStatsCollectionKeyProto; 42da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onukiimport android.service.NetworkStatsCollectionProto; 43da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onukiimport android.service.NetworkStatsCollectionStatsProto; 44f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport android.telephony.SubscriptionPlan; 45090c462be959aff120498828f82df8732bf319beJeff Sharkeyimport android.text.format.DateUtils; 4655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkeyimport android.util.ArrayMap; 4739606a007a5b1309dd000234f2b8cf156c49fd0fDianne Hackbornimport android.util.AtomicFile; 489c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Banimport android.util.IntArray; 49090c462be959aff120498828f82df8732bf319beJeff Sharkeyimport android.util.MathUtils; 500fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkeyimport android.util.Range; 51f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport android.util.Slog; 52da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onukiimport android.util.proto.ProtoOutputStream; 5363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 54f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport com.android.internal.annotations.VisibleForTesting; 55daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkeyimport com.android.internal.util.ArrayUtils; 5663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.FileRotator; 5763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter; 589c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban 59f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport libcore.io.IoUtils; 60f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey 6163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.google.android.collect.Lists; 6263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.google.android.collect.Maps; 6363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 6463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.BufferedInputStream; 6563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.DataInputStream; 6663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.DataOutputStream; 6763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.File; 6863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.FileNotFoundException; 6963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.IOException; 7063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.io.InputStream; 7155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkeyimport java.io.PrintWriter; 7263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.net.ProtocolException; 73f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport java.time.ZonedDateTime; 7463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.util.ArrayList; 7563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.util.Collections; 7663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport java.util.HashMap; 77f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkeyimport java.util.Iterator; 78e6585b32ea586743258a5457e2184ffc087f2d2fKenny Rootimport java.util.Objects; 7963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 8063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey/** 8163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Collection of {@link NetworkStatsHistory}, stored based on combined key of 8263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * {@link NetworkIdentitySet}, UID, set, and tag. Knows how to persist itself. 8363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 8463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeypublic class NetworkStatsCollection implements FileRotator.Reader { 8563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** File header magic number: "ANET" */ 8663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static final int FILE_MAGIC = 0x414E4554; 8763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 8863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static final int VERSION_NETWORK_INIT = 1; 8963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 9063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static final int VERSION_UID_INIT = 1; 9163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static final int VERSION_UID_WITH_IDENT = 2; 9263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static final int VERSION_UID_WITH_TAG = 3; 9363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static final int VERSION_UID_WITH_SET = 4; 9463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 9563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static final int VERSION_UNIFIED_INIT = 16; 9663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 9755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey private ArrayMap<Key, NetworkStatsHistory> mStats = new ArrayMap<>(); 9863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 9970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey private final long mBucketDuration; 10063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 10163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private long mStartMillis; 10263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private long mEndMillis; 10363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private long mTotalBytes; 10463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private boolean mDirty; 10563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 10663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public NetworkStatsCollection(long bucketDuration) { 10763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mBucketDuration = bucketDuration; 10863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey reset(); 10963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 11063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 111e0c2995d0f16246336d4385d5ebe631a60e12e86Jeff Sharkey public void clear() { 112e0c2995d0f16246336d4385d5ebe631a60e12e86Jeff Sharkey reset(); 113e0c2995d0f16246336d4385d5ebe631a60e12e86Jeff Sharkey } 114e0c2995d0f16246336d4385d5ebe631a60e12e86Jeff Sharkey 11563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void reset() { 11663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mStats.clear(); 11763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mStartMillis = Long.MAX_VALUE; 11863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mEndMillis = Long.MIN_VALUE; 11963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mTotalBytes = 0; 12063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mDirty = false; 12163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 12263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 12363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public long getStartMillis() { 12463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return mStartMillis; 12563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 12663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 12770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey /** 12870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey * Return first atomic bucket in this collection, which is more conservative 12970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey * than {@link #mStartMillis}. 13070c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey */ 13170c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey public long getFirstAtomicBucketMillis() { 13270c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey if (mStartMillis == Long.MAX_VALUE) { 13370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey return Long.MAX_VALUE; 13470c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey } else { 13570c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey return mStartMillis + mBucketDuration; 13670c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey } 13770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey } 13870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey 13963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public long getEndMillis() { 14063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return mEndMillis; 14163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 14263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 14363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public long getTotalBytes() { 14463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return mTotalBytes; 14563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 14663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 14763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public boolean isDirty() { 14863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return mDirty; 14963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 15063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 15163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void clearDirty() { 15263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mDirty = false; 15363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 15463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 15563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public boolean isEmpty() { 15663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE; 15763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 15863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 159f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey @VisibleForTesting 160f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey public long roundUp(long time) { 161f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey if (time == Long.MIN_VALUE || time == Long.MAX_VALUE 162f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey || time == SubscriptionPlan.TIME_UNKNOWN) { 163f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey return time; 164f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } else { 165f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey final long mod = time % mBucketDuration; 166f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey if (mod > 0) { 167f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey time -= mod; 168f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey time += mBucketDuration; 169f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } 170f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey return time; 171f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } 172f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } 173f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey 174f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey @VisibleForTesting 175f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey public long roundDown(long time) { 176f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey if (time == Long.MIN_VALUE || time == Long.MAX_VALUE 177f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey || time == SubscriptionPlan.TIME_UNKNOWN) { 178f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey return time; 179f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } else { 180f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey final long mod = time % mBucketDuration; 181f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey if (mod > 0) { 182f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey time -= mod; 183f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } 184f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey return time; 185f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } 186f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } 187f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey 188d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey /** 189d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey * Safely multiple a value by a rational. 190d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey * <p> 191d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey * Internally it uses integer-based math whenever possible, but switches 192d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey * over to double-based math if values would overflow. 193d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey */ 194d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey @VisibleForTesting 195d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey public static long multiplySafe(long value, long num, long den) { 196a7be8da9adefaf6d55f7c90b95d0c6f9e66fca63Jeff Sharkey if (den == 0) den = 1; 197d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey long x = value; 198d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey long y = num; 199d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey 200d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey // Logic shamelessly borrowed from Math.multiplyExact() 201d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey long r = x * y; 202d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey long ax = Math.abs(x); 203d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey long ay = Math.abs(y); 204d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey if (((ax | ay) >>> 31 != 0)) { 205d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey // Some bits greater than 2^31 that might cause overflow 206d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey // Check the result using the divide operator 207d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey // and check for the special case of Long.MIN_VALUE * -1 208d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey if (((y != 0) && (r / y != x)) || 209d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey (x == Long.MIN_VALUE && y == -1)) { 210d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey // Use double math to avoid overflowing 211d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey return (long) (((double) num / den) * value); 212d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey } 213d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey } 214d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey return r / den; 215d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey } 216d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey 2171efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) { 218cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado return getRelevantUids(accessLevel, Binder.getCallingUid()); 219cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado } 220cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado 221cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel, 222cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado final int callerUid) { 2239c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban IntArray uids = new IntArray(); 2249c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban for (int i = 0; i < mStats.size(); i++) { 2259c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban final Key key = mStats.keyAt(i); 2261efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson if (NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel)) { 2279c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban int j = uids.binarySearch(key.uid); 2289c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban 2299c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban if (j < 0) { 2309c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban j = ~j; 2319c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban uids.add(j, key.uid); 2329c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban } 2339c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban } 2349c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban } 2359c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban return uids.toArray(); 2369c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban } 2379c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban 23863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 23963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Combine all {@link NetworkStatsHistory} in this collection which match 24063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * the requested parameters. 24163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 242f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey public NetworkStatsHistory getHistory(NetworkTemplate template, SubscriptionPlan augmentPlan, 243f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey int uid, int set, int tag, int fields, long start, long end, 244cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado @NetworkStatsAccess.Level int accessLevel, int callerUid) { 2451efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) { 2469c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban throw new SecurityException("Network stats history of uid " + uid 2479c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban + " is forbidden for caller " + callerUid); 2489c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban } 2499c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban 250090c462be959aff120498828f82df8732bf319beJeff Sharkey // 180 days of history should be enough for anyone; if we end up needing 251090c462be959aff120498828f82df8732bf319beJeff Sharkey // more, we'll dynamically grow the history object. 252090c462be959aff120498828f82df8732bf319beJeff Sharkey final int bucketEstimate = (int) MathUtils.constrain(((end - start) / mBucketDuration), 0, 253090c462be959aff120498828f82df8732bf319beJeff Sharkey (180 * DateUtils.DAY_IN_MILLIS) / mBucketDuration); 25463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory combined = new NetworkStatsHistory( 255f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey mBucketDuration, bucketEstimate, fields); 2569c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban 2579c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban // shortcut when we know stats will be empty 2589c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban if (start == end) return combined; 2599c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban 260f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey // Figure out the window of time that we should be augmenting (if any) 261f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey long augmentStart = SubscriptionPlan.TIME_UNKNOWN; 262f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey long augmentEnd = (augmentPlan != null) ? augmentPlan.getDataUsageTime() 263f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey : SubscriptionPlan.TIME_UNKNOWN; 264f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey // And if augmenting, we might need to collect more data to adjust with 265f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey long collectStart = start; 266f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey long collectEnd = end; 267f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey 268f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey if (augmentEnd != SubscriptionPlan.TIME_UNKNOWN) { 2690fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey final Iterator<Range<ZonedDateTime>> it = augmentPlan.cycleIterator(); 270f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey while (it.hasNext()) { 2710fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey final Range<ZonedDateTime> cycle = it.next(); 2720fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey final long cycleStart = cycle.getLower().toInstant().toEpochMilli(); 2730fc6d03b628c8cbe80e3c2c14aaf8c6944b32d1eJeff Sharkey final long cycleEnd = cycle.getUpper().toInstant().toEpochMilli(); 274f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey if (cycleStart <= augmentEnd && augmentEnd < cycleEnd) { 275f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey augmentStart = cycleStart; 276f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey collectStart = Long.min(collectStart, augmentStart); 277f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey collectEnd = Long.max(collectEnd, augmentEnd); 278f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey break; 279f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } 280f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } 281f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } 282f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey 283f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey if (augmentStart != SubscriptionPlan.TIME_UNKNOWN) { 284f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey // Shrink augmentation window so we don't risk undercounting. 285f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey augmentStart = roundUp(augmentStart); 286f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey augmentEnd = roundDown(augmentEnd); 287f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey // Grow collection window so we get all the stats needed. 288f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey collectStart = roundDown(collectStart); 289f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey collectEnd = roundUp(collectEnd); 290f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } 291f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey 29255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey for (int i = 0; i < mStats.size(); i++) { 29355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final Key key = mStats.keyAt(i); 29498170b0db191f916bf2a0f104f5d5057c2aaeaa9Wenchao Tong if (key.uid == uid && NetworkStats.setMatches(set, key.set) && key.tag == tag 29563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey && templateMatches(template, key.ident)) { 29655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final NetworkStatsHistory value = mStats.valueAt(i); 297f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey combined.recordHistory(value, collectStart, collectEnd); 29863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 29963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 30063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 301f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey if (augmentStart != SubscriptionPlan.TIME_UNKNOWN) { 302f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey final NetworkStatsHistory.Entry entry = combined.getValues( 303f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey augmentStart, augmentEnd, null); 304f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey 305f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey // If we don't have any recorded data for this time period, give 306f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey // ourselves something to scale with. 307f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey if (entry.rxBytes == 0 || entry.txBytes == 0) { 308f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey combined.recordData(augmentStart, augmentEnd, 309f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey new NetworkStats.Entry(1, 0, 1, 0, 0)); 310f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey combined.getValues(augmentStart, augmentEnd, entry); 311f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } 312f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey 313f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey final long rawBytes = entry.rxBytes + entry.txBytes; 314f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey final long rawRxBytes = entry.rxBytes; 315f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey final long rawTxBytes = entry.txBytes; 316f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey final long targetBytes = augmentPlan.getDataUsageBytes(); 317d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey final long targetRxBytes = multiplySafe(targetBytes, rawRxBytes, rawBytes); 318d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey final long targetTxBytes = multiplySafe(targetBytes, rawTxBytes, rawBytes); 319f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey 320f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey // Scale all matching buckets to reach anchor target 321f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey final long beforeTotal = combined.getTotalBytes(); 322f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey for (int i = 0; i < combined.size(); i++) { 323f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey combined.getValues(i, entry); 324f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey if (entry.bucketStart >= augmentStart 325f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey && entry.bucketStart + entry.bucketDuration <= augmentEnd) { 326d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey entry.rxBytes = multiplySafe(targetRxBytes, entry.rxBytes, rawRxBytes); 327d405d0555ce704d0417b85884ed267ac141302deJeff Sharkey entry.txBytes = multiplySafe(targetTxBytes, entry.txBytes, rawTxBytes); 328f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey // We purposefully clear out packet counters to indicate 329f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey // that this data has been augmented. 330f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey entry.rxPackets = 0; 331f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey entry.txPackets = 0; 332f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey combined.setValues(i, entry); 333f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } 334f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } 335f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey 336f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey final long deltaTotal = combined.getTotalBytes() - beforeTotal; 337f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey if (deltaTotal != 0) { 338f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey Slog.d(TAG, "Augmented network usage by " + deltaTotal + " bytes"); 339f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } 340f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey 341f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey // Finally we can slice data as originally requested 342f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey final NetworkStatsHistory sliced = new NetworkStatsHistory( 343f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey mBucketDuration, bucketEstimate, fields); 344f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey sliced.recordHistory(combined, start, end); 345f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey return sliced; 346f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } else { 347f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey return combined; 348f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey } 349cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado } 350cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado 351cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado /** 352cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado * Summarize all {@link NetworkStatsHistory} in this collection which match 353cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado * the requested parameters. 354cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado */ 355cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado public NetworkStats getSummary(NetworkTemplate template, long start, long end, 356cd42acd9515bdce89d4f1401ee2888d684bf1918Antonio Cansado @NetworkStatsAccess.Level int accessLevel, int callerUid) { 35763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final long now = System.currentTimeMillis(); 35863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 35963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStats stats = new NetworkStats(end - start, 24); 360f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey 36170c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey // shortcut when we know stats will be empty 36270c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey if (start == end) return stats; 36370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey 3649c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban final NetworkStats.Entry entry = new NetworkStats.Entry(); 3659c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban NetworkStatsHistory.Entry historyEntry = null; 3669c5dfa5c79fff17f96bf977b86c0c9ceb8c3cf9bZoltan Szatmary-Ban 36755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey for (int i = 0; i < mStats.size(); i++) { 36855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final Key key = mStats.keyAt(i); 3691efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson if (templateMatches(template, key.ident) 3701efb1335814aea8ee0696144ca0ab24159b86e54Jeff Davidson && NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel) 37198170b0db191f916bf2a0f104f5d5057c2aaeaa9Wenchao Tong && key.set < NetworkStats.SET_DEBUG_START) { 37255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final NetworkStatsHistory value = mStats.valueAt(i); 37355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey historyEntry = value.getValues(start, end, now, historyEntry); 37463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 37563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.iface = IFACE_ALL; 37663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.uid = key.uid; 37763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.set = key.set; 37863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.tag = key.tag; 379d3e4a1e250194bbf59b1e04b60711f97001f61f8Lorenzo Colitti entry.defaultNetwork = key.ident.areAllMembersOnDefaultNetwork() ? 380d3e4a1e250194bbf59b1e04b60711f97001f61f8Lorenzo Colitti DEFAULT_NETWORK_YES : DEFAULT_NETWORK_NO; 38125147878974f82f875062e99cdee85dd33f3f078Stephen Chen entry.metered = key.ident.isAnyMemberMetered() ? METERED_YES : METERED_NO; 3821f7e05eda687279ac9deb894f42ac927bd471ad2Jeff Davidson entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO; 38363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.rxBytes = historyEntry.rxBytes; 38463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.rxPackets = historyEntry.rxPackets; 38563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.txBytes = historyEntry.txBytes; 38663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.txPackets = historyEntry.txPackets; 38763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey entry.operations = historyEntry.operations; 38863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 38963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (!entry.isEmpty()) { 39063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey stats.combineValues(entry); 39163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 39263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 39363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 39463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 39563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return stats; 39663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 39763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 39863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 399bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey * Record given {@link android.net.NetworkStats.Entry} into this collection. 40063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 40163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void recordData(NetworkIdentitySet ident, int uid, int set, int tag, long start, 40263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey long end, NetworkStats.Entry entry) { 40370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey final NetworkStatsHistory history = findOrCreateHistory(ident, uid, set, tag); 40470c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey history.recordData(start, end, entry); 40570c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey noteRecordedHistory(history.getStart(), history.getEnd(), entry.rxBytes + entry.txBytes); 40663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 40763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 40863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 40963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Record given {@link NetworkStatsHistory} into this collection. 41063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 41163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private void recordHistory(Key key, NetworkStatsHistory history) { 41263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (history.size() == 0) return; 41363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey noteRecordedHistory(history.getStart(), history.getEnd(), history.getTotalBytes()); 41463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 415ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey NetworkStatsHistory target = mStats.get(key); 416ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey if (target == null) { 417ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey target = new NetworkStatsHistory(history.getBucketDuration()); 418ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey mStats.put(key, target); 41963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 420ac3fcb1590e1da21324c13ce237ec48f2bf488bfJeff Sharkey target.recordEntireHistory(history); 42163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 42263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 42363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 42463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Record all {@link NetworkStatsHistory} contained in the given collection 42563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * into this collection. 42663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 42763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void recordCollection(NetworkStatsCollection another) { 42855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey for (int i = 0; i < another.mStats.size(); i++) { 42955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final Key key = another.mStats.keyAt(i); 43055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final NetworkStatsHistory value = another.mStats.valueAt(i); 43155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey recordHistory(key, value); 43263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 43363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 43463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 43563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private NetworkStatsHistory findOrCreateHistory( 43663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey NetworkIdentitySet ident, int uid, int set, int tag) { 43763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final Key key = new Key(ident, uid, set, tag); 43863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory existing = mStats.get(key); 43963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 44063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // update when no existing, or when bucket duration changed 44163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey NetworkStatsHistory updated = null; 44263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (existing == null) { 44363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey updated = new NetworkStatsHistory(mBucketDuration, 10); 44463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } else if (existing.getBucketDuration() != mBucketDuration) { 44563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey updated = new NetworkStatsHistory(existing, mBucketDuration); 44663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 44763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 44863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (updated != null) { 44963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mStats.put(key, updated); 45063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return updated; 45163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } else { 45263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return existing; 45363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 45463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 45563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 456bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey @Override 45763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void read(InputStream in) throws IOException { 45863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey read(new DataInputStream(in)); 45963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 46063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 46163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void read(DataInputStream in) throws IOException { 46263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // verify file magic header intact 46363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int magic = in.readInt(); 46463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (magic != FILE_MAGIC) { 46563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey throw new ProtocolException("unexpected magic: " + magic); 46663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 46763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 46863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int version = in.readInt(); 46963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey switch (version) { 47063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey case VERSION_UNIFIED_INIT: { 47163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory)) 47263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int identSize = in.readInt(); 47363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (int i = 0; i < identSize; i++) { 47463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkIdentitySet ident = new NetworkIdentitySet(in); 47563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 47663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int size = in.readInt(); 47763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (int j = 0; j < size; j++) { 47863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int uid = in.readInt(); 47963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int set = in.readInt(); 48063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int tag = in.readInt(); 48163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 48263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final Key key = new Key(ident, uid, set, tag); 48363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory history = new NetworkStatsHistory(in); 48463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey recordHistory(key, history); 48563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 48663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 48763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey break; 48863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 48963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey default: { 49063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey throw new ProtocolException("unexpected version: " + version); 49163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 49263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 49363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 49463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 49563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void write(DataOutputStream out) throws IOException { 49663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // cluster key lists grouped by ident 49763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final HashMap<NetworkIdentitySet, ArrayList<Key>> keysByIdent = Maps.newHashMap(); 49863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (Key key : mStats.keySet()) { 49963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey ArrayList<Key> keys = keysByIdent.get(key.ident); 50063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (keys == null) { 50163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey keys = Lists.newArrayList(); 50263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey keysByIdent.put(key.ident, keys); 50363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 50463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey keys.add(key); 50563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 50663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 50763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey out.writeInt(FILE_MAGIC); 50863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey out.writeInt(VERSION_UNIFIED_INIT); 50963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 51063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey out.writeInt(keysByIdent.size()); 51163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (NetworkIdentitySet ident : keysByIdent.keySet()) { 51263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final ArrayList<Key> keys = keysByIdent.get(ident); 51363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey ident.writeToStream(out); 51463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 51563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey out.writeInt(keys.size()); 51663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (Key key : keys) { 51763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory history = mStats.get(key); 51863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey out.writeInt(key.uid); 51963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey out.writeInt(key.set); 52063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey out.writeInt(key.tag); 52163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey history.writeToStream(out); 52263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 52363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 52463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 52563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey out.flush(); 52663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 52763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 52863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey @Deprecated 52963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void readLegacyNetwork(File file) throws IOException { 53063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final AtomicFile inputFile = new AtomicFile(file); 53163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 53263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey DataInputStream in = null; 53363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey try { 53463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey in = new DataInputStream(new BufferedInputStream(inputFile.openRead())); 53563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 53663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // verify file magic header intact 53763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int magic = in.readInt(); 53863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (magic != FILE_MAGIC) { 53963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey throw new ProtocolException("unexpected magic: " + magic); 54063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 54163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 54263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int version = in.readInt(); 54363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey switch (version) { 54463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey case VERSION_NETWORK_INIT: { 54563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // network := size *(NetworkIdentitySet NetworkStatsHistory) 54663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int size = in.readInt(); 54763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (int i = 0; i < size; i++) { 54863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkIdentitySet ident = new NetworkIdentitySet(in); 54963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory history = new NetworkStatsHistory(in); 55063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 55163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final Key key = new Key(ident, UID_ALL, SET_ALL, TAG_NONE); 55263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey recordHistory(key, history); 55363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 55463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey break; 55563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 55663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey default: { 55763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey throw new ProtocolException("unexpected version: " + version); 55863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 55963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 56063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } catch (FileNotFoundException e) { 56163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // missing stats is okay, probably first boot 56263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } finally { 56363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey IoUtils.closeQuietly(in); 56463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 56563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 56663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 56763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey @Deprecated 56863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public void readLegacyUid(File file, boolean onlyTags) throws IOException { 56963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final AtomicFile inputFile = new AtomicFile(file); 57063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 57163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey DataInputStream in = null; 57263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey try { 57363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey in = new DataInputStream(new BufferedInputStream(inputFile.openRead())); 57463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 57563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // verify file magic header intact 57663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int magic = in.readInt(); 57763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (magic != FILE_MAGIC) { 57863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey throw new ProtocolException("unexpected magic: " + magic); 57963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 58063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 58163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int version = in.readInt(); 58263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey switch (version) { 58363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey case VERSION_UID_INIT: { 58463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // uid := size *(UID NetworkStatsHistory) 58563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 58663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // drop this data version, since we don't have a good 58763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // mapping into NetworkIdentitySet. 58863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey break; 58963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 59063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey case VERSION_UID_WITH_IDENT: { 59163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory)) 59263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 59363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // drop this data version, since this version only existed 59463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // for a short time. 59563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey break; 59663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 59763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey case VERSION_UID_WITH_TAG: 59863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey case VERSION_UID_WITH_SET: { 59963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory)) 60063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int identSize = in.readInt(); 60163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (int i = 0; i < identSize; i++) { 60263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkIdentitySet ident = new NetworkIdentitySet(in); 60363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 60463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int size = in.readInt(); 60563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (int j = 0; j < size; j++) { 60663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int uid = in.readInt(); 60763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt() 60863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey : SET_DEFAULT; 60963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final int tag = in.readInt(); 61063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 61163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final Key key = new Key(ident, uid, set, tag); 61263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory history = new NetworkStatsHistory(in); 61363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 61463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if ((tag == TAG_NONE) != onlyTags) { 61563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey recordHistory(key, history); 61663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 61763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 61863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 61963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey break; 62063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 62163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey default: { 62263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey throw new ProtocolException("unexpected version: " + version); 62363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 62463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 62563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } catch (FileNotFoundException e) { 62663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // missing stats is okay, probably first boot 62763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } finally { 62863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey IoUtils.closeQuietly(in); 62963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 63063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 63163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 63263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 63363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Remove any {@link NetworkStatsHistory} attributed to the requested UID, 63463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * moving any {@link NetworkStats#TAG_NONE} series to 63563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * {@link TrafficStats#UID_REMOVED}. 63663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 637daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey public void removeUids(int[] uids) { 63863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final ArrayList<Key> knownKeys = Lists.newArrayList(); 63963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey knownKeys.addAll(mStats.keySet()); 64063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 64163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // migrate all UID stats into special "removed" bucket 64263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (Key key : knownKeys) { 643daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey if (ArrayUtils.contains(uids, key.uid)) { 64463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey // only migrate combined TAG_NONE history 64563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (key.tag == TAG_NONE) { 64663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory uidHistory = mStats.get(key); 64763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory removedHistory = findOrCreateHistory( 64863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE); 64963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey removedHistory.recordEntireHistory(uidHistory); 65063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 65163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mStats.remove(key); 65263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mDirty = true; 65363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 65463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 65563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 65663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 65763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private void noteRecordedHistory(long startMillis, long endMillis, long totalBytes) { 65863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (startMillis < mStartMillis) mStartMillis = startMillis; 65963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (endMillis > mEndMillis) mEndMillis = endMillis; 66063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mTotalBytes += totalBytes; 66163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey mDirty = true; 66263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 66363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 66463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private int estimateBuckets() { 66555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey return (int) (Math.min(mEndMillis - mStartMillis, WEEK_IN_MILLIS * 5) 66663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey / mBucketDuration); 66763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 66863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 669da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki private ArrayList<Key> getSortedKeys() { 67063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final ArrayList<Key> keys = Lists.newArrayList(); 67163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey keys.addAll(mStats.keySet()); 67263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey Collections.sort(keys); 673da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki return keys; 674da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki } 67563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 676da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki public void dump(IndentingPrintWriter pw) { 677da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki for (Key key : getSortedKeys()) { 67863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey pw.print("ident="); pw.print(key.ident.toString()); 67963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey pw.print(" uid="); pw.print(key.uid); 68063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey pw.print(" set="); pw.print(NetworkStats.setToString(key.set)); 68163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag)); 68263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 68363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final NetworkStatsHistory history = mStats.get(key); 68463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey pw.increaseIndent(); 68563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey history.dump(pw, true); 68663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey pw.decreaseIndent(); 68763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 68863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 68963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 690da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki public void writeToProto(ProtoOutputStream proto, long tag) { 691da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki final long start = proto.start(tag); 692da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki 693da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki for (Key key : getSortedKeys()) { 694da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki final long startStats = proto.start(NetworkStatsCollectionProto.STATS); 695da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki 696da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki // Key 697da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY); 698da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki key.ident.writeToProto(proto, NetworkStatsCollectionKeyProto.IDENTITY); 699da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki proto.write(NetworkStatsCollectionKeyProto.UID, key.uid); 700da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki proto.write(NetworkStatsCollectionKeyProto.SET, key.set); 701da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag); 702da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki proto.end(startKey); 703da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki 704da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki // Value 705da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki final NetworkStatsHistory history = mStats.get(key); 706da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki history.writeToProto(proto, NetworkStatsCollectionStatsProto.HISTORY); 707da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki proto.end(startStats); 708da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki } 709da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki 710da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki proto.end(start); 711da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki } 712da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki 71355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey public void dumpCheckin(PrintWriter pw, long start, long end) { 71455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateMobileWildcard(), "cell"); 71555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateWifiWildcard(), "wifi"); 71655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateEthernet(), "eth"); 71755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateBluetooth(), "bt"); 71855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 71955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 72055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey /** 72155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey * Dump all contained stats that match requested parameters, but group 72255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey * together all matching {@link NetworkTemplate} under a single prefix. 72355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey */ 72455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey private void dumpCheckin(PrintWriter pw, long start, long end, NetworkTemplate groupTemplate, 72555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey String groupPrefix) { 72655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final ArrayMap<Key, NetworkStatsHistory> grouped = new ArrayMap<>(); 72755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 72855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey // Walk through all history, grouping by matching network templates 72955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey for (int i = 0; i < mStats.size(); i++) { 73055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final Key key = mStats.keyAt(i); 73155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final NetworkStatsHistory value = mStats.valueAt(i); 73255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 73355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey if (!templateMatches(groupTemplate, key.ident)) continue; 73498170b0db191f916bf2a0f104f5d5057c2aaeaa9Wenchao Tong if (key.set >= NetworkStats.SET_DEBUG_START) continue; 73555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 73655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final Key groupKey = new Key(null, key.uid, key.set, key.tag); 73755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey NetworkStatsHistory groupHistory = grouped.get(groupKey); 73855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey if (groupHistory == null) { 73955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey groupHistory = new NetworkStatsHistory(value.getBucketDuration()); 74055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey grouped.put(groupKey, groupHistory); 74155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 74255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey groupHistory.recordHistory(value, start, end); 74355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 74455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 74555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey for (int i = 0; i < grouped.size(); i++) { 74655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final Key key = grouped.keyAt(i); 74755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey final NetworkStatsHistory value = grouped.valueAt(i); 74855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 74955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey if (value.size() == 0) continue; 75055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 75155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey pw.print("c,"); 75255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey pw.print(groupPrefix); pw.print(','); 75355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey pw.print(key.uid); pw.print(','); 75455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey pw.print(NetworkStats.setToCheckinString(key.set)); pw.print(','); 75555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey pw.print(key.tag); 75655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey pw.println(); 75755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 75855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey value.dumpCheckin(pw); 75955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 76055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 76155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey 76263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey /** 76363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity} 76463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey * in the given {@link NetworkIdentitySet}. 76563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey */ 76663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) { 76763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey for (NetworkIdentity ident : identSet) { 76863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (template.matches(ident)) { 76963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return true; 77063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 77163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 77263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return false; 77363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 77463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 77563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private static class Key implements Comparable<Key> { 77663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public final NetworkIdentitySet ident; 77763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public final int uid; 77863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public final int set; 77963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public final int tag; 78063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 78163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey private final int hashCode; 78263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 78363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public Key(NetworkIdentitySet ident, int uid, int set, int tag) { 78463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey this.ident = ident; 78563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey this.uid = uid; 78663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey this.set = set; 78763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey this.tag = tag; 788e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root hashCode = Objects.hash(ident, uid, set, tag); 78963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 79063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 79163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey @Override 79263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public int hashCode() { 79363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return hashCode; 79463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 79563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 79663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey @Override 79763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public boolean equals(Object obj) { 79863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey if (obj instanceof Key) { 79963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey final Key key = (Key) obj; 80063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return uid == key.uid && set == key.set && tag == key.tag 801e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root && Objects.equals(ident, key.ident); 80263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 80363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey return false; 80463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 80563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey 806bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey @Override 80763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey public int compareTo(Key another) { 80855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey int res = 0; 80955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey if (ident != null && another.ident != null) { 81055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey res = ident.compareTo(another.ident); 81155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 81255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey if (res == 0) { 81355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey res = Integer.compare(uid, another.uid); 81455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 81555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey if (res == 0) { 81655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey res = Integer.compare(set, another.set); 81755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 81855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey if (res == 0) { 81955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey res = Integer.compare(tag, another.tag); 82055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey } 82155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey return res; 82263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 82363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey } 82463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey} 825