public static final String IFACE_ALL = null;
/** {@link #uid} value when UID details unavailable. */
public static final int UID_ALL = -1;
+ /** {@link #tag} value matching any tag. */
+ public static final int TAG_ALL = -1;
/** {@link #set} value when all sets combined. */
public static final int SET_ALL = -1;
/** {@link #set} value where background data is accounted. */
* {@link SystemClock#elapsedRealtime()} timestamp when this data was
* generated.
*/
- private final long elapsedRealtime;
+ private long elapsedRealtime;
private int size;
+ private int capacity;
private String[] iface;
private int[] uid;
private int[] set;
public NetworkStats(long elapsedRealtime, int initialSize) {
this.elapsedRealtime = elapsedRealtime;
this.size = 0;
- this.iface = new String[initialSize];
- this.uid = new int[initialSize];
- this.set = new int[initialSize];
- this.tag = new int[initialSize];
- this.rxBytes = new long[initialSize];
- this.rxPackets = new long[initialSize];
- this.txBytes = new long[initialSize];
- this.txPackets = new long[initialSize];
- this.operations = new long[initialSize];
+ if (initialSize >= 0) {
+ this.capacity = initialSize;
+ this.iface = new String[initialSize];
+ this.uid = new int[initialSize];
+ this.set = new int[initialSize];
+ this.tag = new int[initialSize];
+ this.rxBytes = new long[initialSize];
+ this.rxPackets = new long[initialSize];
+ this.txBytes = new long[initialSize];
+ this.txPackets = new long[initialSize];
+ this.operations = new long[initialSize];
+ } else {
+ // Special case for use by NetworkStatsFactory to start out *really* empty.
+ this.capacity = 0;
+ }
}
public NetworkStats(Parcel parcel) {
elapsedRealtime = parcel.readLong();
size = parcel.readInt();
+ capacity = parcel.readInt();
iface = parcel.createStringArray();
uid = parcel.createIntArray();
set = parcel.createIntArray();
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(elapsedRealtime);
dest.writeInt(size);
+ dest.writeInt(capacity);
dest.writeStringArray(iface);
dest.writeIntArray(uid);
dest.writeIntArray(set);
* object can be recycled across multiple calls.
*/
public NetworkStats addValues(Entry entry) {
- if (size >= this.iface.length) {
- final int newLength = Math.max(iface.length, 10) * 3 / 2;
+ if (size >= capacity) {
+ final int newLength = Math.max(size, 10) * 3 / 2;
iface = Arrays.copyOf(iface, newLength);
uid = Arrays.copyOf(uid, newLength);
set = Arrays.copyOf(set, newLength);
txBytes = Arrays.copyOf(txBytes, newLength);
txPackets = Arrays.copyOf(txPackets, newLength);
operations = Arrays.copyOf(operations, newLength);
+ capacity = newLength;
}
iface[size] = entry.iface;
return elapsedRealtime;
}
+ public void setElapsedRealtime(long time) {
+ elapsedRealtime = time;
+ }
+
/**
* Return age of this {@link NetworkStats} object with respect to
* {@link SystemClock#elapsedRealtime()}.
@VisibleForTesting
public int internalSize() {
- return iface.length;
+ return capacity;
}
@Deprecated
* If counters have rolled backwards, they are clamped to {@code 0} and
* reported to the given {@link NonMonotonicObserver}.
*/
- public static <C> NetworkStats subtract(
- NetworkStats left, NetworkStats right, NonMonotonicObserver<C> observer, C cookie) {
+ public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right,
+ NonMonotonicObserver<C> observer, C cookie) {
+ return subtract(left, right, observer, cookie, null);
+ }
+
+ /**
+ * Subtract the two given {@link NetworkStats} objects, returning the delta
+ * between two snapshots in time. Assumes that statistics rows collect over
+ * time, and that none of them have disappeared.
+ * <p>
+ * If counters have rolled backwards, they are clamped to {@code 0} and
+ * reported to the given {@link NonMonotonicObserver}.
+ * <p>
+ * If <var>recycle</var> is supplied, this NetworkStats object will be
+ * reused (and returned) as the result if it is large enough to contain
+ * the data.
+ */
+ public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right,
+ NonMonotonicObserver<C> observer, C cookie, NetworkStats recycle) {
long deltaRealtime = left.elapsedRealtime - right.elapsedRealtime;
if (deltaRealtime < 0) {
if (observer != null) {
// result will have our rows, and elapsed time between snapshots
final Entry entry = new Entry();
- final NetworkStats result = new NetworkStats(deltaRealtime, left.size);
+ final NetworkStats result;
+ if (recycle != null && recycle.capacity >= left.size) {
+ result = recycle;
+ result.size = 0;
+ result.elapsedRealtime = deltaRealtime;
+ } else {
+ result = new NetworkStats(deltaRealtime, left.size);
+ }
for (int i = 0; i < left.size; i++) {
entry.iface = left.iface[i];
entry.uid = left.uid[i];
package com.android.internal.net;
import static android.net.NetworkStats.SET_ALL;
+import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
import android.os.SystemClock;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ProcFileReader;
import java.io.File;
}
public NetworkStats readNetworkStatsDetail() throws IOException {
- return readNetworkStatsDetail(UID_ALL);
+ return readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null);
}
- public NetworkStats readNetworkStatsDetail(int limitUid) throws IOException {
+ public NetworkStats readNetworkStatsDetail(int limitUid, String[] limitIfaces, int limitTag,
+ NetworkStats lastStats)
+ throws IOException {
if (USE_NATIVE_PARSING) {
- final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
- if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid) != 0) {
+ final NetworkStats stats;
+ if (lastStats != null) {
+ stats = lastStats;
+ stats.setElapsedRealtime(SystemClock.elapsedRealtime());
+ } else {
+ stats = new NetworkStats(SystemClock.elapsedRealtime(), -1);
+ }
+ if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid,
+ limitIfaces, limitTag) != 0) {
throw new IOException("Failed to parse network stats");
}
if (SANITY_CHECK_NATIVE) {
- final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid);
+ final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid,
+ limitIfaces, limitTag);
assertEquals(javaStats, stats);
}
return stats;
} else {
- return javaReadNetworkStatsDetail(mStatsXtUid, limitUid);
+ return javaReadNetworkStatsDetail(mStatsXtUid, limitUid, limitIfaces, limitTag);
}
}
* expected to monotonically increase since device boot.
*/
@VisibleForTesting
- public static NetworkStats javaReadNetworkStatsDetail(File detailPath, int limitUid)
+ public static NetworkStats javaReadNetworkStatsDetail(File detailPath, int limitUid,
+ String[] limitIfaces, int limitTag)
throws IOException {
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
entry.txBytes = reader.nextLong();
entry.txPackets = reader.nextLong();
- if (limitUid == UID_ALL || limitUid == entry.uid) {
+ if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface))
+ && (limitUid == UID_ALL || limitUid == entry.uid)
+ && (limitTag == TAG_ALL || limitTag == entry.tag)) {
stats.addValues(entry);
}
*/
@VisibleForTesting
public static native int nativeReadNetworkStatsDetail(
- NetworkStats stats, String path, int limitUid);
+ NetworkStats stats, String path, int limitUid, String[] limitIfaces, int limitTag);
}
package com.android.internal.os;
+import static android.net.NetworkStats.UID_ALL;
import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
import android.bluetooth.BluetoothDevice;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.net.NetworkStatsFactory;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.JournaledFile;
import com.google.android.collect.Sets;
new HashMap<String, KernelWakelockStats>();
private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
- private NetworkStats mLastSnapshot;
+ private NetworkStats mLastMobileSnapshot;
+ private NetworkStats mLastWifiSnapshot;
+ private NetworkStats mTmpNetworkStats;
+ private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
@GuardedBy("this")
- private HashSet<String> mMobileIfaces = Sets.newHashSet();
+ private String[] mMobileIfaces = new String[0];
@GuardedBy("this")
- private HashSet<String> mWifiIfaces = Sets.newHashSet();
+ private String[] mWifiIfaces = new String[0];
// For debugging
public BatteryStatsImpl() {
}
}
+ private static String[] includeInStringArray(String[] array, String str) {
+ if (ArrayUtils.indexOf(array, str) >= 0) {
+ return array;
+ }
+ String[] newArray = new String[array.length+1];
+ System.arraycopy(array, 0, newArray, 0, array.length);
+ newArray[array.length] = str;
+ return newArray;
+ }
+
+ private static String[] excludeFromStringArray(String[] array, String str) {
+ int index = ArrayUtils.indexOf(array, str);
+ if (index >= 0) {
+ String[] newArray = new String[array.length-1];
+ if (index > 0) {
+ System.arraycopy(array, 0, newArray, 0, index);
+ }
+ if (index < array.length-1) {
+ System.arraycopy(array, index+1, newArray, index, array.length-index-1);
+ }
+ return newArray;
+ }
+ return array;
+ }
+
public void noteNetworkInterfaceTypeLocked(String iface, int networkType) {
if (ConnectivityManager.isNetworkTypeMobile(networkType)) {
- mMobileIfaces.add(iface);
+ mMobileIfaces = includeInStringArray(mMobileIfaces, iface);
+ if (DEBUG) Slog.d(TAG, "Note mobile iface " + iface + ": " + mMobileIfaces);
} else {
- mMobileIfaces.remove(iface);
+ mMobileIfaces = excludeFromStringArray(mMobileIfaces, iface);
+ if (DEBUG) Slog.d(TAG, "Note non-mobile iface " + iface + ": " + mMobileIfaces);
}
if (ConnectivityManager.isNetworkTypeWifi(networkType)) {
- mWifiIfaces.add(iface);
+ mWifiIfaces = includeInStringArray(mWifiIfaces, iface);
+ if (DEBUG) Slog.d(TAG, "Note wifi iface " + iface + ": " + mWifiIfaces);
} else {
- mWifiIfaces.remove(iface);
+ mWifiIfaces = excludeFromStringArray(mWifiIfaces, iface);
+ if (DEBUG) Slog.d(TAG, "Note non-wifi iface " + iface + ": " + mWifiIfaces);
}
}
private void updateNetworkActivityLocked() {
if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return;
- final NetworkStats snapshot;
- try {
- snapshot = mNetworkStatsFactory.readNetworkStatsDetail();
- } catch (IOException e) {
- Log.wtf(TAG, "Failed to read network stats", e);
- return;
- }
-
- if (mLastSnapshot == null) {
- mLastSnapshot = snapshot;
- return;
- }
+ if (mMobileIfaces.length > 0) {
+ final NetworkStats snapshot;
+ try {
+ snapshot = mNetworkStatsFactory.readNetworkStatsDetail(UID_ALL,
+ mMobileIfaces, NetworkStats.TAG_NONE, mLastMobileSnapshot);
+ } catch (IOException e) {
+ Log.wtf(TAG, "Failed to read mobile network stats", e);
+ return;
+ }
- final NetworkStats delta = snapshot.subtract(mLastSnapshot);
- mLastSnapshot = snapshot;
+ if (mLastMobileSnapshot == null) {
+ mLastMobileSnapshot = snapshot;
+ return;
+ }
- NetworkStats.Entry entry = null;
- final int size = delta.size();
- for (int i = 0; i < size; i++) {
- entry = delta.getValues(i, entry);
+ final NetworkStats delta = NetworkStats.subtract(snapshot, mLastMobileSnapshot,
+ null, null, mTmpNetworkStats);
+ mTmpNetworkStats = delta;
+ mLastMobileSnapshot = snapshot;
- if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
- if (entry.tag != NetworkStats.TAG_NONE) continue;
+ final int size = delta.size();
+ for (int i = 0; i < size; i++) {
+ final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
- final Uid u = getUidStatsLocked(entry.uid);
+ if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
- if (mMobileIfaces.contains(entry.iface)) {
+ final Uid u = getUidStatsLocked(entry.uid);
u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes,
entry.rxPackets);
u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes,
entry.rxPackets);
mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
entry.txPackets);
+ }
+ }
+
+ if (mWifiIfaces.length > 0) {
+ final NetworkStats snapshot;
+ try {
+ snapshot = mNetworkStatsFactory.readNetworkStatsDetail(UID_ALL,
+ mWifiIfaces, NetworkStats.TAG_NONE, mLastWifiSnapshot);
+ } catch (IOException e) {
+ Log.wtf(TAG, "Failed to read wifi network stats", e);
+ return;
+ }
+
+ if (mLastWifiSnapshot == null) {
+ mLastWifiSnapshot = snapshot;
+ return;
+ }
+
+ final NetworkStats delta = NetworkStats.subtract(snapshot, mLastWifiSnapshot,
+ null, null, mTmpNetworkStats);
+ mTmpNetworkStats = delta;
+ mLastWifiSnapshot = snapshot;
+
+ final int size = delta.size();
+ for (int i = 0; i < size; i++) {
+ final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
+
+ if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
- } else if (mWifiIfaces.contains(entry.iface)) {
+ final Uid u = getUidStatsLocked(entry.uid);
u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes, entry.rxPackets);
u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes, entry.txPackets);
static struct {
jfieldID size;
+ jfieldID capacity;
jfieldID iface;
jfieldID uid;
jfieldID set;
} gNetworkStatsClassInfo;
struct stats_line {
- int32_t idx;
char iface[32];
int32_t uid;
int32_t set;
int64_t txPackets;
};
+static jobjectArray get_string_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow)
+{
+ if (!grow) {
+ jobjectArray array = (jobjectArray)env->GetObjectField(obj, field);
+ if (array != NULL) {
+ return array;
+ }
+ }
+ return env->NewObjectArray(size, gStringClass, NULL);
+}
+
+static jintArray get_int_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow)
+{
+ if (!grow) {
+ jintArray array = (jintArray)env->GetObjectField(obj, field);
+ if (array != NULL) {
+ return array;
+ }
+ }
+ return env->NewIntArray(size);
+}
+
+static jlongArray get_long_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow)
+{
+ if (!grow) {
+ jlongArray array = (jlongArray)env->GetObjectField(obj, field);
+ if (array != NULL) {
+ return array;
+ }
+ }
+ return env->NewLongArray(size);
+}
+
static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats,
- jstring path, jint limitUid) {
+ jstring path, jint limitUid, jobjectArray limitIfacesObj, jint limitTag) {
ScopedUtfChars path8(env, path);
if (path8.c_str() == NULL) {
return -1;
return -1;
}
+ Vector<String8> limitIfaces;
+ if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) {
+ int num = env->GetArrayLength(limitIfacesObj);
+ limitIfaces.setCapacity(num);
+ for (int i=0; i<num; i++) {
+ jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i);
+ ScopedUtfChars string8(env, string);
+ if (string8.c_str() != NULL) {
+ limitIfaces.add(String8(string8.c_str()));
+ }
+ }
+ }
+
Vector<stats_line> lines;
int lastIdx = 1;
+ int idx;
char buffer[384];
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
stats_line s;
int64_t rawTag;
- if (sscanf(buffer, "%d %31s 0x%llx %u %u %llu %llu %llu %llu", &s.idx,
- s.iface, &rawTag, &s.uid, &s.set, &s.rxBytes, &s.rxPackets,
- &s.txBytes, &s.txPackets) == 9) {
- if (s.idx != lastIdx + 1) {
- ALOGE("inconsistent idx=%d after lastIdx=%d", s.idx, lastIdx);
- return -1;
+ char* pos = buffer;
+ char* endPos;
+ // First field is the index.
+ idx = (int)strtol(pos, &endPos, 10);
+ //ALOGI("Index #%d: %s", idx, buffer);
+ if (pos == endPos) {
+ // Skip lines that don't start with in index. In particular,
+ // this will skip the initial header line.
+ continue;
+ }
+ if (idx != lastIdx + 1) {
+ ALOGE("inconsistent idx=%d after lastIdx=%d: %s", idx, lastIdx, buffer);
+ fclose(fp);
+ return -1;
+ }
+ lastIdx = idx;
+ pos = endPos;
+ // Skip whitespace.
+ while (*pos == ' ') {
+ pos++;
+ }
+ // Next field is iface.
+ int ifaceIdx = 0;
+ while (*pos != ' ' && *pos != 0 && ifaceIdx < (int)(sizeof(s.iface)-1)) {
+ s.iface[ifaceIdx] = *pos;
+ ifaceIdx++;
+ pos++;
+ }
+ if (*pos != ' ') {
+ ALOGE("bad iface: %s", buffer);
+ fclose(fp);
+ return -1;
+ }
+ s.iface[ifaceIdx] = 0;
+ if (limitIfaces.size() > 0) {
+ // Is this an iface the caller is interested in?
+ int i = 0;
+ while (i < (int)limitIfaces.size()) {
+ if (limitIfaces[i] == s.iface) {
+ break;
+ }
+ i++;
+ }
+ if (i >= (int)limitIfaces.size()) {
+ // Nothing matched; skip this line.
+ //ALOGI("skipping due to iface: %s", buffer);
+ continue;
+ }
+ }
+ // Skip whitespace.
+ while (*pos == ' ') {
+ pos++;
+ }
+ // Next field is tag.
+ rawTag = strtoll(pos, &endPos, 16);
+ //ALOGI("Index #%d: %s", idx, buffer);
+ if (pos == endPos) {
+ ALOGE("bad tag: %s", pos);
+ fclose(fp);
+ return -1;
+ }
+ s.tag = rawTag >> 32;
+ if (limitTag != -1 && s.tag != limitTag) {
+ //ALOGI("skipping due to tag: %s", buffer);
+ continue;
+ }
+ pos = endPos;
+ // Skip whitespace.
+ while (*pos == ' ') {
+ pos++;
+ }
+ // Parse remaining fields.
+ if (sscanf(pos, "%u %u %llu %llu %llu %llu",
+ &s.uid, &s.set, &s.rxBytes, &s.rxPackets,
+ &s.txBytes, &s.txPackets) == 6) {
+ if (limitUid != -1 && limitUid != s.uid) {
+ //ALOGI("skipping due to uid: %s", buffer);
+ continue;
}
- lastIdx = s.idx;
-
- s.tag = rawTag >> 32;
lines.push_back(s);
+ } else {
+ //ALOGI("skipping due to bad remaining fields: %s", pos);
}
}
if (fclose(fp) != 0) {
+ ALOGE("Failed to close netstats file");
return -1;
}
int size = lines.size();
+ bool grow = size > env->GetIntField(stats, gNetworkStatsClassInfo.capacity);
- ScopedLocalRef<jobjectArray> iface(env, env->NewObjectArray(size, gStringClass, NULL));
+ ScopedLocalRef<jobjectArray> iface(env, get_string_array(env, stats,
+ gNetworkStatsClassInfo.iface, size, grow));
if (iface.get() == NULL) return -1;
- ScopedIntArrayRW uid(env, env->NewIntArray(size));
+ ScopedIntArrayRW uid(env, get_int_array(env, stats,
+ gNetworkStatsClassInfo.uid, size, grow));
if (uid.get() == NULL) return -1;
- ScopedIntArrayRW set(env, env->NewIntArray(size));
+ ScopedIntArrayRW set(env, get_int_array(env, stats,
+ gNetworkStatsClassInfo.set, size, grow));
if (set.get() == NULL) return -1;
- ScopedIntArrayRW tag(env, env->NewIntArray(size));
+ ScopedIntArrayRW tag(env, get_int_array(env, stats,
+ gNetworkStatsClassInfo.tag, size, grow));
if (tag.get() == NULL) return -1;
- ScopedLongArrayRW rxBytes(env, env->NewLongArray(size));
+ ScopedLongArrayRW rxBytes(env, get_long_array(env, stats,
+ gNetworkStatsClassInfo.rxBytes, size, grow));
if (rxBytes.get() == NULL) return -1;
- ScopedLongArrayRW rxPackets(env, env->NewLongArray(size));
+ ScopedLongArrayRW rxPackets(env, get_long_array(env, stats,
+ gNetworkStatsClassInfo.rxPackets, size, grow));
if (rxPackets.get() == NULL) return -1;
- ScopedLongArrayRW txBytes(env, env->NewLongArray(size));
+ ScopedLongArrayRW txBytes(env, get_long_array(env, stats,
+ gNetworkStatsClassInfo.txBytes, size, grow));
if (txBytes.get() == NULL) return -1;
- ScopedLongArrayRW txPackets(env, env->NewLongArray(size));
+ ScopedLongArrayRW txPackets(env, get_long_array(env, stats,
+ gNetworkStatsClassInfo.txPackets, size, grow));
if (txPackets.get() == NULL) return -1;
- ScopedLongArrayRW operations(env, env->NewLongArray(size));
+ ScopedLongArrayRW operations(env, get_long_array(env, stats,
+ gNetworkStatsClassInfo.operations, size, grow));
if (operations.get() == NULL) return -1;
for (int i = 0; i < size; i++) {
}
env->SetIntField(stats, gNetworkStatsClassInfo.size, size);
- env->SetObjectField(stats, gNetworkStatsClassInfo.iface, iface.get());
- env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray());
- env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray());
- env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray());
- env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray());
- env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray());
- env->SetObjectField(stats, gNetworkStatsClassInfo.txBytes, txBytes.getJavaArray());
- env->SetObjectField(stats, gNetworkStatsClassInfo.txPackets, txPackets.getJavaArray());
- env->SetObjectField(stats, gNetworkStatsClassInfo.operations, operations.getJavaArray());
+ if (grow) {
+ env->SetIntField(stats, gNetworkStatsClassInfo.capacity, size);
+ env->SetObjectField(stats, gNetworkStatsClassInfo.iface, iface.get());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.txBytes, txBytes.getJavaArray());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.txPackets, txPackets.getJavaArray());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.operations, operations.getJavaArray());
+ }
return 0;
}
static JNINativeMethod gMethods[] = {
{ "nativeReadNetworkStatsDetail",
- "(Landroid/net/NetworkStats;Ljava/lang/String;I)I",
+ "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;I)I",
(void*) readNetworkStatsDetail }
};
jclass clazz = env->FindClass("android/net/NetworkStats");
gNetworkStatsClassInfo.size = env->GetFieldID(clazz, "size", "I");
+ gNetworkStatsClassInfo.capacity = env->GetFieldID(clazz, "capacity", "I");
gNetworkStatsClassInfo.iface = env->GetFieldID(clazz, "iface", "[Ljava/lang/String;");
gNetworkStatsClassInfo.uid = env->GetFieldID(clazz, "uid", "[I");
gNetworkStatsClassInfo.set = env->GetFieldID(clazz, "set", "[I");
import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.SHUTDOWN;
import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_TETHERING;
public NetworkStats getNetworkStatsDetail() {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- return mStatsFactory.readNetworkStatsDetail(UID_ALL);
+ return mStatsFactory.readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null);
} catch (IOException e) {
throw new IllegalStateException(e);
}
public NetworkStats getNetworkStatsUidDetail(int uid) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- return mStatsFactory.readNetworkStatsDetail(uid);
+ return mStatsFactory.readNetworkStatsDetail(uid, null, TAG_ALL, null);
} catch (IOException e) {
throw new IllegalStateException(e);
}