NetworkStatsHistory.java revision 55a442e58262e253df965d652bd8219c8d1e72d3
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
19a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeyimport static android.net.NetworkStats.IFACE_ALL;
20b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkeyimport static android.net.NetworkStats.SET_DEFAULT;
21a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeyimport static android.net.NetworkStats.TAG_NONE;
22a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeyimport static android.net.NetworkStats.UID_ALL;
2363d27a9233fed934340231f438493746084a681dJeff Sharkeyimport static android.net.NetworkStatsHistory.DataStreamUtils.readFullLongArray;
2463d27a9233fed934340231f438493746084a681dJeff Sharkeyimport static android.net.NetworkStatsHistory.DataStreamUtils.readVarLongArray;
2563d27a9233fed934340231f438493746084a681dJeff Sharkeyimport static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray;
2663d27a9233fed934340231f438493746084a681dJeff Sharkeyimport static android.net.NetworkStatsHistory.Entry.UNKNOWN;
27a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeyimport static android.net.NetworkStatsHistory.ParcelUtils.readLongArray;
28a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeyimport static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
2955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkeyimport static android.text.format.DateUtils.SECOND_IN_MILLIS;
3063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static com.android.internal.util.ArrayUtils.total;
31a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
3275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.os.Parcel;
3375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.os.Parcelable;
3469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkeyimport android.util.MathUtils;
3575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
3663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter;
3763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
3875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.CharArrayWriter;
3975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.DataInputStream;
4075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.DataOutputStream;
4175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.IOException;
4255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkeyimport java.io.PrintWriter;
4361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkeyimport java.net.ProtocolException;
4475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.util.Arrays;
4561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkeyimport java.util.Random;
4675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
4775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey/**
4875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Collection of historical network statistics, recorded into equally-sized
4975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * "buckets" in time. Internally it stores data in {@code long} series for more
5075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * efficient persistence.
5175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * <p>
5275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Each bucket is defined by a {@link #bucketStart} timestamp, and lasts for
5375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * {@link #bucketDuration}. Internally assumes that {@link #bucketStart} is
5475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * sorted at all times.
5575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey *
5675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * @hide
5775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */
5875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeypublic class NetworkStatsHistory implements Parcelable {
591b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey    private static final int VERSION_INIT = 1;
6063d27a9233fed934340231f438493746084a681dJeff Sharkey    private static final int VERSION_ADD_PACKETS = 2;
61558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    private static final int VERSION_ADD_ACTIVE = 3;
6275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
63558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_ACTIVE_TIME = 0x01;
64558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_RX_BYTES = 0x02;
65558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_RX_PACKETS = 0x04;
66558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_TX_BYTES = 0x08;
67558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_TX_PACKETS = 0x10;
68558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_OPERATIONS = 0x20;
69d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
7063d27a9233fed934340231f438493746084a681dJeff Sharkey    public static final int FIELD_ALL = 0xFFFFFFFF;
7163d27a9233fed934340231f438493746084a681dJeff Sharkey
7263d27a9233fed934340231f438493746084a681dJeff Sharkey    private long bucketDuration;
73d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private int bucketCount;
74d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] bucketStart;
75558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    private long[] activeTime;
76d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] rxBytes;
77a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    private long[] rxPackets;
78d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] txBytes;
79a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    private long[] txPackets;
8063d27a9233fed934340231f438493746084a681dJeff Sharkey    private long[] operations;
8163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private long totalBytes;
82d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
83d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public static class Entry {
8463d27a9233fed934340231f438493746084a681dJeff Sharkey        public static final long UNKNOWN = -1;
8563d27a9233fed934340231f438493746084a681dJeff Sharkey
86d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        public long bucketDuration;
87558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        public long bucketStart;
88558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        public long activeTime;
89d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        public long rxBytes;
90a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        public long rxPackets;
91d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        public long txBytes;
92a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        public long txPackets;
9363d27a9233fed934340231f438493746084a681dJeff Sharkey        public long operations;
94d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
9575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
96d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey    public NetworkStatsHistory(long bucketDuration) {
9763d27a9233fed934340231f438493746084a681dJeff Sharkey        this(bucketDuration, 10, FIELD_ALL);
984a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey    }
994a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey
1004a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey    public NetworkStatsHistory(long bucketDuration, int initialSize) {
10163d27a9233fed934340231f438493746084a681dJeff Sharkey        this(bucketDuration, initialSize, FIELD_ALL);
10263d27a9233fed934340231f438493746084a681dJeff Sharkey    }
10363d27a9233fed934340231f438493746084a681dJeff Sharkey
10463d27a9233fed934340231f438493746084a681dJeff Sharkey    public NetworkStatsHistory(long bucketDuration, int initialSize, int fields) {
10575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        this.bucketDuration = bucketDuration;
1064a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        bucketStart = new long[initialSize];
107558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        if ((fields & FIELD_ACTIVE_TIME) != 0) activeTime = new long[initialSize];
10863d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_RX_BYTES) != 0) rxBytes = new long[initialSize];
10963d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_RX_PACKETS) != 0) rxPackets = new long[initialSize];
11063d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_TX_BYTES) != 0) txBytes = new long[initialSize];
11163d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_TX_PACKETS) != 0) txPackets = new long[initialSize];
11263d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_OPERATIONS) != 0) operations = new long[initialSize];
1134a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        bucketCount = 0;
11463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        totalBytes = 0;
11563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
11663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
11763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public NetworkStatsHistory(NetworkStatsHistory existing, long bucketDuration) {
11863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        this(bucketDuration, existing.estimateResizeBuckets(bucketDuration));
11963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        recordEntireHistory(existing);
12075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
12175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
12275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public NetworkStatsHistory(Parcel in) {
12375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketDuration = in.readLong();
12475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketStart = readLongArray(in);
125558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        activeTime = readLongArray(in);
126a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        rxBytes = readLongArray(in);
127a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        rxPackets = readLongArray(in);
128a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        txBytes = readLongArray(in);
129a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        txPackets = readLongArray(in);
13063d27a9233fed934340231f438493746084a681dJeff Sharkey        operations = readLongArray(in);
13175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketCount = bucketStart.length;
13263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        totalBytes = in.readLong();
13375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
13475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
135bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey    @Override
13675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void writeToParcel(Parcel out, int flags) {
13775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        out.writeLong(bucketDuration);
13875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        writeLongArray(out, bucketStart, bucketCount);
139558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        writeLongArray(out, activeTime, bucketCount);
140d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        writeLongArray(out, rxBytes, bucketCount);
141a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        writeLongArray(out, rxPackets, bucketCount);
142d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        writeLongArray(out, txBytes, bucketCount);
143a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        writeLongArray(out, txPackets, bucketCount);
14463d27a9233fed934340231f438493746084a681dJeff Sharkey        writeLongArray(out, operations, bucketCount);
14563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        out.writeLong(totalBytes);
14675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
14775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
14875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public NetworkStatsHistory(DataInputStream in) throws IOException {
14975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final int version = in.readInt();
15061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        switch (version) {
1511b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey            case VERSION_INIT: {
15261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey                bucketDuration = in.readLong();
15363d27a9233fed934340231f438493746084a681dJeff Sharkey                bucketStart = readFullLongArray(in);
15463d27a9233fed934340231f438493746084a681dJeff Sharkey                rxBytes = readFullLongArray(in);
155a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                rxPackets = new long[bucketStart.length];
15663d27a9233fed934340231f438493746084a681dJeff Sharkey                txBytes = readFullLongArray(in);
157a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                txPackets = new long[bucketStart.length];
15863d27a9233fed934340231f438493746084a681dJeff Sharkey                operations = new long[bucketStart.length];
15963d27a9233fed934340231f438493746084a681dJeff Sharkey                bucketCount = bucketStart.length;
16063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                totalBytes = total(rxBytes) + total(txBytes);
16163d27a9233fed934340231f438493746084a681dJeff Sharkey                break;
16263d27a9233fed934340231f438493746084a681dJeff Sharkey            }
163558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            case VERSION_ADD_PACKETS:
164558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            case VERSION_ADD_ACTIVE: {
16563d27a9233fed934340231f438493746084a681dJeff Sharkey                bucketDuration = in.readLong();
16663d27a9233fed934340231f438493746084a681dJeff Sharkey                bucketStart = readVarLongArray(in);
167558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey                activeTime = (version >= VERSION_ADD_ACTIVE) ? readVarLongArray(in)
168558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey                        : new long[bucketStart.length];
16963d27a9233fed934340231f438493746084a681dJeff Sharkey                rxBytes = readVarLongArray(in);
17063d27a9233fed934340231f438493746084a681dJeff Sharkey                rxPackets = readVarLongArray(in);
17163d27a9233fed934340231f438493746084a681dJeff Sharkey                txBytes = readVarLongArray(in);
17263d27a9233fed934340231f438493746084a681dJeff Sharkey                txPackets = readVarLongArray(in);
17363d27a9233fed934340231f438493746084a681dJeff Sharkey                operations = readVarLongArray(in);
17461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey                bucketCount = bucketStart.length;
17563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                totalBytes = total(rxBytes) + total(txBytes);
17661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey                break;
17761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            }
17861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            default: {
17961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey                throw new ProtocolException("unexpected version: " + version);
18061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            }
18161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        }
182b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey
183b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey        if (bucketStart.length != bucketCount || rxBytes.length != bucketCount
184b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey                || rxPackets.length != bucketCount || txBytes.length != bucketCount
185b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey                || txPackets.length != bucketCount || operations.length != bucketCount) {
186b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey            throw new ProtocolException("Mismatched history lengths");
187b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey        }
18875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
18975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
19075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void writeToStream(DataOutputStream out) throws IOException {
191558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        out.writeInt(VERSION_ADD_ACTIVE);
19275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        out.writeLong(bucketDuration);
19363d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, bucketStart, bucketCount);
194558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        writeVarLongArray(out, activeTime, bucketCount);
19563d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, rxBytes, bucketCount);
19663d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, rxPackets, bucketCount);
19763d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, txBytes, bucketCount);
19863d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, txPackets, bucketCount);
19963d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, operations, bucketCount);
20075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
20175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
202bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey    @Override
20375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public int describeContents() {
20475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        return 0;
20575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
20675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
207d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public int size() {
208d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        return bucketCount;
209d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
210d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
211d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public long getBucketDuration() {
212d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        return bucketDuration;
213d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
214d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
215434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    public long getStart() {
216434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        if (bucketCount > 0) {
217434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            return bucketStart[0];
218434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        } else {
219434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            return Long.MAX_VALUE;
220434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        }
221434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    }
222434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey
223434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    public long getEnd() {
224434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        if (bucketCount > 0) {
225434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            return bucketStart[bucketCount - 1] + bucketDuration;
226434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        } else {
227434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            return Long.MIN_VALUE;
228434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        }
229434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    }
230434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey
231d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    /**
23263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Return total bytes represented by this history.
23363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
23463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public long getTotalBytes() {
23563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return totalBytes;
23663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
23763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
23863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
23969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     * Return index of bucket that contains or is immediately before the
24069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     * requested time.
24169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     */
24269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    public int getIndexBefore(long time) {
24369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
24469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        if (index < 0) {
24569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            index = (~index) - 1;
24669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        } else {
24769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            index -= 1;
24869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        }
24969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        return MathUtils.constrain(index, 0, bucketCount - 1);
25069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    }
25169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey
25269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    /**
25369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     * Return index of bucket that contains or is immediately after the
25469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     * requested time.
25569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     */
25669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    public int getIndexAfter(long time) {
25769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
25869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        if (index < 0) {
25969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            index = ~index;
26069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        } else {
26169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            index += 1;
26269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        }
26369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        return MathUtils.constrain(index, 0, bucketCount - 1);
26469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    }
26569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey
26669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    /**
267d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey     * Return specific stats entry.
268d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey     */
269d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public Entry getValues(int i, Entry recycle) {
270d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        final Entry entry = recycle != null ? recycle : new Entry();
271d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        entry.bucketStart = bucketStart[i];
272d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        entry.bucketDuration = bucketDuration;
273558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        entry.activeTime = getLong(activeTime, i, UNKNOWN);
27463d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.rxBytes = getLong(rxBytes, i, UNKNOWN);
27563d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.rxPackets = getLong(rxPackets, i, UNKNOWN);
27663d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.txBytes = getLong(txBytes, i, UNKNOWN);
27763d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.txPackets = getLong(txPackets, i, UNKNOWN);
27863d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.operations = getLong(operations, i, UNKNOWN);
279d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        return entry;
280d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
281d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
28275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
28375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Record that data traffic occurred in the given time range. Will
28475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * distribute across internal buckets, creating new buckets as needed.
28575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
286a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    @Deprecated
287a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void recordData(long start, long end, long rxBytes, long txBytes) {
288b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        recordData(start, end, new NetworkStats.Entry(
289b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L));
290a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
291a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
292a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /**
293a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * Record that data traffic occurred in the given time range. Will
294a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * distribute across internal buckets, creating new buckets as needed.
295a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     */
296a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void recordData(long start, long end, NetworkStats.Entry entry) {
29763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long rxBytes = entry.rxBytes;
29863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long rxPackets = entry.rxPackets;
29963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long txBytes = entry.txBytes;
30063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long txPackets = entry.txPackets;
30163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long operations = entry.operations;
30263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
30363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (entry.isNegative()) {
304a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            throw new IllegalArgumentException("tried recording negative data");
3051b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        }
30663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (entry.isEmpty()) {
307367d15ab1a33b6159447fa8542d4fa8ff148371cJeff Sharkey            return;
308367d15ab1a33b6159447fa8542d4fa8ff148371cJeff Sharkey        }
3091b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey
31075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // create any buckets needed by this range
31175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        ensureBuckets(start, end);
31275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
31375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // distribute data usage into buckets
314a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        long duration = end - start;
31569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        final int startIndex = getIndexAfter(end);
31669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        for (int i = startIndex; i >= 0; i--) {
31775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long curStart = bucketStart[i];
31875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long curEnd = curStart + bucketDuration;
31975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
32075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // bucket is older than record; we're finished
32175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (curEnd < start) break;
32275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // bucket is newer than record; keep looking
32375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (curStart > end) continue;
32475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
32575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long overlap = Math.min(curEnd, end) - Math.max(curStart, start);
326a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (overlap <= 0) continue;
327a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
328a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            // integer math each time is faster than floating point
32963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracRxBytes = rxBytes * overlap / duration;
33063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracRxPackets = rxPackets * overlap / duration;
33163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracTxBytes = txBytes * overlap / duration;
33263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracTxPackets = txPackets * overlap / duration;
33363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracOperations = operations * overlap / duration;
334a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
335558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            addLong(activeTime, i, overlap);
33663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.rxBytes, i, fracRxBytes); rxBytes -= fracRxBytes;
33763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.rxPackets, i, fracRxPackets); rxPackets -= fracRxPackets;
33863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.txBytes, i, fracTxBytes); txBytes -= fracTxBytes;
33963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.txPackets, i, fracTxPackets); txPackets -= fracTxPackets;
34063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.operations, i, fracOperations); operations -= fracOperations;
341a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
342a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            duration -= overlap;
34375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
34463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
34563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        totalBytes += entry.rxBytes + entry.txBytes;
34675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
34775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
34875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
34919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     * Record an entire {@link NetworkStatsHistory} into this history. Usually
35019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     * for combining together stats for external reporting.
35119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     */
35219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    public void recordEntireHistory(NetworkStatsHistory input) {
35370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        recordHistory(input, Long.MIN_VALUE, Long.MAX_VALUE);
35470c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    }
35570c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey
35670c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    /**
35770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     * Record given {@link NetworkStatsHistory} into this history, copying only
35870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     * buckets that atomically occur in the inclusive time range. Doesn't
35970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     * interpolate across partial buckets.
36070c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     */
36170c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    public void recordHistory(NetworkStatsHistory input, long start, long end) {
362a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        final NetworkStats.Entry entry = new NetworkStats.Entry(
363b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
36419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        for (int i = 0; i < input.bucketCount; i++) {
36570c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            final long bucketStart = input.bucketStart[i];
36670c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            final long bucketEnd = bucketStart + input.bucketDuration;
36770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey
36870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            // skip when bucket is outside requested range
36970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            if (bucketStart < start || bucketEnd > end) continue;
370a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
37163d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.rxBytes = getLong(input.rxBytes, i, 0L);
37263d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.rxPackets = getLong(input.rxPackets, i, 0L);
37363d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.txBytes = getLong(input.txBytes, i, 0L);
37463d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.txPackets = getLong(input.txPackets, i, 0L);
37563d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.operations = getLong(input.operations, i, 0L);
376a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
37770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            recordData(bucketStart, bucketEnd, entry);
37819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        }
37919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    }
38019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
38119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    /**
38275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Ensure that buckets exist for given time range, creating as needed.
38375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
38475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private void ensureBuckets(long start, long end) {
38575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // normalize incoming range to bucket boundaries
38675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        start -= start % bucketDuration;
38775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        end += (bucketDuration - (end % bucketDuration)) % bucketDuration;
38875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
38975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        for (long now = start; now < end; now += bucketDuration) {
39075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // try finding existing bucket
39175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final int index = Arrays.binarySearch(bucketStart, 0, bucketCount, now);
39275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (index < 0) {
39375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                // bucket missing, create and insert
39475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                insertBucket(~index, now);
39575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            }
39675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
39775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
39875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
39975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
40075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Insert new bucket at requested index and starting time.
40175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
40275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private void insertBucket(int index, long start) {
40375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // create more buckets when needed
4044a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        if (bucketCount >= bucketStart.length) {
4054a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey            final int newLength = Math.max(bucketStart.length, 10) * 3 / 2;
40675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            bucketStart = Arrays.copyOf(bucketStart, newLength);
407558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            if (activeTime != null) activeTime = Arrays.copyOf(activeTime, newLength);
40863d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxBytes != null) rxBytes = Arrays.copyOf(rxBytes, newLength);
40963d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxPackets != null) rxPackets = Arrays.copyOf(rxPackets, newLength);
41063d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txBytes != null) txBytes = Arrays.copyOf(txBytes, newLength);
41163d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txPackets != null) txPackets = Arrays.copyOf(txPackets, newLength);
41263d27a9233fed934340231f438493746084a681dJeff Sharkey            if (operations != null) operations = Arrays.copyOf(operations, newLength);
41375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
41475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
41575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // create gap when inserting bucket in middle
41675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        if (index < bucketCount) {
41775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final int dstPos = index + 1;
41875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final int length = bucketCount - index;
41975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
42075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            System.arraycopy(bucketStart, index, bucketStart, dstPos, length);
421558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            if (activeTime != null) System.arraycopy(activeTime, index, activeTime, dstPos, length);
42263d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxBytes != null) System.arraycopy(rxBytes, index, rxBytes, dstPos, length);
42363d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxPackets != null) System.arraycopy(rxPackets, index, rxPackets, dstPos, length);
42463d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txBytes != null) System.arraycopy(txBytes, index, txBytes, dstPos, length);
42563d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txPackets != null) System.arraycopy(txPackets, index, txPackets, dstPos, length);
42663d27a9233fed934340231f438493746084a681dJeff Sharkey            if (operations != null) System.arraycopy(operations, index, operations, dstPos, length);
42775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
42875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
42975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketStart[index] = start;
430558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        setLong(activeTime, index, 0L);
43163d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(rxBytes, index, 0L);
43263d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(rxPackets, index, 0L);
43363d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(txBytes, index, 0L);
43463d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(txPackets, index, 0L);
43563d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(operations, index, 0L);
43675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketCount++;
43775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
43875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
43975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
44075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Remove buckets older than requested cutoff.
44175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
44263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    @Deprecated
44375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void removeBucketsBefore(long cutoff) {
44475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        int i;
44575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        for (i = 0; i < bucketCount; i++) {
44675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long curStart = bucketStart[i];
44775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long curEnd = curStart + bucketDuration;
44875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
44975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // cutoff happens before or during this bucket; everything before
45075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // this bucket should be removed.
45175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (curEnd > cutoff) break;
45275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
45375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
45475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        if (i > 0) {
45575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final int length = bucketStart.length;
45675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            bucketStart = Arrays.copyOfRange(bucketStart, i, length);
457558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            if (activeTime != null) activeTime = Arrays.copyOfRange(activeTime, i, length);
45863d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxBytes != null) rxBytes = Arrays.copyOfRange(rxBytes, i, length);
45963d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxPackets != null) rxPackets = Arrays.copyOfRange(rxPackets, i, length);
46063d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txBytes != null) txBytes = Arrays.copyOfRange(txBytes, i, length);
46163d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txPackets != null) txPackets = Arrays.copyOfRange(txPackets, i, length);
46263d27a9233fed934340231f438493746084a681dJeff Sharkey            if (operations != null) operations = Arrays.copyOfRange(operations, i, length);
46375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            bucketCount -= i;
46463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
46563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // TODO: subtract removed values from totalBytes
46675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
46775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
46875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
46961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    /**
47019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     * Return interpolated data usage across the requested range. Interpolates
47119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     * across buckets, so values may be rounded slightly.
47219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     */
473434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    public Entry getValues(long start, long end, Entry recycle) {
474434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        return getValues(start, end, Long.MAX_VALUE, recycle);
475434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    }
476434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey
477434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    /**
478434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey     * Return interpolated data usage across the requested range. Interpolates
479434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey     * across buckets, so values may be rounded slightly.
480434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey     */
481434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    public Entry getValues(long start, long end, long now, Entry recycle) {
482434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        final Entry entry = recycle != null ? recycle : new Entry();
483434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        entry.bucketDuration = end - start;
484558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        entry.bucketStart = start;
485558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        entry.activeTime = activeTime != null ? 0 : UNKNOWN;
48663d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.rxBytes = rxBytes != null ? 0 : UNKNOWN;
48763d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.rxPackets = rxPackets != null ? 0 : UNKNOWN;
48863d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.txBytes = txBytes != null ? 0 : UNKNOWN;
48963d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.txPackets = txPackets != null ? 0 : UNKNOWN;
49063d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.operations = operations != null ? 0 : UNKNOWN;
49119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
49269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        final int startIndex = getIndexAfter(end);
49369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        for (int i = startIndex; i >= 0; i--) {
49419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey            final long curStart = bucketStart[i];
49519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey            final long curEnd = curStart + bucketDuration;
49619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
49734c73acf88c8190b8cd51d8b8f2b9c22aa7f7941Jeff Sharkey            // bucket is older than request; we're finished
49834c73acf88c8190b8cd51d8b8f2b9c22aa7f7941Jeff Sharkey            if (curEnd <= start) break;
49934c73acf88c8190b8cd51d8b8f2b9c22aa7f7941Jeff Sharkey            // bucket is newer than request; keep looking
50034c73acf88c8190b8cd51d8b8f2b9c22aa7f7941Jeff Sharkey            if (curStart >= end) continue;
50119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
502434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            // include full value for active buckets, otherwise only fractional
503434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            final boolean activeBucket = curStart < now && curEnd > now;
50469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            final long overlap;
50569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            if (activeBucket) {
50669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                overlap = bucketDuration;
50769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            } else {
50869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                final long overlapEnd = curEnd < end ? curEnd : end;
50969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                final long overlapStart = curStart > start ? curStart : start;
51069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                overlap = overlapEnd - overlapStart;
51169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            }
512a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (overlap <= 0) continue;
513a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
514a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            // integer math each time is faster than floating point
515558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            if (activeTime != null) entry.activeTime += activeTime[i] * overlap / bucketDuration;
51663d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketDuration;
51763d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketDuration;
51863d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketDuration;
51963d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration;
52063d27a9233fed934340231f438493746084a681dJeff Sharkey            if (operations != null) entry.operations += operations[i] * overlap / bucketDuration;
52119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        }
522434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        return entry;
52319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    }
52419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
52519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    /**
52661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey     * @deprecated only for temporary testing
52761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey     */
52861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    @Deprecated
529293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    public void generateRandom(long start, long end, long bytes) {
530293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final Random r = new Random();
531293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey
532293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final float fractionRx = r.nextFloat();
533293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long rxBytes = (long) (bytes * fractionRx);
534293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long txBytes = (long) (bytes * (1 - fractionRx));
535293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey
536293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long rxPackets = rxBytes / 1024;
537293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long txPackets = txBytes / 1024;
538293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long operations = rxBytes / 2048;
539293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey
540293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        generateRandom(start, end, rxBytes, rxPackets, txBytes, txPackets, operations, r);
541293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    }
542293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey
543293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    /**
544293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey     * @deprecated only for temporary testing
545293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey     */
546293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    @Deprecated
54763d27a9233fed934340231f438493746084a681dJeff Sharkey    public void generateRandom(long start, long end, long rxBytes, long rxPackets, long txBytes,
548293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey            long txPackets, long operations, Random r) {
54961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        ensureBuckets(start, end);
55061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
551a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        final NetworkStats.Entry entry = new NetworkStats.Entry(
552b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
55304cd0e47dbc1e9769ac6f258c923d5b17fa57986Jeff Sharkey        while (rxBytes > 1024 || rxPackets > 128 || txBytes > 1024 || txPackets > 128
55404cd0e47dbc1e9769ac6f258c923d5b17fa57986Jeff Sharkey                || operations > 32) {
55561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            final long curStart = randomLong(r, start, end);
556293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey            final long curEnd = curStart + randomLong(r, 0, (end - curStart) / 2);
55763d27a9233fed934340231f438493746084a681dJeff Sharkey
55863d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.rxBytes = randomLong(r, 0, rxBytes);
55963d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.rxPackets = randomLong(r, 0, rxPackets);
56063d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.txBytes = randomLong(r, 0, txBytes);
56163d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.txPackets = randomLong(r, 0, txPackets);
56263d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.operations = randomLong(r, 0, operations);
56363d27a9233fed934340231f438493746084a681dJeff Sharkey
56463d27a9233fed934340231f438493746084a681dJeff Sharkey            rxBytes -= entry.rxBytes;
56563d27a9233fed934340231f438493746084a681dJeff Sharkey            rxPackets -= entry.rxPackets;
56663d27a9233fed934340231f438493746084a681dJeff Sharkey            txBytes -= entry.txBytes;
56763d27a9233fed934340231f438493746084a681dJeff Sharkey            txPackets -= entry.txPackets;
56863d27a9233fed934340231f438493746084a681dJeff Sharkey            operations -= entry.operations;
569f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey
570f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey            recordData(curStart, curEnd, entry);
57161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        }
57261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    }
57361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
574293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    public static long randomLong(Random r, long start, long end) {
57561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        return (long) (start + (r.nextFloat() * (end - start)));
57661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    }
57761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
57855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    /**
57955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey     * Quickly determine if this history intersects with given window.
58055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey     */
58155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    public boolean intersects(long start, long end) {
58255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        final long dataStart = getStart();
58355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        final long dataEnd = getEnd();
58455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (start >= dataStart && start <= dataEnd) return true;
58555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (end >= dataStart && end <= dataEnd) return true;
58655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (dataStart >= start && dataStart <= end) return true;
58755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (dataEnd >= start && dataEnd <= end) return true;
58855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        return false;
58955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    }
59055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey
59163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void dump(IndentingPrintWriter pw, boolean fullHistory) {
59255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        pw.print("NetworkStatsHistory: bucketDuration=");
59355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        pw.println(bucketDuration / SECOND_IN_MILLIS);
59463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        pw.increaseIndent();
595350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey
596350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32);
597350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        if (start > 0) {
59863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            pw.print("(omitting "); pw.print(start); pw.println(" buckets)");
599350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        }
600350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey
601350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        for (int i = start; i < bucketCount; i++) {
60255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            pw.print("st="); pw.print(bucketStart[i] / SECOND_IN_MILLIS);
60355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (rxBytes != null) { pw.print(" rb="); pw.print(rxBytes[i]); }
60455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (rxPackets != null) { pw.print(" rp="); pw.print(rxPackets[i]); }
60555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (txBytes != null) { pw.print(" tb="); pw.print(txBytes[i]); }
60655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (txPackets != null) { pw.print(" tp="); pw.print(txPackets[i]); }
60755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (operations != null) { pw.print(" op="); pw.print(operations[i]); }
60863d27a9233fed934340231f438493746084a681dJeff Sharkey            pw.println();
60975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
61063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
61163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        pw.decreaseIndent();
61275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
61375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
61455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    public void dumpCheckin(PrintWriter pw) {
61555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        pw.print("d,");
61655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        pw.print(bucketDuration / SECOND_IN_MILLIS);
61755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        pw.println();
61855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey
61955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        for (int i = 0; i < bucketCount; i++) {
62055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            pw.print("b,");
62155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            pw.print(bucketStart[i] / SECOND_IN_MILLIS); pw.print(',');
62255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (rxBytes != null) { pw.print(rxBytes[i]); } else { pw.print("*"); } pw.print(',');
62355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (rxPackets != null) { pw.print(rxPackets[i]); } else { pw.print("*"); } pw.print(',');
62455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (txBytes != null) { pw.print(txBytes[i]); } else { pw.print("*"); } pw.print(',');
62555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (txPackets != null) { pw.print(txPackets[i]); } else { pw.print("*"); } pw.print(',');
62655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (operations != null) { pw.print(operations[i]); } else { pw.print("*"); }
62755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            pw.println();
62855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        }
62955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    }
63055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey
63175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    @Override
63275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public String toString() {
63375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final CharArrayWriter writer = new CharArrayWriter();
63463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        dump(new IndentingPrintWriter(writer, "  "), false);
63575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        return writer.toString();
63675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
63775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
63875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public static final Creator<NetworkStatsHistory> CREATOR = new Creator<NetworkStatsHistory>() {
639bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
64075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        public NetworkStatsHistory createFromParcel(Parcel in) {
64175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            return new NetworkStatsHistory(in);
64275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
64375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
644bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
64575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        public NetworkStatsHistory[] newArray(int size) {
64675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            return new NetworkStatsHistory[size];
64775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
64875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    };
64975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
65063d27a9233fed934340231f438493746084a681dJeff Sharkey    private static long getLong(long[] array, int i, long value) {
65163d27a9233fed934340231f438493746084a681dJeff Sharkey        return array != null ? array[i] : value;
65263d27a9233fed934340231f438493746084a681dJeff Sharkey    }
65363d27a9233fed934340231f438493746084a681dJeff Sharkey
65463d27a9233fed934340231f438493746084a681dJeff Sharkey    private static void setLong(long[] array, int i, long value) {
65563d27a9233fed934340231f438493746084a681dJeff Sharkey        if (array != null) array[i] = value;
65663d27a9233fed934340231f438493746084a681dJeff Sharkey    }
65763d27a9233fed934340231f438493746084a681dJeff Sharkey
65863d27a9233fed934340231f438493746084a681dJeff Sharkey    private static void addLong(long[] array, int i, long value) {
65963d27a9233fed934340231f438493746084a681dJeff Sharkey        if (array != null) array[i] += value;
66063d27a9233fed934340231f438493746084a681dJeff Sharkey    }
66163d27a9233fed934340231f438493746084a681dJeff Sharkey
66263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public int estimateResizeBuckets(long newBucketDuration) {
66363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return (int) (size() * getBucketDuration() / newBucketDuration);
66463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
66563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
666a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /**
667a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * Utility methods for interacting with {@link DataInputStream} and
668a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * {@link DataOutputStream}, mostly dealing with writing partial arrays.
669a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     */
670a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public static class DataStreamUtils {
67163d27a9233fed934340231f438493746084a681dJeff Sharkey        @Deprecated
67263d27a9233fed934340231f438493746084a681dJeff Sharkey        public static long[] readFullLongArray(DataInputStream in) throws IOException {
673a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final int size = in.readInt();
6741f99a483e410811473b12d8efedd79c738df7af3Jeff Sharkey            if (size < 0) throw new ProtocolException("negative array size");
675a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final long[] values = new long[size];
676a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            for (int i = 0; i < values.length; i++) {
677a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                values[i] = in.readLong();
678a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
679a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            return values;
680a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        }
681a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
68263d27a9233fed934340231f438493746084a681dJeff Sharkey        /**
68363d27a9233fed934340231f438493746084a681dJeff Sharkey         * Read variable-length {@link Long} using protobuf-style approach.
68463d27a9233fed934340231f438493746084a681dJeff Sharkey         */
68563d27a9233fed934340231f438493746084a681dJeff Sharkey        public static long readVarLong(DataInputStream in) throws IOException {
68663d27a9233fed934340231f438493746084a681dJeff Sharkey            int shift = 0;
68763d27a9233fed934340231f438493746084a681dJeff Sharkey            long result = 0;
68863d27a9233fed934340231f438493746084a681dJeff Sharkey            while (shift < 64) {
68963d27a9233fed934340231f438493746084a681dJeff Sharkey                byte b = in.readByte();
69063d27a9233fed934340231f438493746084a681dJeff Sharkey                result |= (long) (b & 0x7F) << shift;
69163d27a9233fed934340231f438493746084a681dJeff Sharkey                if ((b & 0x80) == 0)
69263d27a9233fed934340231f438493746084a681dJeff Sharkey                    return result;
69363d27a9233fed934340231f438493746084a681dJeff Sharkey                shift += 7;
69463d27a9233fed934340231f438493746084a681dJeff Sharkey            }
69563d27a9233fed934340231f438493746084a681dJeff Sharkey            throw new ProtocolException("malformed long");
69663d27a9233fed934340231f438493746084a681dJeff Sharkey        }
69763d27a9233fed934340231f438493746084a681dJeff Sharkey
69863d27a9233fed934340231f438493746084a681dJeff Sharkey        /**
69963d27a9233fed934340231f438493746084a681dJeff Sharkey         * Write variable-length {@link Long} using protobuf-style approach.
70063d27a9233fed934340231f438493746084a681dJeff Sharkey         */
70163d27a9233fed934340231f438493746084a681dJeff Sharkey        public static void writeVarLong(DataOutputStream out, long value) throws IOException {
70263d27a9233fed934340231f438493746084a681dJeff Sharkey            while (true) {
70363d27a9233fed934340231f438493746084a681dJeff Sharkey                if ((value & ~0x7FL) == 0) {
70463d27a9233fed934340231f438493746084a681dJeff Sharkey                    out.writeByte((int) value);
70563d27a9233fed934340231f438493746084a681dJeff Sharkey                    return;
70663d27a9233fed934340231f438493746084a681dJeff Sharkey                } else {
70763d27a9233fed934340231f438493746084a681dJeff Sharkey                    out.writeByte(((int) value & 0x7F) | 0x80);
70863d27a9233fed934340231f438493746084a681dJeff Sharkey                    value >>>= 7;
70963d27a9233fed934340231f438493746084a681dJeff Sharkey                }
71063d27a9233fed934340231f438493746084a681dJeff Sharkey            }
71163d27a9233fed934340231f438493746084a681dJeff Sharkey        }
71263d27a9233fed934340231f438493746084a681dJeff Sharkey
71363d27a9233fed934340231f438493746084a681dJeff Sharkey        public static long[] readVarLongArray(DataInputStream in) throws IOException {
71463d27a9233fed934340231f438493746084a681dJeff Sharkey            final int size = in.readInt();
71563d27a9233fed934340231f438493746084a681dJeff Sharkey            if (size == -1) return null;
7161f99a483e410811473b12d8efedd79c738df7af3Jeff Sharkey            if (size < 0) throw new ProtocolException("negative array size");
71763d27a9233fed934340231f438493746084a681dJeff Sharkey            final long[] values = new long[size];
71863d27a9233fed934340231f438493746084a681dJeff Sharkey            for (int i = 0; i < values.length; i++) {
71963d27a9233fed934340231f438493746084a681dJeff Sharkey                values[i] = readVarLong(in);
72063d27a9233fed934340231f438493746084a681dJeff Sharkey            }
72163d27a9233fed934340231f438493746084a681dJeff Sharkey            return values;
72263d27a9233fed934340231f438493746084a681dJeff Sharkey        }
72363d27a9233fed934340231f438493746084a681dJeff Sharkey
72463d27a9233fed934340231f438493746084a681dJeff Sharkey        public static void writeVarLongArray(DataOutputStream out, long[] values, int size)
725a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                throws IOException {
72663d27a9233fed934340231f438493746084a681dJeff Sharkey            if (values == null) {
72763d27a9233fed934340231f438493746084a681dJeff Sharkey                out.writeInt(-1);
72863d27a9233fed934340231f438493746084a681dJeff Sharkey                return;
72963d27a9233fed934340231f438493746084a681dJeff Sharkey            }
730a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (size > values.length) {
731a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                throw new IllegalArgumentException("size larger than length");
732a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
733a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            out.writeInt(size);
734a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            for (int i = 0; i < size; i++) {
73563d27a9233fed934340231f438493746084a681dJeff Sharkey                writeVarLong(out, values[i]);
736a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
73775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
73875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
73975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
740a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /**
741a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * Utility methods for interacting with {@link Parcel} structures, mostly
742a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * dealing with writing partial arrays.
743a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     */
744a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public static class ParcelUtils {
745a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        public static long[] readLongArray(Parcel in) {
746a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final int size = in.readInt();
74763d27a9233fed934340231f438493746084a681dJeff Sharkey            if (size == -1) return null;
748a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final long[] values = new long[size];
749a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            for (int i = 0; i < values.length; i++) {
750a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                values[i] = in.readLong();
751a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
752a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            return values;
75375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
75475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
755a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        public static void writeLongArray(Parcel out, long[] values, int size) {
75663d27a9233fed934340231f438493746084a681dJeff Sharkey            if (values == null) {
75763d27a9233fed934340231f438493746084a681dJeff Sharkey                out.writeInt(-1);
75863d27a9233fed934340231f438493746084a681dJeff Sharkey                return;
759a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
760a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (size > values.length) {
761a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                throw new IllegalArgumentException("size larger than length");
762a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
763a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            out.writeInt(size);
764a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            for (int i = 0; i < size; i++) {
76563d27a9233fed934340231f438493746084a681dJeff Sharkey                out.writeLong(values[i]);
766a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
76775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
76875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
76975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
77075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey}
771