NetworkStatsHistory.java revision 4a97122ebf4d92a3f94402041729d77905e6c0c0
175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey/* 275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Copyright (C) 2011 The Android Open Source Project 375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * 475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * you may not use this file except in compliance with the License. 675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * You may obtain a copy of the License at 775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * 875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * 1075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Unless required by applicable law or agreed to in writing, software 1175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 1275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * See the License for the specific language governing permissions and 1475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * limitations under the License. 1575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */ 1675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 1775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeypackage android.net; 1875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 1975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.os.Parcel; 2075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.os.Parcelable; 2175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 2275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.CharArrayWriter; 2375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.DataInputStream; 2475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.DataOutputStream; 2575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.IOException; 2675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.PrintWriter; 2761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkeyimport java.net.ProtocolException; 2875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.util.Arrays; 2961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkeyimport java.util.Random; 3075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 3175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey/** 3275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Collection of historical network statistics, recorded into equally-sized 3375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * "buckets" in time. Internally it stores data in {@code long} series for more 3475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * efficient persistence. 3575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * <p> 3675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Each bucket is defined by a {@link #bucketStart} timestamp, and lasts for 3775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * {@link #bucketDuration}. Internally assumes that {@link #bucketStart} is 3875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * sorted at all times. 3975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * 4075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * @hide 4175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */ 4275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeypublic class NetworkStatsHistory implements Parcelable { 4361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey private static final int VERSION_CURRENT = 1; 4475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 4575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // TODO: teach about zigzag encoding to use less disk space 4675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // TODO: teach how to convert between bucket sizes 4775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 4875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public final long bucketDuration; 4975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 50d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey public int bucketCount; 51d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey public long[] bucketStart; 52d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey public long[] rx; 53d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey public long[] tx; 5475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 55d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey public NetworkStatsHistory(long bucketDuration) { 564a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey this(bucketDuration, 10); 574a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey } 584a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey 594a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey public NetworkStatsHistory(long bucketDuration, int initialSize) { 6075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey this.bucketDuration = bucketDuration; 614a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey bucketStart = new long[initialSize]; 624a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey rx = new long[initialSize]; 634a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey tx = new long[initialSize]; 644a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey bucketCount = 0; 6575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 6675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 6775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public NetworkStatsHistory(Parcel in) { 6875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketDuration = in.readLong(); 6975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketStart = readLongArray(in); 7075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey rx = in.createLongArray(); 7175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey tx = in.createLongArray(); 7275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketCount = bucketStart.length; 7375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 7475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 7575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** {@inheritDoc} */ 7675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public void writeToParcel(Parcel out, int flags) { 7775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeLong(bucketDuration); 7875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey writeLongArray(out, bucketStart, bucketCount); 7975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey writeLongArray(out, rx, bucketCount); 8075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey writeLongArray(out, tx, bucketCount); 8175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 8275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 8375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public NetworkStatsHistory(DataInputStream in) throws IOException { 8475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int version = in.readInt(); 8561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey switch (version) { 8661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey case VERSION_CURRENT: { 8761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey bucketDuration = in.readLong(); 8861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey bucketStart = readLongArray(in); 8961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey rx = readLongArray(in); 9061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey tx = readLongArray(in); 9161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey bucketCount = bucketStart.length; 9261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey break; 9361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 9461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey default: { 9561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey throw new ProtocolException("unexpected version: " + version); 9661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 9761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 9875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 9975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 10075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public void writeToStream(DataOutputStream out) throws IOException { 10161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey out.writeInt(VERSION_CURRENT); 10275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeLong(bucketDuration); 10375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey writeLongArray(out, bucketStart, bucketCount); 10475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey writeLongArray(out, rx, bucketCount); 10575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey writeLongArray(out, tx, bucketCount); 10675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 10775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 10875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** {@inheritDoc} */ 10975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public int describeContents() { 11075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return 0; 11175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 11275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 11375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** 11475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Record that data traffic occurred in the given time range. Will 11575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * distribute across internal buckets, creating new buckets as needed. 11675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */ 11775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public void recordData(long start, long end, long rx, long tx) { 11875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // create any buckets needed by this range 11975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey ensureBuckets(start, end); 12075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 12175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // distribute data usage into buckets 12275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long duration = end - start; 12375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (int i = bucketCount - 1; i >= 0; i--) { 12475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long curStart = bucketStart[i]; 12575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long curEnd = curStart + bucketDuration; 12675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 12775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // bucket is older than record; we're finished 12875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (curEnd < start) break; 12975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // bucket is newer than record; keep looking 13075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (curStart > end) continue; 13175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 13275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); 13375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (overlap > 0) { 13475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey this.rx[i] += rx * overlap / duration; 13575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey this.tx[i] += tx * overlap / duration; 13675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 13775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 13875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 13975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 14075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** 14119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey * Record an entire {@link NetworkStatsHistory} into this history. Usually 14219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey * for combining together stats for external reporting. 14319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey */ 14419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey public void recordEntireHistory(NetworkStatsHistory input) { 14519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey for (int i = 0; i < input.bucketCount; i++) { 14619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey final long start = input.bucketStart[i]; 14719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey final long end = start + input.bucketDuration; 14819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey recordData(start, end, input.rx[i], input.tx[i]); 14919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey } 15019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey } 15119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 15219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey /** 15375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Ensure that buckets exist for given time range, creating as needed. 15475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */ 15575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private void ensureBuckets(long start, long end) { 15675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // normalize incoming range to bucket boundaries 15775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey start -= start % bucketDuration; 15875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey end += (bucketDuration - (end % bucketDuration)) % bucketDuration; 15975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 16075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (long now = start; now < end; now += bucketDuration) { 16175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // try finding existing bucket 16275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int index = Arrays.binarySearch(bucketStart, 0, bucketCount, now); 16375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (index < 0) { 16475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // bucket missing, create and insert 16575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey insertBucket(~index, now); 16675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 16775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 16875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 16975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 17075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** 17175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Insert new bucket at requested index and starting time. 17275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */ 17375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private void insertBucket(int index, long start) { 17475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // create more buckets when needed 1754a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey if (bucketCount >= bucketStart.length) { 1764a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey final int newLength = Math.max(bucketStart.length, 10) * 3 / 2; 17775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketStart = Arrays.copyOf(bucketStart, newLength); 17875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey rx = Arrays.copyOf(rx, newLength); 17975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey tx = Arrays.copyOf(tx, newLength); 18075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 18175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 18275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // create gap when inserting bucket in middle 18375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (index < bucketCount) { 18475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int dstPos = index + 1; 18575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int length = bucketCount - index; 18675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 18775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey System.arraycopy(bucketStart, index, bucketStart, dstPos, length); 18875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey System.arraycopy(rx, index, rx, dstPos, length); 18975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey System.arraycopy(tx, index, tx, dstPos, length); 19075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 19175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 19275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketStart[index] = start; 19375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey rx[index] = 0; 19475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey tx[index] = 0; 19575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketCount++; 19675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 19775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 19875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** 19975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Remove buckets older than requested cutoff. 20075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */ 20175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public void removeBucketsBefore(long cutoff) { 20275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey int i; 20375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (i = 0; i < bucketCount; i++) { 20475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long curStart = bucketStart[i]; 20575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long curEnd = curStart + bucketDuration; 20675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 20775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // cutoff happens before or during this bucket; everything before 20875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // this bucket should be removed. 20975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (curEnd > cutoff) break; 21075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 21175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 21275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (i > 0) { 21375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int length = bucketStart.length; 21475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketStart = Arrays.copyOfRange(bucketStart, i, length); 21575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey rx = Arrays.copyOfRange(rx, i, length); 21675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey tx = Arrays.copyOfRange(tx, i, length); 21775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketCount -= i; 21875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 21975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 22075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 22161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey /** 22219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey * Return interpolated data usage across the requested range. Interpolates 22319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey * across buckets, so values may be rounded slightly. 22419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey */ 2253f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey public long[] getTotalData(long start, long end, long[] outTotal) { 22619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey long rx = 0; 22719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey long tx = 0; 22819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 22919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey for (int i = bucketCount - 1; i >= 0; i--) { 23019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey final long curStart = bucketStart[i]; 23119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey final long curEnd = curStart + bucketDuration; 23219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 23319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey // bucket is older than record; we're finished 23419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey if (curEnd < start) break; 23519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey // bucket is newer than record; keep looking 23619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey if (curStart > end) continue; 23719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 23819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); 23919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey if (overlap > 0) { 24019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey rx += this.rx[i] * overlap / bucketDuration; 24119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey tx += this.tx[i] * overlap / bucketDuration; 24219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey } 24319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey } 24419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 2453f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey if (outTotal == null || outTotal.length != 2) { 2463f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey outTotal = new long[2]; 2473f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey } 24819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey outTotal[0] = rx; 24919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey outTotal[1] = tx; 2503f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey return outTotal; 25119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey } 25219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 25319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey /** 25461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey * @deprecated only for temporary testing 25561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey */ 25661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey @Deprecated 25761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey public void generateRandom(long start, long end, long rx, long tx) { 25861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey ensureBuckets(start, end); 25961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey 26061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey final Random r = new Random(); 26161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey while (rx > 1024 && tx > 1024) { 26261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey final long curStart = randomLong(r, start, end); 26361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey final long curEnd = randomLong(r, curStart, end); 26461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey final long curRx = randomLong(r, 0, rx); 26561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey final long curTx = randomLong(r, 0, tx); 26661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey 26761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey recordData(curStart, curEnd, curRx, curTx); 26861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey 26961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey rx -= curRx; 27061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey tx -= curTx; 27161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 27261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 27361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey 27461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey private static long randomLong(Random r, long start, long end) { 27561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey return (long) (start + (r.nextFloat() * (end - start))); 27661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 27761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey 27875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public void dump(String prefix, PrintWriter pw) { 27975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey pw.print(prefix); 28061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration); 28175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (int i = 0; i < bucketCount; i++) { 28275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey pw.print(prefix); 28361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey pw.print(" bucketStart="); pw.print(bucketStart[i]); 28475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey pw.print(" rx="); pw.print(rx[i]); 28575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey pw.print(" tx="); pw.println(tx[i]); 28675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 28775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 28875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 28975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey @Override 29075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public String toString() { 29175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final CharArrayWriter writer = new CharArrayWriter(); 29275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey dump("", new PrintWriter(writer)); 29375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return writer.toString(); 29475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 29575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 29675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public static final Creator<NetworkStatsHistory> CREATOR = new Creator<NetworkStatsHistory>() { 29775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public NetworkStatsHistory createFromParcel(Parcel in) { 29875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return new NetworkStatsHistory(in); 29975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 30075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 30175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public NetworkStatsHistory[] newArray(int size) { 30275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return new NetworkStatsHistory[size]; 30375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 30475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey }; 30575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 30675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private static long[] readLongArray(DataInputStream in) throws IOException { 30775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int size = in.readInt(); 30875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long[] values = new long[size]; 30975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (int i = 0; i < values.length; i++) { 31075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey values[i] = in.readLong(); 31175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 31275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return values; 31375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 31475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 31575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private static void writeLongArray(DataOutputStream out, long[] values, int size) throws IOException { 31675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (size > values.length) { 31775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey throw new IllegalArgumentException("size larger than length"); 31875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 31975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeInt(size); 32075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (int i = 0; i < size; i++) { 32175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeLong(values[i]); 32275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 32375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 32475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 32575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private static long[] readLongArray(Parcel in) { 32675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int size = in.readInt(); 32775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long[] values = new long[size]; 32875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (int i = 0; i < values.length; i++) { 32975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey values[i] = in.readLong(); 33075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 33175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return values; 33275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 33375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 33475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private static void writeLongArray(Parcel out, long[] values, int size) { 33575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (size > values.length) { 33675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey throw new IllegalArgumentException("size larger than length"); 33775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 33875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeInt(size); 33975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (int i = 0; i < size; i++) { 34075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeLong(values[i]); 34175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 34275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 34375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 34475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey} 345