2626import static android .net .NetworkStatsHistory .Entry .UNKNOWN ;
2727import static android .net .NetworkStatsHistory .ParcelUtils .readLongArray ;
2828import static android .net .NetworkStatsHistory .ParcelUtils .writeLongArray ;
29+ import static com .android .internal .util .ArrayUtils .total ;
2930
3031import android .os .Parcel ;
3132import android .os .Parcelable ;
3233import android .util .MathUtils ;
3334
35+ import com .android .internal .util .IndentingPrintWriter ;
36+
3437import java .io .CharArrayWriter ;
3538import java .io .DataInputStream ;
3639import java .io .DataOutputStream ;
3740import java .io .IOException ;
38- import java .io .PrintWriter ;
3941import java .net .ProtocolException ;
4042import java .util .Arrays ;
4143import java .util .Random ;
@@ -74,6 +76,7 @@ public class NetworkStatsHistory implements Parcelable {
7476 private long [] txBytes ;
7577 private long [] txPackets ;
7678 private long [] operations ;
79+ private long totalBytes ;
7780
7881 public static class Entry {
7982 public static final long UNKNOWN = -1 ;
@@ -106,6 +109,12 @@ public NetworkStatsHistory(long bucketDuration, int initialSize, int fields) {
106109 if ((fields & FIELD_TX_PACKETS ) != 0 ) txPackets = new long [initialSize ];
107110 if ((fields & FIELD_OPERATIONS ) != 0 ) operations = new long [initialSize ];
108111 bucketCount = 0 ;
112+ totalBytes = 0 ;
113+ }
114+
115+ public NetworkStatsHistory (NetworkStatsHistory existing , long bucketDuration ) {
116+ this (bucketDuration , existing .estimateResizeBuckets (bucketDuration ));
117+ recordEntireHistory (existing );
109118 }
110119
111120 public NetworkStatsHistory (Parcel in ) {
@@ -118,6 +127,7 @@ public NetworkStatsHistory(Parcel in) {
118127 txPackets = readLongArray (in );
119128 operations = readLongArray (in );
120129 bucketCount = bucketStart .length ;
130+ totalBytes = in .readLong ();
121131 }
122132
123133 /** {@inheritDoc} */
@@ -130,6 +140,7 @@ public void writeToParcel(Parcel out, int flags) {
130140 writeLongArray (out , txBytes , bucketCount );
131141 writeLongArray (out , txPackets , bucketCount );
132142 writeLongArray (out , operations , bucketCount );
143+ out .writeLong (totalBytes );
133144 }
134145
135146 public NetworkStatsHistory (DataInputStream in ) throws IOException {
@@ -144,6 +155,7 @@ public NetworkStatsHistory(DataInputStream in) throws IOException {
144155 txPackets = new long [bucketStart .length ];
145156 operations = new long [bucketStart .length ];
146157 bucketCount = bucketStart .length ;
158+ totalBytes = total (rxBytes ) + total (txBytes );
147159 break ;
148160 }
149161 case VERSION_ADD_PACKETS :
@@ -158,6 +170,7 @@ public NetworkStatsHistory(DataInputStream in) throws IOException {
158170 txPackets = readVarLongArray (in );
159171 operations = readVarLongArray (in );
160172 bucketCount = bucketStart .length ;
173+ totalBytes = total (rxBytes ) + total (txBytes );
161174 break ;
162175 }
163176 default : {
@@ -207,6 +220,13 @@ public long getEnd() {
207220 }
208221 }
209222
223+ /**
224+ * Return total bytes represented by this history.
225+ */
226+ public long getTotalBytes () {
227+ return totalBytes ;
228+ }
229+
210230 /**
211231 * Return index of bucket that contains or is immediately before the
212232 * requested time.
@@ -266,13 +286,16 @@ public void recordData(long start, long end, long rxBytes, long txBytes) {
266286 * distribute across internal buckets, creating new buckets as needed.
267287 */
268288 public void recordData (long start , long end , NetworkStats .Entry entry ) {
269- if (entry .rxBytes < 0 || entry .rxPackets < 0 || entry .txBytes < 0 || entry .txPackets < 0
270- || entry .operations < 0 ) {
289+ long rxBytes = entry .rxBytes ;
290+ long rxPackets = entry .rxPackets ;
291+ long txBytes = entry .txBytes ;
292+ long txPackets = entry .txPackets ;
293+ long operations = entry .operations ;
294+
295+ if (entry .isNegative ()) {
271296 throw new IllegalArgumentException ("tried recording negative data" );
272297 }
273- if (entry .rxBytes == 0 && entry .rxPackets == 0 && entry .txBytes == 0 && entry .txPackets == 0
274- && entry .operations == 0 ) {
275- // nothing to record; skip
298+ if (entry .isEmpty ()) {
276299 return ;
277300 }
278301
@@ -295,21 +318,23 @@ public void recordData(long start, long end, NetworkStats.Entry entry) {
295318 if (overlap <= 0 ) continue ;
296319
297320 // integer math each time is faster than floating point
298- final long fracRxBytes = entry . rxBytes * overlap / duration ;
299- final long fracRxPackets = entry . rxPackets * overlap / duration ;
300- final long fracTxBytes = entry . txBytes * overlap / duration ;
301- final long fracTxPackets = entry . txPackets * overlap / duration ;
302- final long fracOperations = entry . operations * overlap / duration ;
321+ final long fracRxBytes = rxBytes * overlap / duration ;
322+ final long fracRxPackets = rxPackets * overlap / duration ;
323+ final long fracTxBytes = txBytes * overlap / duration ;
324+ final long fracTxPackets = txPackets * overlap / duration ;
325+ final long fracOperations = operations * overlap / duration ;
303326
304327 addLong (activeTime , i , overlap );
305- addLong (rxBytes , i , fracRxBytes ); entry . rxBytes -= fracRxBytes ;
306- addLong (rxPackets , i , fracRxPackets ); entry . rxPackets -= fracRxPackets ;
307- addLong (txBytes , i , fracTxBytes ); entry . txBytes -= fracTxBytes ;
308- addLong (txPackets , i , fracTxPackets ); entry . txPackets -= fracTxPackets ;
309- addLong (operations , i , fracOperations ); entry . operations -= fracOperations ;
328+ addLong (this . rxBytes , i , fracRxBytes ); rxBytes -= fracRxBytes ;
329+ addLong (this . rxPackets , i , fracRxPackets ); rxPackets -= fracRxPackets ;
330+ addLong (this . txBytes , i , fracTxBytes ); txBytes -= fracTxBytes ;
331+ addLong (this . txPackets , i , fracTxPackets ); txPackets -= fracTxPackets ;
332+ addLong (this . operations , i , fracOperations ); operations -= fracOperations ;
310333
311334 duration -= overlap ;
312335 }
336+
337+ totalBytes += entry .rxBytes + entry .txBytes ;
313338 }
314339
315340 /**
@@ -394,6 +419,7 @@ private void insertBucket(int index, long start) {
394419 /**
395420 * Remove buckets older than requested cutoff.
396421 */
422+ @ Deprecated
397423 public void removeBucketsBefore (long cutoff ) {
398424 int i ;
399425 for (i = 0 ; i < bucketCount ; i ++) {
@@ -415,6 +441,8 @@ public void removeBucketsBefore(long cutoff) {
415441 if (txPackets != null ) txPackets = Arrays .copyOfRange (txPackets , i , length );
416442 if (operations != null ) operations = Arrays .copyOfRange (operations , i , length );
417443 bucketCount -= i ;
444+
445+ // TODO: subtract removed values from totalBytes
418446 }
419447 }
420448
@@ -527,19 +555,17 @@ public static long randomLong(Random r, long start, long end) {
527555 return (long ) (start + (r .nextFloat () * (end - start )));
528556 }
529557
530- public void dump (String prefix , PrintWriter pw , boolean fullHistory ) {
531- pw .print (prefix );
558+ public void dump (IndentingPrintWriter pw , boolean fullHistory ) {
532559 pw .print ("NetworkStatsHistory: bucketDuration=" ); pw .println (bucketDuration );
560+ pw .increaseIndent ();
533561
534562 final int start = fullHistory ? 0 : Math .max (0 , bucketCount - 32 );
535563 if (start > 0 ) {
536- pw .print (prefix );
537- pw .print (" (omitting " ); pw .print (start ); pw .println (" buckets)" );
564+ pw .print ("(omitting " ); pw .print (start ); pw .println (" buckets)" );
538565 }
539566
540567 for (int i = start ; i < bucketCount ; i ++) {
541- pw .print (prefix );
542- pw .print (" bucketStart=" ); pw .print (bucketStart [i ]);
568+ pw .print ("bucketStart=" ); pw .print (bucketStart [i ]);
543569 if (activeTime != null ) { pw .print (" activeTime=" ); pw .print (activeTime [i ]); }
544570 if (rxBytes != null ) { pw .print (" rxBytes=" ); pw .print (rxBytes [i ]); }
545571 if (rxPackets != null ) { pw .print (" rxPackets=" ); pw .print (rxPackets [i ]); }
@@ -548,12 +574,14 @@ public void dump(String prefix, PrintWriter pw, boolean fullHistory) {
548574 if (operations != null ) { pw .print (" operations=" ); pw .print (operations [i ]); }
549575 pw .println ();
550576 }
577+
578+ pw .decreaseIndent ();
551579 }
552580
553581 @ Override
554582 public String toString () {
555583 final CharArrayWriter writer = new CharArrayWriter ();
556- dump ("" , new PrintWriter (writer ), false );
584+ dump (new IndentingPrintWriter (writer , " " ), false );
557585 return writer .toString ();
558586 }
559587
@@ -579,6 +607,10 @@ private static void addLong(long[] array, int i, long value) {
579607 if (array != null ) array [i ] += value ;
580608 }
581609
610+ public int estimateResizeBuckets (long newBucketDuration ) {
611+ return (int ) (size () * getBucketDuration () / newBucketDuration );
612+ }
613+
582614 /**
583615 * Utility methods for interacting with {@link DataInputStream} and
584616 * {@link DataOutputStream}, mostly dealing with writing partial arrays.
0 commit comments