NetworkStatsHistory.java revision da65a52f87ca1a31c9e01e99756e38d37d7e7202
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;
34da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onukiimport android.service.NetworkStatsHistoryBucketProto;
35da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onukiimport android.service.NetworkStatsHistoryProto;
3669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkeyimport android.util.MathUtils;
37da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onukiimport android.util.proto.ProtoOutputStream;
3875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
3963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter;
4063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
4175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.CharArrayWriter;
4275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.DataInputStream;
4375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.DataOutputStream;
4475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.IOException;
4555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkeyimport java.io.PrintWriter;
4661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkeyimport java.net.ProtocolException;
4775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.util.Arrays;
4861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkeyimport java.util.Random;
4975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
5075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey/**
5175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Collection of historical network statistics, recorded into equally-sized
5275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * "buckets" in time. Internally it stores data in {@code long} series for more
5375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * efficient persistence.
5475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * <p>
5575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Each bucket is defined by a {@link #bucketStart} timestamp, and lasts for
5675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * {@link #bucketDuration}. Internally assumes that {@link #bucketStart} is
5775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * sorted at all times.
5875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey *
5975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * @hide
6075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */
6175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeypublic class NetworkStatsHistory implements Parcelable {
621b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey    private static final int VERSION_INIT = 1;
6363d27a9233fed934340231f438493746084a681dJeff Sharkey    private static final int VERSION_ADD_PACKETS = 2;
64558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    private static final int VERSION_ADD_ACTIVE = 3;
6575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
66558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_ACTIVE_TIME = 0x01;
67558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_RX_BYTES = 0x02;
68558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_RX_PACKETS = 0x04;
69558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_TX_BYTES = 0x08;
70558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_TX_PACKETS = 0x10;
71558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_OPERATIONS = 0x20;
72d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
7363d27a9233fed934340231f438493746084a681dJeff Sharkey    public static final int FIELD_ALL = 0xFFFFFFFF;
7463d27a9233fed934340231f438493746084a681dJeff Sharkey
7563d27a9233fed934340231f438493746084a681dJeff Sharkey    private long bucketDuration;
76d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private int bucketCount;
77d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] bucketStart;
78558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    private long[] activeTime;
79d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] rxBytes;
80a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    private long[] rxPackets;
81d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] txBytes;
82a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    private long[] txPackets;
8363d27a9233fed934340231f438493746084a681dJeff Sharkey    private long[] operations;
8463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private long totalBytes;
85d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
86d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public static class Entry {
8763d27a9233fed934340231f438493746084a681dJeff Sharkey        public static final long UNKNOWN = -1;
8863d27a9233fed934340231f438493746084a681dJeff Sharkey
89d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        public long bucketDuration;
90558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        public long bucketStart;
91558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        public long activeTime;
92d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        public long rxBytes;
93a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        public long rxPackets;
94d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        public long txBytes;
95a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        public long txPackets;
9663d27a9233fed934340231f438493746084a681dJeff Sharkey        public long operations;
97d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
9875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
99d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey    public NetworkStatsHistory(long bucketDuration) {
10063d27a9233fed934340231f438493746084a681dJeff Sharkey        this(bucketDuration, 10, FIELD_ALL);
1014a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey    }
1024a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey
1034a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey    public NetworkStatsHistory(long bucketDuration, int initialSize) {
10463d27a9233fed934340231f438493746084a681dJeff Sharkey        this(bucketDuration, initialSize, FIELD_ALL);
10563d27a9233fed934340231f438493746084a681dJeff Sharkey    }
10663d27a9233fed934340231f438493746084a681dJeff Sharkey
10763d27a9233fed934340231f438493746084a681dJeff Sharkey    public NetworkStatsHistory(long bucketDuration, int initialSize, int fields) {
10875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        this.bucketDuration = bucketDuration;
1094a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        bucketStart = new long[initialSize];
110558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        if ((fields & FIELD_ACTIVE_TIME) != 0) activeTime = new long[initialSize];
11163d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_RX_BYTES) != 0) rxBytes = new long[initialSize];
11263d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_RX_PACKETS) != 0) rxPackets = new long[initialSize];
11363d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_TX_BYTES) != 0) txBytes = new long[initialSize];
11463d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_TX_PACKETS) != 0) txPackets = new long[initialSize];
11563d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_OPERATIONS) != 0) operations = new long[initialSize];
1164a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        bucketCount = 0;
11763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        totalBytes = 0;
11863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
11963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
12063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public NetworkStatsHistory(NetworkStatsHistory existing, long bucketDuration) {
12163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        this(bucketDuration, existing.estimateResizeBuckets(bucketDuration));
12263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        recordEntireHistory(existing);
12375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
12475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
12575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public NetworkStatsHistory(Parcel in) {
12675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketDuration = in.readLong();
12775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketStart = readLongArray(in);
128558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        activeTime = readLongArray(in);
129a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        rxBytes = readLongArray(in);
130a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        rxPackets = readLongArray(in);
131a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        txBytes = readLongArray(in);
132a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        txPackets = readLongArray(in);
13363d27a9233fed934340231f438493746084a681dJeff Sharkey        operations = readLongArray(in);
13475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketCount = bucketStart.length;
13563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        totalBytes = in.readLong();
13675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
13775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
138bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey    @Override
13975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void writeToParcel(Parcel out, int flags) {
14075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        out.writeLong(bucketDuration);
14175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        writeLongArray(out, bucketStart, bucketCount);
142558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        writeLongArray(out, activeTime, bucketCount);
143d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        writeLongArray(out, rxBytes, bucketCount);
144a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        writeLongArray(out, rxPackets, bucketCount);
145d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        writeLongArray(out, txBytes, bucketCount);
146a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        writeLongArray(out, txPackets, bucketCount);
14763d27a9233fed934340231f438493746084a681dJeff Sharkey        writeLongArray(out, operations, bucketCount);
14863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        out.writeLong(totalBytes);
14975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
15075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
15175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public NetworkStatsHistory(DataInputStream in) throws IOException {
15275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final int version = in.readInt();
15361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        switch (version) {
1541b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey            case VERSION_INIT: {
15561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey                bucketDuration = in.readLong();
15663d27a9233fed934340231f438493746084a681dJeff Sharkey                bucketStart = readFullLongArray(in);
15763d27a9233fed934340231f438493746084a681dJeff Sharkey                rxBytes = readFullLongArray(in);
158a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                rxPackets = new long[bucketStart.length];
15963d27a9233fed934340231f438493746084a681dJeff Sharkey                txBytes = readFullLongArray(in);
160a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                txPackets = new long[bucketStart.length];
16163d27a9233fed934340231f438493746084a681dJeff Sharkey                operations = new long[bucketStart.length];
16263d27a9233fed934340231f438493746084a681dJeff Sharkey                bucketCount = bucketStart.length;
16363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                totalBytes = total(rxBytes) + total(txBytes);
16463d27a9233fed934340231f438493746084a681dJeff Sharkey                break;
16563d27a9233fed934340231f438493746084a681dJeff Sharkey            }
166558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            case VERSION_ADD_PACKETS:
167558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            case VERSION_ADD_ACTIVE: {
16863d27a9233fed934340231f438493746084a681dJeff Sharkey                bucketDuration = in.readLong();
16963d27a9233fed934340231f438493746084a681dJeff Sharkey                bucketStart = readVarLongArray(in);
170558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey                activeTime = (version >= VERSION_ADD_ACTIVE) ? readVarLongArray(in)
171558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey                        : new long[bucketStart.length];
17263d27a9233fed934340231f438493746084a681dJeff Sharkey                rxBytes = readVarLongArray(in);
17363d27a9233fed934340231f438493746084a681dJeff Sharkey                rxPackets = readVarLongArray(in);
17463d27a9233fed934340231f438493746084a681dJeff Sharkey                txBytes = readVarLongArray(in);
17563d27a9233fed934340231f438493746084a681dJeff Sharkey                txPackets = readVarLongArray(in);
17663d27a9233fed934340231f438493746084a681dJeff Sharkey                operations = readVarLongArray(in);
17761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey                bucketCount = bucketStart.length;
17863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                totalBytes = total(rxBytes) + total(txBytes);
17961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey                break;
18061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            }
18161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            default: {
18261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey                throw new ProtocolException("unexpected version: " + version);
18361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            }
18461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        }
185b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey
186b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey        if (bucketStart.length != bucketCount || rxBytes.length != bucketCount
187b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey                || rxPackets.length != bucketCount || txBytes.length != bucketCount
188b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey                || txPackets.length != bucketCount || operations.length != bucketCount) {
189b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey            throw new ProtocolException("Mismatched history lengths");
190b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey        }
19175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
19275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
19375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void writeToStream(DataOutputStream out) throws IOException {
194558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        out.writeInt(VERSION_ADD_ACTIVE);
19575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        out.writeLong(bucketDuration);
19663d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, bucketStart, bucketCount);
197558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        writeVarLongArray(out, activeTime, bucketCount);
19863d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, rxBytes, bucketCount);
19963d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, rxPackets, bucketCount);
20063d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, txBytes, bucketCount);
20163d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, txPackets, bucketCount);
20263d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, operations, bucketCount);
20375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
20475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
205bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey    @Override
20675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public int describeContents() {
20775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        return 0;
20875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
20975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
210d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public int size() {
211d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        return bucketCount;
212d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
213d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
214d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public long getBucketDuration() {
215d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        return bucketDuration;
216d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
217d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
218434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    public long getStart() {
219434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        if (bucketCount > 0) {
220434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            return bucketStart[0];
221434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        } else {
222434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            return Long.MAX_VALUE;
223434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        }
224434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    }
225434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey
226434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    public long getEnd() {
227434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        if (bucketCount > 0) {
228434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            return bucketStart[bucketCount - 1] + bucketDuration;
229434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        } else {
230434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            return Long.MIN_VALUE;
231434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        }
232434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    }
233434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey
234d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    /**
23563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Return total bytes represented by this history.
23663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
23763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public long getTotalBytes() {
23863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return totalBytes;
23963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
24063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
24163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
24269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     * Return index of bucket that contains or is immediately before the
24369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     * requested time.
24469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     */
24569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    public int getIndexBefore(long time) {
24669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
24769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        if (index < 0) {
24869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            index = (~index) - 1;
24969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        } else {
25069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            index -= 1;
25169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        }
25269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        return MathUtils.constrain(index, 0, bucketCount - 1);
25369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    }
25469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey
25569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    /**
25669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     * Return index of bucket that contains or is immediately after the
25769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     * requested time.
25869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     */
25969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    public int getIndexAfter(long time) {
26069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
26169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        if (index < 0) {
26269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            index = ~index;
26369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        } else {
26469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            index += 1;
26569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        }
26669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        return MathUtils.constrain(index, 0, bucketCount - 1);
26769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    }
26869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey
26969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    /**
270d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey     * Return specific stats entry.
271d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey     */
272d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public Entry getValues(int i, Entry recycle) {
273d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        final Entry entry = recycle != null ? recycle : new Entry();
274d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        entry.bucketStart = bucketStart[i];
275d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        entry.bucketDuration = bucketDuration;
276558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        entry.activeTime = getLong(activeTime, i, UNKNOWN);
27763d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.rxBytes = getLong(rxBytes, i, UNKNOWN);
27863d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.rxPackets = getLong(rxPackets, i, UNKNOWN);
27963d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.txBytes = getLong(txBytes, i, UNKNOWN);
28063d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.txPackets = getLong(txPackets, i, UNKNOWN);
28163d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.operations = getLong(operations, i, UNKNOWN);
282d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        return entry;
283d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
284d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
28575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
28675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Record that data traffic occurred in the given time range. Will
28775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * distribute across internal buckets, creating new buckets as needed.
28875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
289a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    @Deprecated
290a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void recordData(long start, long end, long rxBytes, long txBytes) {
291b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        recordData(start, end, new NetworkStats.Entry(
292b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L));
293a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
294a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
295a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /**
296a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * Record that data traffic occurred in the given time range. Will
297a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * distribute across internal buckets, creating new buckets as needed.
298a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     */
299a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void recordData(long start, long end, NetworkStats.Entry entry) {
30063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long rxBytes = entry.rxBytes;
30163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long rxPackets = entry.rxPackets;
30263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long txBytes = entry.txBytes;
30363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long txPackets = entry.txPackets;
30463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long operations = entry.operations;
30563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
30663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (entry.isNegative()) {
307a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            throw new IllegalArgumentException("tried recording negative data");
3081b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        }
30963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (entry.isEmpty()) {
310367d15ab1a33b6159447fa8542d4fa8ff148371cJeff Sharkey            return;
311367d15ab1a33b6159447fa8542d4fa8ff148371cJeff Sharkey        }
3121b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey
31375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // create any buckets needed by this range
31475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        ensureBuckets(start, end);
31575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
31675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // distribute data usage into buckets
317a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        long duration = end - start;
31869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        final int startIndex = getIndexAfter(end);
31969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        for (int i = startIndex; i >= 0; i--) {
32075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long curStart = bucketStart[i];
32175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long curEnd = curStart + bucketDuration;
32275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
32375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // bucket is older than record; we're finished
32475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (curEnd < start) break;
32575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // bucket is newer than record; keep looking
32675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (curStart > end) continue;
32775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
32875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long overlap = Math.min(curEnd, end) - Math.max(curStart, start);
329a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (overlap <= 0) continue;
330a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
331a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            // integer math each time is faster than floating point
33263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracRxBytes = rxBytes * overlap / duration;
33363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracRxPackets = rxPackets * overlap / duration;
33463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracTxBytes = txBytes * overlap / duration;
33563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracTxPackets = txPackets * overlap / duration;
33663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracOperations = operations * overlap / duration;
337a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
338558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            addLong(activeTime, i, overlap);
33963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.rxBytes, i, fracRxBytes); rxBytes -= fracRxBytes;
34063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.rxPackets, i, fracRxPackets); rxPackets -= fracRxPackets;
34163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.txBytes, i, fracTxBytes); txBytes -= fracTxBytes;
34263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.txPackets, i, fracTxPackets); txPackets -= fracTxPackets;
34363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.operations, i, fracOperations); operations -= fracOperations;
344a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
345a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            duration -= overlap;
34675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
34763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
34863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        totalBytes += entry.rxBytes + entry.txBytes;
34975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
35075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
35175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
35219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     * Record an entire {@link NetworkStatsHistory} into this history. Usually
35319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     * for combining together stats for external reporting.
35419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     */
35519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    public void recordEntireHistory(NetworkStatsHistory input) {
35670c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        recordHistory(input, Long.MIN_VALUE, Long.MAX_VALUE);
35770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    }
35870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey
35970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    /**
36070c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     * Record given {@link NetworkStatsHistory} into this history, copying only
36170c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     * buckets that atomically occur in the inclusive time range. Doesn't
36270c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     * interpolate across partial buckets.
36370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     */
36470c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    public void recordHistory(NetworkStatsHistory input, long start, long end) {
365a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        final NetworkStats.Entry entry = new NetworkStats.Entry(
366b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
36719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        for (int i = 0; i < input.bucketCount; i++) {
36870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            final long bucketStart = input.bucketStart[i];
36970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            final long bucketEnd = bucketStart + input.bucketDuration;
37070c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey
37170c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            // skip when bucket is outside requested range
37270c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            if (bucketStart < start || bucketEnd > end) continue;
373a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
37463d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.rxBytes = getLong(input.rxBytes, i, 0L);
37563d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.rxPackets = getLong(input.rxPackets, i, 0L);
37663d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.txBytes = getLong(input.txBytes, i, 0L);
37763d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.txPackets = getLong(input.txPackets, i, 0L);
37863d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.operations = getLong(input.operations, i, 0L);
379a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
38070c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            recordData(bucketStart, bucketEnd, entry);
38119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        }
38219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    }
38319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
38419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    /**
38575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Ensure that buckets exist for given time range, creating as needed.
38675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
38775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private void ensureBuckets(long start, long end) {
38875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // normalize incoming range to bucket boundaries
38975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        start -= start % bucketDuration;
39075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        end += (bucketDuration - (end % bucketDuration)) % bucketDuration;
39175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
39275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        for (long now = start; now < end; now += bucketDuration) {
39375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // try finding existing bucket
39475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final int index = Arrays.binarySearch(bucketStart, 0, bucketCount, now);
39575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (index < 0) {
39675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                // bucket missing, create and insert
39775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                insertBucket(~index, now);
39875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            }
39975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
40075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
40175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
40275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
40375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Insert new bucket at requested index and starting time.
40475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
40575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private void insertBucket(int index, long start) {
40675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // create more buckets when needed
4074a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        if (bucketCount >= bucketStart.length) {
4084a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey            final int newLength = Math.max(bucketStart.length, 10) * 3 / 2;
40975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            bucketStart = Arrays.copyOf(bucketStart, newLength);
410558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            if (activeTime != null) activeTime = Arrays.copyOf(activeTime, newLength);
41163d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxBytes != null) rxBytes = Arrays.copyOf(rxBytes, newLength);
41263d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxPackets != null) rxPackets = Arrays.copyOf(rxPackets, newLength);
41363d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txBytes != null) txBytes = Arrays.copyOf(txBytes, newLength);
41463d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txPackets != null) txPackets = Arrays.copyOf(txPackets, newLength);
41563d27a9233fed934340231f438493746084a681dJeff Sharkey            if (operations != null) operations = Arrays.copyOf(operations, newLength);
41675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
41775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
41875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // create gap when inserting bucket in middle
41975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        if (index < bucketCount) {
42075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final int dstPos = index + 1;
42175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final int length = bucketCount - index;
42275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
42375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            System.arraycopy(bucketStart, index, bucketStart, dstPos, length);
424558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            if (activeTime != null) System.arraycopy(activeTime, index, activeTime, dstPos, length);
42563d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxBytes != null) System.arraycopy(rxBytes, index, rxBytes, dstPos, length);
42663d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxPackets != null) System.arraycopy(rxPackets, index, rxPackets, dstPos, length);
42763d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txBytes != null) System.arraycopy(txBytes, index, txBytes, dstPos, length);
42863d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txPackets != null) System.arraycopy(txPackets, index, txPackets, dstPos, length);
42963d27a9233fed934340231f438493746084a681dJeff Sharkey            if (operations != null) System.arraycopy(operations, index, operations, dstPos, length);
43075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
43175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
43275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketStart[index] = start;
433558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        setLong(activeTime, index, 0L);
43463d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(rxBytes, index, 0L);
43563d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(rxPackets, index, 0L);
43663d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(txBytes, index, 0L);
43763d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(txPackets, index, 0L);
43863d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(operations, index, 0L);
43975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketCount++;
44075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
44175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
44275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
44375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Remove buckets older than requested cutoff.
44475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
44563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    @Deprecated
44675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void removeBucketsBefore(long cutoff) {
44775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        int i;
44875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        for (i = 0; i < bucketCount; i++) {
44975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long curStart = bucketStart[i];
45075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long curEnd = curStart + bucketDuration;
45175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
45275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // cutoff happens before or during this bucket; everything before
45375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // this bucket should be removed.
45475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (curEnd > cutoff) break;
45575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
45675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
45775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        if (i > 0) {
45875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final int length = bucketStart.length;
45975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            bucketStart = Arrays.copyOfRange(bucketStart, i, length);
460558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            if (activeTime != null) activeTime = Arrays.copyOfRange(activeTime, i, length);
46163d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxBytes != null) rxBytes = Arrays.copyOfRange(rxBytes, i, length);
46263d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxPackets != null) rxPackets = Arrays.copyOfRange(rxPackets, i, length);
46363d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txBytes != null) txBytes = Arrays.copyOfRange(txBytes, i, length);
46463d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txPackets != null) txPackets = Arrays.copyOfRange(txPackets, i, length);
46563d27a9233fed934340231f438493746084a681dJeff Sharkey            if (operations != null) operations = Arrays.copyOfRange(operations, i, length);
46675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            bucketCount -= i;
46763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
46863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // TODO: subtract removed values from totalBytes
46975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
47075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
47175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
47261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    /**
47319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     * Return interpolated data usage across the requested range. Interpolates
47419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     * across buckets, so values may be rounded slightly.
47519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     */
476434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    public Entry getValues(long start, long end, Entry recycle) {
477434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        return getValues(start, end, Long.MAX_VALUE, recycle);
478434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    }
479434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey
480434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    /**
481434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey     * Return interpolated data usage across the requested range. Interpolates
482434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey     * across buckets, so values may be rounded slightly.
483434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey     */
484434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    public Entry getValues(long start, long end, long now, Entry recycle) {
485434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        final Entry entry = recycle != null ? recycle : new Entry();
486434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        entry.bucketDuration = end - start;
487558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        entry.bucketStart = start;
488558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        entry.activeTime = activeTime != null ? 0 : UNKNOWN;
48963d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.rxBytes = rxBytes != null ? 0 : UNKNOWN;
49063d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.rxPackets = rxPackets != null ? 0 : UNKNOWN;
49163d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.txBytes = txBytes != null ? 0 : UNKNOWN;
49263d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.txPackets = txPackets != null ? 0 : UNKNOWN;
49363d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.operations = operations != null ? 0 : UNKNOWN;
49419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
49569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        final int startIndex = getIndexAfter(end);
49669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        for (int i = startIndex; i >= 0; i--) {
49719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey            final long curStart = bucketStart[i];
49819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey            final long curEnd = curStart + bucketDuration;
49919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
50034c73acf88c8190b8cd51d8b8f2b9c22aa7f7941Jeff Sharkey            // bucket is older than request; we're finished
50134c73acf88c8190b8cd51d8b8f2b9c22aa7f7941Jeff Sharkey            if (curEnd <= start) break;
50234c73acf88c8190b8cd51d8b8f2b9c22aa7f7941Jeff Sharkey            // bucket is newer than request; keep looking
50334c73acf88c8190b8cd51d8b8f2b9c22aa7f7941Jeff Sharkey            if (curStart >= end) continue;
50419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
505434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            // include full value for active buckets, otherwise only fractional
506434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            final boolean activeBucket = curStart < now && curEnd > now;
50769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            final long overlap;
50869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            if (activeBucket) {
50969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                overlap = bucketDuration;
51069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            } else {
51169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                final long overlapEnd = curEnd < end ? curEnd : end;
51269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                final long overlapStart = curStart > start ? curStart : start;
51369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                overlap = overlapEnd - overlapStart;
51469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            }
515a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (overlap <= 0) continue;
516a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
517a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            // integer math each time is faster than floating point
518558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            if (activeTime != null) entry.activeTime += activeTime[i] * overlap / bucketDuration;
51963d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketDuration;
52063d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketDuration;
52163d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketDuration;
52263d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration;
52363d27a9233fed934340231f438493746084a681dJeff Sharkey            if (operations != null) entry.operations += operations[i] * overlap / bucketDuration;
52419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        }
525434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        return entry;
52619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    }
52719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
52819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    /**
52961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey     * @deprecated only for temporary testing
53061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey     */
53161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    @Deprecated
532293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    public void generateRandom(long start, long end, long bytes) {
533293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final Random r = new Random();
534293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey
535293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final float fractionRx = r.nextFloat();
536293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long rxBytes = (long) (bytes * fractionRx);
537293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long txBytes = (long) (bytes * (1 - fractionRx));
538293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey
539293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long rxPackets = rxBytes / 1024;
540293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long txPackets = txBytes / 1024;
541293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long operations = rxBytes / 2048;
542293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey
543293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        generateRandom(start, end, rxBytes, rxPackets, txBytes, txPackets, operations, r);
544293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    }
545293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey
546293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    /**
547293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey     * @deprecated only for temporary testing
548293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey     */
549293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    @Deprecated
55063d27a9233fed934340231f438493746084a681dJeff Sharkey    public void generateRandom(long start, long end, long rxBytes, long rxPackets, long txBytes,
551293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey            long txPackets, long operations, Random r) {
55261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        ensureBuckets(start, end);
55361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
554a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        final NetworkStats.Entry entry = new NetworkStats.Entry(
555b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
55604cd0e47dbc1e9769ac6f258c923d5b17fa57986Jeff Sharkey        while (rxBytes > 1024 || rxPackets > 128 || txBytes > 1024 || txPackets > 128
55704cd0e47dbc1e9769ac6f258c923d5b17fa57986Jeff Sharkey                || operations > 32) {
55861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            final long curStart = randomLong(r, start, end);
559293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey            final long curEnd = curStart + randomLong(r, 0, (end - curStart) / 2);
56063d27a9233fed934340231f438493746084a681dJeff Sharkey
56163d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.rxBytes = randomLong(r, 0, rxBytes);
56263d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.rxPackets = randomLong(r, 0, rxPackets);
56363d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.txBytes = randomLong(r, 0, txBytes);
56463d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.txPackets = randomLong(r, 0, txPackets);
56563d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.operations = randomLong(r, 0, operations);
56663d27a9233fed934340231f438493746084a681dJeff Sharkey
56763d27a9233fed934340231f438493746084a681dJeff Sharkey            rxBytes -= entry.rxBytes;
56863d27a9233fed934340231f438493746084a681dJeff Sharkey            rxPackets -= entry.rxPackets;
56963d27a9233fed934340231f438493746084a681dJeff Sharkey            txBytes -= entry.txBytes;
57063d27a9233fed934340231f438493746084a681dJeff Sharkey            txPackets -= entry.txPackets;
57163d27a9233fed934340231f438493746084a681dJeff Sharkey            operations -= entry.operations;
572f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey
573f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey            recordData(curStart, curEnd, entry);
57461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        }
57561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    }
57661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
577293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    public static long randomLong(Random r, long start, long end) {
57861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        return (long) (start + (r.nextFloat() * (end - start)));
57961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    }
58061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
58155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    /**
58255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey     * Quickly determine if this history intersects with given window.
58355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey     */
58455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    public boolean intersects(long start, long end) {
58555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        final long dataStart = getStart();
58655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        final long dataEnd = getEnd();
58755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (start >= dataStart && start <= dataEnd) return true;
58855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (end >= dataStart && end <= dataEnd) return true;
58955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (dataStart >= start && dataStart <= end) return true;
59055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (dataEnd >= start && dataEnd <= end) return true;
59155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        return false;
59255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    }
59355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey
59463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void dump(IndentingPrintWriter pw, boolean fullHistory) {
59555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        pw.print("NetworkStatsHistory: bucketDuration=");
59655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        pw.println(bucketDuration / SECOND_IN_MILLIS);
59763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        pw.increaseIndent();
598350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey
599350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32);
600350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        if (start > 0) {
60163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            pw.print("(omitting "); pw.print(start); pw.println(" buckets)");
602350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        }
603350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey
604350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        for (int i = start; i < bucketCount; i++) {
60555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            pw.print("st="); pw.print(bucketStart[i] / SECOND_IN_MILLIS);
60655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (rxBytes != null) { pw.print(" rb="); pw.print(rxBytes[i]); }
60755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (rxPackets != null) { pw.print(" rp="); pw.print(rxPackets[i]); }
60855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (txBytes != null) { pw.print(" tb="); pw.print(txBytes[i]); }
60955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (txPackets != null) { pw.print(" tp="); pw.print(txPackets[i]); }
61055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (operations != null) { pw.print(" op="); pw.print(operations[i]); }
61163d27a9233fed934340231f438493746084a681dJeff Sharkey            pw.println();
61275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
61363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
61463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        pw.decreaseIndent();
61575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
61675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
61755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    public void dumpCheckin(PrintWriter pw) {
61855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        pw.print("d,");
61955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        pw.print(bucketDuration / SECOND_IN_MILLIS);
62055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        pw.println();
62155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey
62255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        for (int i = 0; i < bucketCount; i++) {
62355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            pw.print("b,");
62455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            pw.print(bucketStart[i] / SECOND_IN_MILLIS); pw.print(',');
62555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (rxBytes != null) { pw.print(rxBytes[i]); } else { pw.print("*"); } pw.print(',');
62655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (rxPackets != null) { pw.print(rxPackets[i]); } else { pw.print("*"); } pw.print(',');
62755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (txBytes != null) { pw.print(txBytes[i]); } else { pw.print("*"); } pw.print(',');
62855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (txPackets != null) { pw.print(txPackets[i]); } else { pw.print("*"); } pw.print(',');
62955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (operations != null) { pw.print(operations[i]); } else { pw.print("*"); }
63055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            pw.println();
63155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        }
63255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    }
63355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey
634da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki    public void writeToProto(ProtoOutputStream proto, long tag) {
635da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        final long start = proto.start(tag);
636da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki
637da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration);
638da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki
639da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        for (int i = 0; i < bucketCount; i++) {
640da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS);
641da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki
642da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]);
643da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            writeToProto(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i);
644da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            writeToProto(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i);
645da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            writeToProto(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i);
646da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            writeToProto(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i);
647da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            writeToProto(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i);
648da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki
649da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            proto.end(startBucket);
650da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        }
651da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki
652da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        proto.end(start);
653da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki    }
654da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki
655da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki    private static void writeToProto(ProtoOutputStream proto, long tag, long[] array, int index) {
656da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        if (array != null) {
657da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            proto.write(tag, array[index]);
658da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        }
659da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki    }
660da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki
66175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    @Override
66275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public String toString() {
66375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final CharArrayWriter writer = new CharArrayWriter();
66463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        dump(new IndentingPrintWriter(writer, "  "), false);
66575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        return writer.toString();
66675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
66775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
66875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public static final Creator<NetworkStatsHistory> CREATOR = new Creator<NetworkStatsHistory>() {
669bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
67075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        public NetworkStatsHistory createFromParcel(Parcel in) {
67175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            return new NetworkStatsHistory(in);
67275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
67375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
674bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
67575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        public NetworkStatsHistory[] newArray(int size) {
67675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            return new NetworkStatsHistory[size];
67775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
67875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    };
67975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
68063d27a9233fed934340231f438493746084a681dJeff Sharkey    private static long getLong(long[] array, int i, long value) {
68163d27a9233fed934340231f438493746084a681dJeff Sharkey        return array != null ? array[i] : value;
68263d27a9233fed934340231f438493746084a681dJeff Sharkey    }
68363d27a9233fed934340231f438493746084a681dJeff Sharkey
68463d27a9233fed934340231f438493746084a681dJeff Sharkey    private static void setLong(long[] array, int i, long value) {
68563d27a9233fed934340231f438493746084a681dJeff Sharkey        if (array != null) array[i] = value;
68663d27a9233fed934340231f438493746084a681dJeff Sharkey    }
68763d27a9233fed934340231f438493746084a681dJeff Sharkey
68863d27a9233fed934340231f438493746084a681dJeff Sharkey    private static void addLong(long[] array, int i, long value) {
68963d27a9233fed934340231f438493746084a681dJeff Sharkey        if (array != null) array[i] += value;
69063d27a9233fed934340231f438493746084a681dJeff Sharkey    }
69163d27a9233fed934340231f438493746084a681dJeff Sharkey
69263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public int estimateResizeBuckets(long newBucketDuration) {
69363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return (int) (size() * getBucketDuration() / newBucketDuration);
69463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
69563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
696a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /**
697a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * Utility methods for interacting with {@link DataInputStream} and
698a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * {@link DataOutputStream}, mostly dealing with writing partial arrays.
699a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     */
700a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public static class DataStreamUtils {
70163d27a9233fed934340231f438493746084a681dJeff Sharkey        @Deprecated
70263d27a9233fed934340231f438493746084a681dJeff Sharkey        public static long[] readFullLongArray(DataInputStream in) throws IOException {
703a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final int size = in.readInt();
7041f99a483e410811473b12d8efedd79c738df7af3Jeff Sharkey            if (size < 0) throw new ProtocolException("negative array size");
705a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final long[] values = new long[size];
706a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            for (int i = 0; i < values.length; i++) {
707a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                values[i] = in.readLong();
708a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
709a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            return values;
710a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        }
711a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
71263d27a9233fed934340231f438493746084a681dJeff Sharkey        /**
71363d27a9233fed934340231f438493746084a681dJeff Sharkey         * Read variable-length {@link Long} using protobuf-style approach.
71463d27a9233fed934340231f438493746084a681dJeff Sharkey         */
71563d27a9233fed934340231f438493746084a681dJeff Sharkey        public static long readVarLong(DataInputStream in) throws IOException {
71663d27a9233fed934340231f438493746084a681dJeff Sharkey            int shift = 0;
71763d27a9233fed934340231f438493746084a681dJeff Sharkey            long result = 0;
71863d27a9233fed934340231f438493746084a681dJeff Sharkey            while (shift < 64) {
71963d27a9233fed934340231f438493746084a681dJeff Sharkey                byte b = in.readByte();
72063d27a9233fed934340231f438493746084a681dJeff Sharkey                result |= (long) (b & 0x7F) << shift;
72163d27a9233fed934340231f438493746084a681dJeff Sharkey                if ((b & 0x80) == 0)
72263d27a9233fed934340231f438493746084a681dJeff Sharkey                    return result;
72363d27a9233fed934340231f438493746084a681dJeff Sharkey                shift += 7;
72463d27a9233fed934340231f438493746084a681dJeff Sharkey            }
72563d27a9233fed934340231f438493746084a681dJeff Sharkey            throw new ProtocolException("malformed long");
72663d27a9233fed934340231f438493746084a681dJeff Sharkey        }
72763d27a9233fed934340231f438493746084a681dJeff Sharkey
72863d27a9233fed934340231f438493746084a681dJeff Sharkey        /**
72963d27a9233fed934340231f438493746084a681dJeff Sharkey         * Write variable-length {@link Long} using protobuf-style approach.
73063d27a9233fed934340231f438493746084a681dJeff Sharkey         */
73163d27a9233fed934340231f438493746084a681dJeff Sharkey        public static void writeVarLong(DataOutputStream out, long value) throws IOException {
73263d27a9233fed934340231f438493746084a681dJeff Sharkey            while (true) {
73363d27a9233fed934340231f438493746084a681dJeff Sharkey                if ((value & ~0x7FL) == 0) {
73463d27a9233fed934340231f438493746084a681dJeff Sharkey                    out.writeByte((int) value);
73563d27a9233fed934340231f438493746084a681dJeff Sharkey                    return;
73663d27a9233fed934340231f438493746084a681dJeff Sharkey                } else {
73763d27a9233fed934340231f438493746084a681dJeff Sharkey                    out.writeByte(((int) value & 0x7F) | 0x80);
73863d27a9233fed934340231f438493746084a681dJeff Sharkey                    value >>>= 7;
73963d27a9233fed934340231f438493746084a681dJeff Sharkey                }
74063d27a9233fed934340231f438493746084a681dJeff Sharkey            }
74163d27a9233fed934340231f438493746084a681dJeff Sharkey        }
74263d27a9233fed934340231f438493746084a681dJeff Sharkey
74363d27a9233fed934340231f438493746084a681dJeff Sharkey        public static long[] readVarLongArray(DataInputStream in) throws IOException {
74463d27a9233fed934340231f438493746084a681dJeff Sharkey            final int size = in.readInt();
74563d27a9233fed934340231f438493746084a681dJeff Sharkey            if (size == -1) return null;
7461f99a483e410811473b12d8efedd79c738df7af3Jeff Sharkey            if (size < 0) throw new ProtocolException("negative array size");
74763d27a9233fed934340231f438493746084a681dJeff Sharkey            final long[] values = new long[size];
74863d27a9233fed934340231f438493746084a681dJeff Sharkey            for (int i = 0; i < values.length; i++) {
74963d27a9233fed934340231f438493746084a681dJeff Sharkey                values[i] = readVarLong(in);
75063d27a9233fed934340231f438493746084a681dJeff Sharkey            }
75163d27a9233fed934340231f438493746084a681dJeff Sharkey            return values;
75263d27a9233fed934340231f438493746084a681dJeff Sharkey        }
75363d27a9233fed934340231f438493746084a681dJeff Sharkey
75463d27a9233fed934340231f438493746084a681dJeff Sharkey        public static void writeVarLongArray(DataOutputStream out, long[] values, int size)
755a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                throws IOException {
75663d27a9233fed934340231f438493746084a681dJeff Sharkey            if (values == null) {
75763d27a9233fed934340231f438493746084a681dJeff Sharkey                out.writeInt(-1);
75863d27a9233fed934340231f438493746084a681dJeff Sharkey                return;
75963d27a9233fed934340231f438493746084a681dJeff 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                writeVarLong(out, values[i]);
766a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
76775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
76875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
76975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
770a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /**
771a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * Utility methods for interacting with {@link Parcel} structures, mostly
772a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * dealing with writing partial arrays.
773a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     */
774a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public static class ParcelUtils {
775a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        public static long[] readLongArray(Parcel in) {
776a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final int size = in.readInt();
77763d27a9233fed934340231f438493746084a681dJeff Sharkey            if (size == -1) return null;
778a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final long[] values = new long[size];
779a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            for (int i = 0; i < values.length; i++) {
780a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                values[i] = in.readLong();
781a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
782a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            return values;
78375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
78475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
785a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        public static void writeLongArray(Parcel out, long[] values, int size) {
78663d27a9233fed934340231f438493746084a681dJeff Sharkey            if (values == null) {
78763d27a9233fed934340231f438493746084a681dJeff Sharkey                out.writeInt(-1);
78863d27a9233fed934340231f438493746084a681dJeff Sharkey                return;
789a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
790a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (size > values.length) {
791a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                throw new IllegalArgumentException("size larger than length");
792a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
793a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            out.writeInt(size);
794a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            for (int i = 0; i < size; i++) {
79563d27a9233fed934340231f438493746084a681dJeff Sharkey                out.writeLong(values[i]);
796a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
79775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
79875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
79975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
80075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey}
801