@@ -229,6 +229,14 @@ public long getElapsedRealtime() {
229229 return elapsedRealtime ;
230230 }
231231
232+ /**
233+ * Return age of this {@link NetworkStats} object with respect to
234+ * {@link SystemClock#elapsedRealtime()}.
235+ */
236+ public long getElapsedRealtimeAge () {
237+ return SystemClock .elapsedRealtime () - elapsedRealtime ;
238+ }
239+
232240 public int size () {
233241 return size ;
234242 }
@@ -354,26 +362,59 @@ public long getTotalBytes() {
354362 * Return total of all fields represented by this snapshot object.
355363 */
356364 public Entry getTotal (Entry recycle ) {
365+ return getTotal (recycle , null , UID_ALL );
366+ }
367+
368+ /**
369+ * Return total of all fields represented by this snapshot object matching
370+ * the requested {@link #uid}.
371+ */
372+ public Entry getTotal (Entry recycle , int limitUid ) {
373+ return getTotal (recycle , null , limitUid );
374+ }
375+
376+ /**
377+ * Return total of all fields represented by this snapshot object matching
378+ * the requested {@link #iface}.
379+ */
380+ public Entry getTotal (Entry recycle , HashSet <String > limitIface ) {
381+ return getTotal (recycle , limitIface , UID_ALL );
382+ }
383+
384+ /**
385+ * Return total of all fields represented by this snapshot object matching
386+ * the requested {@link #iface} and {@link #uid}.
387+ *
388+ * @param limitIface Set of {@link #iface} to include in total; or {@code
389+ * null} to include all ifaces.
390+ */
391+ private Entry getTotal (Entry recycle , HashSet <String > limitIface , int limitUid ) {
357392 final Entry entry = recycle != null ? recycle : new Entry ();
358393
359394 entry .iface = IFACE_ALL ;
360- entry .uid = UID_ALL ;
395+ entry .uid = limitUid ;
361396 entry .set = SET_ALL ;
362397 entry .tag = TAG_NONE ;
363398 entry .rxBytes = 0 ;
364399 entry .rxPackets = 0 ;
365400 entry .txBytes = 0 ;
366401 entry .txPackets = 0 ;
402+ entry .operations = 0 ;
367403
368404 for (int i = 0 ; i < size ; i ++) {
369- // skip specific tags, since already counted in TAG_NONE
370- if (tag [i ] != TAG_NONE ) continue ;
371-
372- entry .rxBytes += rxBytes [i ];
373- entry .rxPackets += rxPackets [i ];
374- entry .txBytes += txBytes [i ];
375- entry .txPackets += txPackets [i ];
376- entry .operations += operations [i ];
405+ final boolean matchesUid = (limitUid == UID_ALL ) || (limitUid == uid [i ]);
406+ final boolean matchesIface = (limitIface == null ) || (limitIface .contains (iface [i ]));
407+
408+ if (matchesUid && matchesIface ) {
409+ // skip specific tags, since already counted in TAG_NONE
410+ if (tag [i ] != TAG_NONE ) continue ;
411+
412+ entry .rxBytes += rxBytes [i ];
413+ entry .rxPackets += rxPackets [i ];
414+ entry .txBytes += txBytes [i ];
415+ entry .txPackets += txPackets [i ];
416+ entry .operations += operations [i ];
417+ }
377418 }
378419 return entry ;
379420 }
@@ -495,6 +536,34 @@ public NetworkStats groupedByIface() {
495536 return stats ;
496537 }
497538
539+ /**
540+ * Return total statistics grouped by {@link #uid}; doesn't mutate the
541+ * original structure.
542+ */
543+ public NetworkStats groupedByUid () {
544+ final NetworkStats stats = new NetworkStats (elapsedRealtime , 10 );
545+
546+ final Entry entry = new Entry ();
547+ entry .iface = IFACE_ALL ;
548+ entry .set = SET_ALL ;
549+ entry .tag = TAG_NONE ;
550+
551+ for (int i = 0 ; i < size ; i ++) {
552+ // skip specific tags, since already counted in TAG_NONE
553+ if (tag [i ] != TAG_NONE ) continue ;
554+
555+ entry .uid = uid [i ];
556+ entry .rxBytes = rxBytes [i ];
557+ entry .rxPackets = rxPackets [i ];
558+ entry .txBytes = txBytes [i ];
559+ entry .txPackets = txPackets [i ];
560+ entry .operations = operations [i ];
561+ stats .combineValues (entry );
562+ }
563+
564+ return stats ;
565+ }
566+
498567 public void dump (String prefix , PrintWriter pw ) {
499568 pw .print (prefix );
500569 pw .print ("NetworkStats: elapsedRealtime=" ); pw .println (elapsedRealtime );
0 commit comments