NetworkStats.java revision eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.net; 18 19import android.os.Parcel; 20import android.os.Parcelable; 21import android.os.SystemClock; 22 23import java.io.CharArrayWriter; 24import java.io.PrintWriter; 25 26/** 27 * Collection of network statistics. Can contain summary details across all 28 * interfaces, or details with per-UID granularity. Designed to parcel quickly 29 * across process boundaries. 30 * 31 * @hide 32 */ 33public class NetworkStats implements Parcelable { 34 /** {@link #iface} value when entry is summarized over all interfaces. */ 35 public static final String IFACE_ALL = null; 36 /** {@link #uid} value when entry is summarized over all UIDs. */ 37 public static final int UID_ALL = 0; 38 39 // NOTE: data should only be accounted for once in this structure; if data 40 // is broken out, the summarized version should not be included. 41 42 /** 43 * {@link SystemClock#elapsedRealtime()} timestamp when this data was 44 * generated. 45 */ 46 public final long elapsedRealtime; 47 public final String[] iface; 48 public final int[] uid; 49 public final long[] rx; 50 public final long[] tx; 51 52 // TODO: add fg/bg stats and tag granularity 53 54 private NetworkStats(long elapsedRealtime, String[] iface, int[] uid, long[] rx, long[] tx) { 55 this.elapsedRealtime = elapsedRealtime; 56 this.iface = iface; 57 this.uid = uid; 58 this.rx = rx; 59 this.tx = tx; 60 } 61 62 public NetworkStats(Parcel parcel) { 63 elapsedRealtime = parcel.readLong(); 64 iface = parcel.createStringArray(); 65 uid = parcel.createIntArray(); 66 rx = parcel.createLongArray(); 67 tx = parcel.createLongArray(); 68 } 69 70 public static class Builder { 71 private long mElapsedRealtime; 72 private final String[] mIface; 73 private final int[] mUid; 74 private final long[] mRx; 75 private final long[] mTx; 76 77 private int mIndex = 0; 78 79 public Builder(long elapsedRealtime, int size) { 80 mElapsedRealtime = elapsedRealtime; 81 mIface = new String[size]; 82 mUid = new int[size]; 83 mRx = new long[size]; 84 mTx = new long[size]; 85 } 86 87 public Builder addEntry(String iface, int uid, long rx, long tx) { 88 mIface[mIndex] = iface; 89 mUid[mIndex] = uid; 90 mRx[mIndex] = rx; 91 mTx[mIndex] = tx; 92 mIndex++; 93 return this; 94 } 95 96 public NetworkStats build() { 97 if (mIndex != mIface.length) { 98 throw new IllegalArgumentException("unexpected number of entries"); 99 } 100 return new NetworkStats(mElapsedRealtime, mIface, mUid, mRx, mTx); 101 } 102 } 103 104 public int length() { 105 // length is identical for all fields 106 return iface.length; 107 } 108 109 /** 110 * Find first stats index that matches the requested parameters. 111 */ 112 public int findIndex(String iface, int uid) { 113 final int length = length(); 114 for (int i = 0; i < length; i++) { 115 if (equal(iface, this.iface[i]) && uid == this.uid[i]) { 116 return i; 117 } 118 } 119 return -1; 120 } 121 122 /** 123 * Subtract the given {@link NetworkStats}, effectively leaving the delta 124 * between two snapshots in time. Assumes that statistics rows collect over 125 * time, and that none of them have disappeared. 126 */ 127 public NetworkStats subtract(NetworkStats value) { 128 // result will have our rows, but no meaningful timestamp 129 final int length = length(); 130 final NetworkStats.Builder result = new NetworkStats.Builder(-1, length); 131 132 for (int i = 0; i < length; i++) { 133 final String iface = this.iface[i]; 134 final int uid = this.uid[i]; 135 136 // find remote row that matches, and subtract 137 final int j = value.findIndex(iface, uid); 138 if (j == -1) { 139 // newly appearing row, return entire value 140 result.addEntry(iface, uid, this.rx[i], this.tx[i]); 141 } else { 142 // existing row, subtract remote value 143 final long rx = this.rx[i] - value.rx[j]; 144 final long tx = this.tx[i] - value.tx[j]; 145 result.addEntry(iface, uid, rx, tx); 146 } 147 } 148 149 return result.build(); 150 } 151 152 private static boolean equal(Object a, Object b) { 153 return a == b || (a != null && a.equals(b)); 154 } 155 156 public void dump(String prefix, PrintWriter pw) { 157 pw.print(prefix); 158 pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); 159 for (int i = 0; i < iface.length; i++) { 160 pw.print(prefix); 161 pw.print(" iface="); pw.print(iface[i]); 162 pw.print(" uid="); pw.print(uid[i]); 163 pw.print(" rx="); pw.print(rx[i]); 164 pw.print(" tx="); pw.println(tx[i]); 165 } 166 } 167 168 @Override 169 public String toString() { 170 final CharArrayWriter writer = new CharArrayWriter(); 171 dump("", new PrintWriter(writer)); 172 return writer.toString(); 173 } 174 175 /** {@inheritDoc} */ 176 public int describeContents() { 177 return 0; 178 } 179 180 /** {@inheritDoc} */ 181 public void writeToParcel(Parcel dest, int flags) { 182 dest.writeLong(elapsedRealtime); 183 dest.writeStringArray(iface); 184 dest.writeIntArray(uid); 185 dest.writeLongArray(rx); 186 dest.writeLongArray(tx); 187 } 188 189 public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() { 190 public NetworkStats createFromParcel(Parcel in) { 191 return new NetworkStats(in); 192 } 193 194 public NetworkStats[] newArray(int size) { 195 return new NetworkStats[size]; 196 } 197 }; 198} 199