Merge "Hack and ship: NetworkStats edition." into lmp-dev
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user