Merge "Improve how battery stats collects network stats."

This commit is contained in:
Dianne Hackborn
2014-02-24 20:33:42 +00:00
committed by Android (Google) Code Review
5 changed files with 338 additions and 87 deletions

View File

@@ -44,6 +44,8 @@ public class NetworkStats implements Parcelable {
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. */
@@ -59,8 +61,9 @@ public class NetworkStats implements Parcelable {
* {@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;
@@ -152,20 +155,27 @@ public class NetworkStats implements Parcelable {
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();
@@ -181,6 +191,7 @@ public class NetworkStats implements Parcelable {
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);
@@ -222,8 +233,8 @@ public class NetworkStats implements Parcelable {
* 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);
@@ -233,6 +244,7 @@ public class NetworkStats implements Parcelable {
txBytes = Arrays.copyOf(txBytes, newLength);
txPackets = Arrays.copyOf(txPackets, newLength);
operations = Arrays.copyOf(operations, newLength);
capacity = newLength;
}
iface[size] = entry.iface;
@@ -270,6 +282,10 @@ public class NetworkStats implements Parcelable {
return elapsedRealtime;
}
public void setElapsedRealtime(long time) {
elapsedRealtime = time;
}
/**
* Return age of this {@link NetworkStats} object with respect to
* {@link SystemClock#elapsedRealtime()}.
@@ -284,7 +300,7 @@ public class NetworkStats implements Parcelable {
@VisibleForTesting
public int internalSize() {
return iface.length;
return capacity;
}
@Deprecated
@@ -507,8 +523,25 @@ public class NetworkStats implements Parcelable {
* 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) {
@@ -519,7 +552,14 @@ public class NetworkStats implements Parcelable {
// 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];

View File

@@ -17,6 +17,7 @@
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;
@@ -26,6 +27,7 @@ import android.os.StrictMode;
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;
@@ -165,22 +167,32 @@ public class NetworkStatsFactory {
}
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);
}
}
@@ -189,7 +201,8 @@ public class NetworkStatsFactory {
* 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();
@@ -222,7 +235,9 @@ public class NetworkStatsFactory {
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);
}
@@ -264,5 +279,5 @@ public class NetworkStatsFactory {
*/
@VisibleForTesting
public static native int nativeReadNetworkStatsDetail(
NetworkStats stats, String path, int limitUid);
NetworkStats stats, String path, int limitUid, String[] limitIfaces, int limitTag);
}

View File

@@ -16,6 +16,7 @@
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;
@@ -52,6 +53,7 @@ import android.util.TimeUtils;
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;
@@ -370,12 +372,15 @@ public final class BatteryStatsImpl extends BatteryStats {
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() {
@@ -2954,16 +2959,45 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
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);
}
}
@@ -5572,33 +5606,33 @@ public final class BatteryStatsImpl extends BatteryStats {
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 (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;
}
if (mLastSnapshot == null) {
mLastSnapshot = snapshot;
return;
}
if (mLastMobileSnapshot == null) {
mLastMobileSnapshot = snapshot;
return;
}
final NetworkStats delta = snapshot.subtract(mLastSnapshot);
mLastSnapshot = snapshot;
final NetworkStats delta = NetworkStats.subtract(snapshot, mLastMobileSnapshot,
null, null, mTmpNetworkStats);
mTmpNetworkStats = delta;
mLastMobileSnapshot = snapshot;
NetworkStats.Entry entry = null;
final int size = delta.size();
for (int i = 0; i < size; i++) {
entry = delta.getValues(i, entry);
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;
if (entry.tag != NetworkStats.TAG_NONE) continue;
if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
final Uid u = getUidStatsLocked(entry.uid);
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,
@@ -5610,8 +5644,36 @@ public final class BatteryStatsImpl extends BatteryStats {
entry.rxPackets);
mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
entry.txPackets);
}
}
} else if (mWifiIfaces.contains(entry.iface)) {
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;
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);

View File

@@ -37,6 +37,7 @@ static jclass gStringClass;
static struct {
jfieldID size;
jfieldID capacity;
jfieldID iface;
jfieldID uid;
jfieldID set;
@@ -49,7 +50,6 @@ static struct {
} gNetworkStatsClassInfo;
struct stats_line {
int32_t idx;
char iface[32];
int32_t uid;
int32_t set;
@@ -60,8 +60,41 @@ struct stats_line {
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;
@@ -72,50 +105,146 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats,
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++) {
@@ -132,15 +261,18 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats,
}
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;
}
@@ -157,7 +289,7 @@ static jclass findClass(JNIEnv* env, const char* name) {
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 }
};
@@ -170,6 +302,7 @@ int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) {
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");

View File

@@ -20,6 +20,7 @@ import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
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;
@@ -1271,7 +1272,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
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);
}
@@ -1432,7 +1433,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
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);
}