NetworkStatsFactory: Take VPNs into account for network/battery stats
This change fixes detailed UID stats to ensure network and battery stats both take VPNs into account. NetworkStatsFactory is being made aware of VPNs enabled, and the full set of underlying networks present. Since traffic can only be migrated over a NetworkStats delta, NSF maintains a NetworkStats snapshot across all UIDs/ifaces/tags. This snapshot gets updated whenever NSF records a new snapshot (based on various hooks such as VPN updating its underlying networks, network getting lost, etc.), or NetworkStatsService's getDetailedUidStats() method being called. This change widens the scope of the existing mPersistentSnapshot lock, renaming it to mPersistentDataLock, and ensures that TUN migrations are not done in parallel. Additionally, mVpnInfos is updated via pointer-swapping, to reduce the scope of the mPersistentDataLock. The safety of this change is predicated on: 1. NetworkStatsFactory lock not held, so services cannot deadlock through the cyclical lock. 2. The broadening of the scope of the lock in NetworkStatsFactory has no threading implications, as it is always the last (leaf node) lock held, and therefore is impossible to have lock inversion. Additionally, to ensure VPNs work with 464xlat, the VPN info passed to the NetworkStatsFactory includes all underlying interfaces, instead of only passing the first one. This (partially) re-applies changes from: aosp/972848: Add one more test for VPN usage stats. aosp/972847: Addressing comments for http://ag/7700679. aosp/885338: NetworkStatsService: Fix getDetailedUidStats to take VPNs into account. Co-developed with: Varun Anand <vaanand@google.com> Bug: 113122541 Bug: 120145746 Bug: 129264869 Bug: 134244752 Test: FrameworksNetTest passing Test: Manual tests show data usage fixes maintained. Merged-In: I6466ec1411fc5ed6954125d27d353b6cd1be719e Change-Id: Id45ae956ad7165be346ecc010e17d260563ac1c0 (cherry picked from commit 9fbbdebc61513982a6775460e1d400956f803bde)
This commit is contained in:
@@ -66,7 +66,6 @@ interface INetworkStatsService {
|
||||
/** Force update of ifaces. */
|
||||
void forceUpdateIfaces(
|
||||
in Network[] defaultNetworks,
|
||||
in VpnInfo[] vpnArray,
|
||||
in NetworkState[] networkStates,
|
||||
in String activeIface);
|
||||
/** Force update of statistics. */
|
||||
|
||||
@@ -23,7 +23,6 @@ import android.annotation.UnsupportedAppUsage;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseBooleanArray;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
@@ -37,6 +36,7 @@ import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Collection of active network statistics. Can contain summary details across
|
||||
@@ -994,23 +994,33 @@ public class NetworkStats implements Parcelable {
|
||||
if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) {
|
||||
return;
|
||||
}
|
||||
filter(e -> (limitUid == UID_ALL || limitUid == e.uid)
|
||||
&& (limitTag == TAG_ALL || limitTag == e.tag)
|
||||
&& (limitIfaces == INTERFACES_ALL
|
||||
|| ArrayUtils.contains(limitIfaces, e.iface)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Only keep entries with {@link #set} value less than {@link #SET_DEBUG_START}.
|
||||
*
|
||||
* <p>This mutates the original structure in place.
|
||||
*/
|
||||
public void filterDebugEntries() {
|
||||
filter(e -> e.set < SET_DEBUG_START);
|
||||
}
|
||||
|
||||
private void filter(Predicate<Entry> predicate) {
|
||||
Entry entry = new Entry();
|
||||
int nextOutputEntry = 0;
|
||||
for (int i = 0; i < size; i++) {
|
||||
entry = getValues(i, entry);
|
||||
final boolean matches =
|
||||
(limitUid == UID_ALL || limitUid == entry.uid)
|
||||
&& (limitTag == TAG_ALL || limitTag == entry.tag)
|
||||
&& (limitIfaces == INTERFACES_ALL
|
||||
|| ArrayUtils.contains(limitIfaces, entry.iface));
|
||||
|
||||
if (matches) {
|
||||
setValues(nextOutputEntry, entry);
|
||||
if (predicate.test(entry)) {
|
||||
if (nextOutputEntry != i) {
|
||||
setValues(nextOutputEntry, entry);
|
||||
}
|
||||
nextOutputEntry++;
|
||||
}
|
||||
}
|
||||
|
||||
size = nextOutputEntry;
|
||||
}
|
||||
|
||||
@@ -1289,7 +1299,8 @@ public class NetworkStats implements Parcelable {
|
||||
}
|
||||
|
||||
final Entry tmpEntry = new Entry();
|
||||
for (int i = 0; i < size; i++) {
|
||||
final int origSize = size;
|
||||
for (int i = 0; i < origSize; i++) {
|
||||
if (!Objects.equals(iface[i], tunIface)) {
|
||||
// Consider only entries that go onto the VPN interface.
|
||||
continue;
|
||||
@@ -1305,8 +1316,9 @@ public class NetworkStats implements Parcelable {
|
||||
tmpEntry.roaming = roaming[i];
|
||||
tmpEntry.defaultNetwork = defaultNetwork[i];
|
||||
|
||||
// In a first pass, compute each UID's total share of data across all underlyingIfaces.
|
||||
// This is computed on the basis of the share of each UID's usage over tunIface.
|
||||
// In a first pass, compute this entry's total share of data across all
|
||||
// underlyingIfaces. This is computed on the basis of the share of this entry's usage
|
||||
// over tunIface.
|
||||
// TODO: Consider refactoring first pass into a separate helper method.
|
||||
long totalRxBytes = 0;
|
||||
if (tunIfaceTotal.rxBytes > 0) {
|
||||
@@ -1383,9 +1395,11 @@ public class NetworkStats implements Parcelable {
|
||||
* perInterfaceTotal[j].operations
|
||||
/ underlyingIfacesTotal.operations;
|
||||
}
|
||||
|
||||
// tmpEntry now contains the migrated data of the i-th entry for the j-th underlying
|
||||
// interface. Add that data usage to this object.
|
||||
combineValues(tmpEntry);
|
||||
if (tag[i] == TAG_NONE) {
|
||||
// Add the migrated data to moved so it is deducted from the VPN app later.
|
||||
moved[j].add(tmpEntry);
|
||||
// Add debug info
|
||||
tmpEntry.set = SET_DBG_VPN_IN;
|
||||
@@ -1401,8 +1415,8 @@ public class NetworkStats implements Parcelable {
|
||||
@NonNull String[] underlyingIfaces,
|
||||
@NonNull Entry[] moved) {
|
||||
for (int i = 0; i < underlyingIfaces.length; i++) {
|
||||
// Add debug info
|
||||
moved[i].uid = tunUid;
|
||||
// Add debug info
|
||||
moved[i].set = SET_DBG_VPN_OUT;
|
||||
moved[i].tag = TAG_NONE;
|
||||
moved[i].iface = underlyingIfaces[i];
|
||||
|
||||
Reference in New Issue
Block a user