Merge "Hack and ship: NetworkStats edition." into lmp-dev

This commit is contained in:
Jeff Sharkey
2014-08-12 02:31:00 +00:00
committed by Android (Google) Code Review
5 changed files with 178 additions and 57 deletions

View File

@@ -16,6 +16,7 @@
package android.net;
import android.annotation.NonNull;
import android.net.ProxyInfo;
import android.os.Parcelable;
import android.os.Parcel;
@@ -24,7 +25,6 @@ import android.text.TextUtils;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
@@ -480,10 +480,13 @@ public final class LinkProperties implements Parcelable {
* Returns all the links stacked on top of this link.
* @hide
*/
public List<LinkProperties> getStackedLinks() {
public @NonNull List<LinkProperties> getStackedLinks() {
if (mStackedLinks.isEmpty()) {
return Collections.EMPTY_LIST;
}
List<LinkProperties> stacked = new ArrayList<LinkProperties>();
for (LinkProperties link : mStackedLinks.values()) {
stacked.add(new LinkProperties(link));
stacked.add(new LinkProperties(link));
}
return Collections.unmodifiableList(stacked);
}

View File

@@ -25,17 +25,20 @@ import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
import android.net.NetworkStats;
import android.os.StrictMode;
import android.os.SystemClock;
import android.util.ArrayMap;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ProcFileReader;
import libcore.io.IoUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.ProtocolException;
import libcore.io.IoUtils;
import java.util.Objects;
/**
* Creates {@link NetworkStats} instances by parsing various {@code /proc/}
@@ -54,6 +57,19 @@ public class NetworkStatsFactory {
/** Path to {@code /proc/net/xt_qtaguid/stats}. */
private final File mStatsXtUid;
@GuardedBy("sStackedIfaces")
private static final ArrayMap<String, String> sStackedIfaces = new ArrayMap<>();
public static void noteStackedIface(String stackedIface, String baseIface) {
synchronized (sStackedIfaces) {
if (baseIface != null) {
sStackedIfaces.put(stackedIface, baseIface);
} else {
sStackedIfaces.remove(stackedIface);
}
}
}
public NetworkStatsFactory() {
this(new File("/proc/"));
}
@@ -171,8 +187,54 @@ public class NetworkStatsFactory {
}
public NetworkStats readNetworkStatsDetail(int limitUid, String[] limitIfaces, int limitTag,
NetworkStats lastStats)
throws IOException {
NetworkStats lastStats) throws IOException {
final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag,
lastStats);
synchronized (sStackedIfaces) {
// Sigh, xt_qtaguid ends up double-counting tx traffic going through
// clatd interfaces, so we need to subtract it here.
final int size = sStackedIfaces.size();
for (int i = 0; i < size; i++) {
final String stackedIface = sStackedIfaces.keyAt(i);
final String baseIface = sStackedIfaces.valueAt(i);
// Count up the tx traffic and subtract from root UID on the
// base interface.
NetworkStats.Entry adjust = new NetworkStats.Entry(baseIface, 0, 0, 0, 0L, 0L, 0L,
0L, 0L);
NetworkStats.Entry entry = null;
for (int j = 0; j < stats.size(); j++) {
entry = stats.getValues(j, entry);
if (Objects.equals(entry.iface, stackedIface)) {
adjust.txBytes -= entry.txBytes;
adjust.txPackets -= entry.txPackets;
}
}
stats.combineValues(adjust);
}
}
// Double sigh, all rx traffic on clat needs to be tweaked to
// account for the dropped IPv6 header size post-unwrap.
NetworkStats.Entry entry = null;
for (int i = 0; i < stats.size(); i++) {
entry = stats.getValues(i, entry);
if (entry.iface != null && entry.iface.startsWith("clat")) {
// Delta between IPv4 header (20b) and IPv6 header (40b)
entry.rxBytes = entry.rxPackets * 20;
entry.rxPackets = 0;
entry.txBytes = 0;
entry.txPackets = 0;
stats.combineValues(entry);
}
}
return stats;
}
private NetworkStats readNetworkStatsDetailInternal(int limitUid, String[] limitIfaces,
int limitTag, NetworkStats lastStats) throws IOException {
if (USE_NATIVE_PARSING) {
final NetworkStats stats;
if (lastStats != null) {

View File

@@ -119,7 +119,9 @@ import android.util.Xml;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
import com.android.internal.telephony.DctConstants;
@@ -4476,12 +4478,23 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// TODO - read the tcp buffer size config string from somewhere
// updateNetworkSettings();
}
// notify battery stats service about this network
// Notify battery stats service about this network, both the normal
// interface and any stacked links.
try {
BatteryStatsService.getService().noteNetworkInterfaceType(
newNetwork.linkProperties.getInterfaceName(),
newNetwork.networkInfo.getType());
} catch (RemoteException e) { }
final IBatteryStats bs = BatteryStatsService.getService();
final int type = newNetwork.networkInfo.getType();
final String baseIface = newNetwork.linkProperties.getInterfaceName();
bs.noteNetworkInterfaceType(baseIface, type);
for (LinkProperties stacked : newNetwork.linkProperties.getStackedLinks()) {
final String stackedIface = stacked.getInterfaceName();
bs.noteNetworkInterfaceType(stackedIface, type);
NetworkStatsFactory.noteStackedIface(stackedIface, baseIface);
}
} catch (RemoteException ignored) {
}
notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_AVAILABLE);
} else {
if (DBG && newNetwork.networkRequests.size() != 0) {

View File

@@ -38,8 +38,8 @@ import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
@@ -96,6 +96,7 @@ import android.net.INetworkManagementEventObserver;
import android.net.INetworkPolicyListener;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.LinkProperties;
import android.net.NetworkIdentity;
import android.net.NetworkInfo;
import android.net.NetworkPolicy;
@@ -127,6 +128,7 @@ import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Log;
import android.util.NtpTrustedTime;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -142,6 +144,8 @@ import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.google.android.collect.Lists;
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -158,8 +162,6 @@ import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import libcore.io.IoUtils;
/**
* Service that maintains low-level network policy rules, using
* {@link NetworkStatsService} statistics to drive those rules.
@@ -1049,36 +1051,44 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// use over those networks can have a cost associated with it).
final boolean powerSave = mRestrictPower && !mRestrictBackground;
// first, derive identity for all connected networks, which can be used
// to match against templates.
final ArrayMap<NetworkIdentity, String> networks = new ArrayMap<NetworkIdentity,
String>(states.length);
// First, generate identities of all connected networks so we can
// quickly compare them against all defined policies below.
final ArrayList<Pair<String, NetworkIdentity>> connIdents = new ArrayList<>(states.length);
final ArraySet<String> connIfaces = new ArraySet<String>(states.length);
for (NetworkState state : states) {
// stash identity and iface away for later use
if (state.networkInfo.isConnected()) {
final String iface = state.linkProperties.getInterfaceName();
final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
networks.put(ident, iface);
final String baseIface = state.linkProperties.getInterfaceName();
connIdents.add(Pair.create(baseIface, ident));
if (powerSave) {
connIfaces.add(iface);
connIfaces.add(baseIface);
}
// Stacked interfaces are considered to have same identity as
// their parent network.
final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks();
for (LinkProperties stackedLink : stackedLinks) {
final String stackedIface = stackedLink.getInterfaceName();
connIdents.add(Pair.create(stackedIface, ident));
if (powerSave) {
connIfaces.add(stackedIface);
}
}
}
}
// build list of rules and ifaces to enforce them against
// Apply policies against all connected interfaces found above
mNetworkRules.clear();
final ArrayList<String> ifaceList = Lists.newArrayList();
for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) {
final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
// collect all active ifaces that match this template
ifaceList.clear();
for (int j = networks.size()-1; j >= 0; j--) {
final NetworkIdentity ident = networks.keyAt(j);
if (policy.template.matches(ident)) {
final String iface = networks.valueAt(j);
ifaceList.add(iface);
for (int j = connIdents.size() - 1; j >= 0; j--) {
final Pair<String, NetworkIdentity> ident = connIdents.get(j);
if (policy.template.matches(ident.second)) {
ifaceList.add(ident.first);
}
}
@@ -1787,6 +1797,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
fout.decreaseIndent();
fout.print("Metered ifaces: "); fout.println(String.valueOf(mMeteredIfaces));
fout.println("Policy for UIDs:");
fout.increaseIndent();
int size = mUidPolicy.size();

View File

@@ -62,8 +62,6 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import static com.android.internal.util.ArrayUtils.appendElement;
import static com.android.internal.util.ArrayUtils.contains;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
@@ -107,6 +105,8 @@ import android.provider.Settings;
import android.provider.Settings.Global;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
import android.util.Log;
import android.util.MathUtils;
@@ -121,14 +121,12 @@ import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.EventLogTags;
import com.android.server.connectivity.Tethering;
import com.google.android.collect.Maps;
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -215,7 +213,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private final Object mStatsLock = new Object();
/** Set of currently active ifaces. */
private HashMap<String, NetworkIdentitySet> mActiveIfaces = Maps.newHashMap();
private final ArrayMap<String, NetworkIdentitySet> mActiveIfaces = new ArrayMap<>();
/** Set of currently active ifaces for UID stats. */
private final ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces = new ArrayMap<>();
/** Current default active iface. */
private String mActiveIface;
/** Set of any ifaces associated with mobile networks since boot. */
@@ -883,30 +883,52 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mActiveIface = activeLink != null ? activeLink.getInterfaceName() : null;
// rebuild active interfaces based on connected networks
// Rebuild active interfaces based on connected networks
mActiveIfaces.clear();
mActiveUidIfaces.clear();
final ArraySet<String> mobileIfaces = new ArraySet<>();
for (NetworkState state : states) {
if (state.networkInfo.isConnected()) {
// collect networks under their parent interfaces
final String iface = state.linkProperties.getInterfaceName();
final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType());
final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
NetworkIdentitySet ident = mActiveIfaces.get(iface);
if (ident == null) {
ident = new NetworkIdentitySet();
mActiveIfaces.put(iface, ident);
// Traffic occurring on the base interface is always counted for
// both total usage and UID details.
final String baseIface = state.linkProperties.getInterfaceName();
findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident);
findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident);
if (isMobile) {
mobileIfaces.add(baseIface);
}
ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state));
// remember any ifaces associated with mobile networks
if (isNetworkTypeMobile(state.networkInfo.getType()) && iface != null) {
if (!contains(mMobileIfaces, iface)) {
mMobileIfaces = appendElement(String.class, mMobileIfaces, iface);
// Traffic occurring on stacked interfaces is usually clatd,
// which is already accounted against its final egress interface
// by the kernel. Thus, we only need to collect stacked
// interface stats at the UID level.
final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks();
for (LinkProperties stackedLink : stackedLinks) {
final String stackedIface = stackedLink.getInterfaceName();
findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident);
if (isMobile) {
mobileIfaces.add(stackedIface);
}
}
}
}
mobileIfaces.remove(null);
mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]);
}
private static <K> NetworkIdentitySet findOrCreateNetworkIdentitySet(
ArrayMap<K, NetworkIdentitySet> map, K key) {
NetworkIdentitySet ident = map.get(key);
if (ident == null) {
ident = new NetworkIdentitySet();
map.put(key, ident);
}
return ident;
}
/**
@@ -926,8 +948,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime);
mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime);
mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime);
mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime);
mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime);
mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime);
} catch (IllegalStateException e) {
Slog.w(TAG, "problem reading network stats: " + e);
@@ -980,8 +1002,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime);
mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime);
mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime);
mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime);
mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime);
mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem reading network stats", e);
@@ -1136,10 +1158,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
pw.println("Active interfaces:");
pw.increaseIndent();
for (String iface : mActiveIfaces.keySet()) {
final NetworkIdentitySet ident = mActiveIfaces.get(iface);
pw.print("iface="); pw.print(iface);
pw.print(" ident="); pw.println(ident.toString());
for (int i = 0; i < mActiveIfaces.size(); i++) {
pw.printPair("iface", mActiveIfaces.keyAt(i));
pw.printPair("ident", mActiveIfaces.valueAt(i));
pw.println();
}
pw.decreaseIndent();
pw.println("Active UID interfaces:");
pw.increaseIndent();
for (int i = 0; i < mActiveUidIfaces.size(); i++) {
pw.printPair("iface", mActiveUidIfaces.keyAt(i));
pw.printPair("ident", mActiveUidIfaces.valueAt(i));
pw.println();
}
pw.decreaseIndent();