Keep debug information in NetworkStats files

Create two special SETs.

SET_DBG_VPN_IN is used by individual applications to know
how much traffic of the NetworkIdentity was actually moved
from a VPN app.
SET_DBG_VPN_OUT is used by the VPN app to know how much
traffic of the NetworkIdentity was deducted.

A debug application can restore the raw stats by these
entries.
  raw_traffic = recorded_entry (TAG_NONE, SET_ALL)
              + recorded_entry (TAG_NONE, SET_DBF_VPN_OUT)
              - recorded_entry (TAG_NONE, SET_DBF_VPN_IN)

The two debug SETs are not returned by
NetworkStatsService.openSession(). These debug entries are
retrieved by NetworkStatsCollection.dump().

Bug: 19536273
Change-Id: I03ef9f7667f5f2f48cbe3f6b11447fe7ead8ad3b
This commit is contained in:
Wenchao Tong
2015-03-17 16:14:23 -07:00
parent b293e46f2c
commit efd57ecab8
2 changed files with 44 additions and 4 deletions

View File

@@ -50,12 +50,19 @@ public class NetworkStats implements Parcelable {
public static final int UID_ALL = -1; public static final int UID_ALL = -1;
/** {@link #tag} value matching any tag. */ /** {@link #tag} value matching any tag. */
public static final int TAG_ALL = -1; public static final int TAG_ALL = -1;
/** {@link #set} value when all sets combined. */ /** {@link #set} value when all sets combined, not including debug sets. */
public static final int SET_ALL = -1; public static final int SET_ALL = -1;
/** {@link #set} value where background data is accounted. */ /** {@link #set} value where background data is accounted. */
public static final int SET_DEFAULT = 0; public static final int SET_DEFAULT = 0;
/** {@link #set} value where foreground data is accounted. */ /** {@link #set} value where foreground data is accounted. */
public static final int SET_FOREGROUND = 1; public static final int SET_FOREGROUND = 1;
/** All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values. */
public static final int SET_DEBUG_START = 1000;
/** Debug {@link #set} value when the VPN stats are moved in. */
public static final int SET_DBG_VPN_IN = 1001;
/** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */
public static final int SET_DBG_VPN_OUT = 1002;
/** {@link #tag} value for total data across all tags. */ /** {@link #tag} value for total data across all tags. */
public static final int TAG_NONE = 0; public static final int TAG_NONE = 0;
@@ -729,6 +736,10 @@ public class NetworkStats implements Parcelable {
return "DEFAULT"; return "DEFAULT";
case SET_FOREGROUND: case SET_FOREGROUND:
return "FOREGROUND"; return "FOREGROUND";
case SET_DBG_VPN_IN:
return "DBG_VPN_IN";
case SET_DBG_VPN_OUT:
return "DBG_VPN_OUT";
default: default:
return "UNKNOWN"; return "UNKNOWN";
} }
@@ -745,11 +756,26 @@ public class NetworkStats implements Parcelable {
return "def"; return "def";
case SET_FOREGROUND: case SET_FOREGROUND:
return "fg"; return "fg";
case SET_DBG_VPN_IN:
return "vpnin";
case SET_DBG_VPN_OUT:
return "vpnout";
default: default:
return "unk"; return "unk";
} }
} }
/**
* @return true if the querySet matches the dataSet.
*/
public static boolean setMatches(int querySet, int dataSet) {
if (querySet == dataSet) {
return true;
}
// SET_ALL matches all non-debugging sets.
return querySet == SET_ALL && dataSet < SET_DEBUG_START;
}
/** /**
* Return text description of {@link #tag} value. * Return text description of {@link #tag} value.
*/ */
@@ -843,6 +869,9 @@ public class NetworkStats implements Parcelable {
if (recycle.uid == UID_ALL) { if (recycle.uid == UID_ALL) {
throw new IllegalStateException( throw new IllegalStateException(
"Cannot adjust VPN accounting on an iface aggregated NetworkStats."); "Cannot adjust VPN accounting on an iface aggregated NetworkStats.");
} if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) {
throw new IllegalStateException(
"Cannot adjust VPN accounting on a NetworkStats containing SET_DBG_VPN_*");
} }
if (recycle.uid == tunUid && recycle.tag == TAG_NONE if (recycle.uid == tunUid && recycle.tag == TAG_NONE
@@ -906,6 +935,9 @@ public class NetworkStats implements Parcelable {
combineValues(tmpEntry); combineValues(tmpEntry);
if (tag[i] == TAG_NONE) { if (tag[i] == TAG_NONE) {
moved.add(tmpEntry); moved.add(tmpEntry);
// Add debug info
tmpEntry.set = SET_DBG_VPN_IN;
combineValues(tmpEntry);
} }
} }
} }
@@ -913,6 +945,13 @@ public class NetworkStats implements Parcelable {
} }
private void deductTrafficFromVpnApp(int tunUid, String underlyingIface, Entry moved) { private void deductTrafficFromVpnApp(int tunUid, String underlyingIface, Entry moved) {
// Add debug info
moved.uid = tunUid;
moved.set = SET_DBG_VPN_OUT;
moved.tag = TAG_NONE;
moved.iface = underlyingIface;
combineValues(moved);
// Caveat: if the vpn software uses tag, the total tagged traffic may be greater than // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than
// the TAG_NONE traffic. // the TAG_NONE traffic.
int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE); int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE);

View File

@@ -182,8 +182,7 @@ public class NetworkStatsCollection implements FileRotator.Reader {
for (int i = 0; i < mStats.size(); i++) { for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i); final Key key = mStats.keyAt(i);
final boolean setMatches = set == SET_ALL || key.set == set; if (key.uid == uid && NetworkStats.setMatches(set, key.set) && key.tag == tag
if (key.uid == uid && setMatches && key.tag == tag
&& templateMatches(template, key.ident)) { && templateMatches(template, key.ident)) {
final NetworkStatsHistory value = mStats.valueAt(i); final NetworkStatsHistory value = mStats.valueAt(i);
combined.recordHistory(value, start, end); combined.recordHistory(value, start, end);
@@ -209,7 +208,8 @@ public class NetworkStatsCollection implements FileRotator.Reader {
final int callerUid = Binder.getCallingUid(); final int callerUid = Binder.getCallingUid();
for (int i = 0; i < mStats.size(); i++) { for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i); final Key key = mStats.keyAt(i);
if (templateMatches(template, key.ident) && isAccessibleToUser(key.uid, callerUid)) { if (templateMatches(template, key.ident) && isAccessibleToUser(key.uid, callerUid)
&& key.set < NetworkStats.SET_DEBUG_START) {
final NetworkStatsHistory value = mStats.valueAt(i); final NetworkStatsHistory value = mStats.valueAt(i);
historyEntry = value.getValues(start, end, now, historyEntry); historyEntry = value.getValues(start, end, now, historyEntry);
@@ -542,6 +542,7 @@ public class NetworkStatsCollection implements FileRotator.Reader {
final NetworkStatsHistory value = mStats.valueAt(i); final NetworkStatsHistory value = mStats.valueAt(i);
if (!templateMatches(groupTemplate, key.ident)) continue; if (!templateMatches(groupTemplate, key.ident)) continue;
if (key.set >= NetworkStats.SET_DEBUG_START) continue;
final Key groupKey = new Key(null, key.uid, key.set, key.tag); final Key groupKey = new Key(null, key.uid, key.set, key.tag);
NetworkStatsHistory groupHistory = grouped.get(groupKey); NetworkStatsHistory groupHistory = grouped.get(groupKey);