Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dfbd4669 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I47694963,Ia4b33fd4,Id04f9080

* changes:
  Connectivity metrics: add transports to connect stats
  Connectivity metrics: log DnsEvents in-band
  Connectivity metrics: add transports pretty printing
parents 12b4dd77 dfc2cc58
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.net;

import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.BitUtils;

/**
 * Represents a core networking event defined in package android.net.metrics.
@@ -78,13 +79,15 @@ public final class ConnectivityMetricsEvent implements Parcelable {
    public String toString() {
        StringBuilder buffer = new StringBuilder("ConnectivityMetricsEvent(");
        buffer.append(String.format("%tT.%tL", timestamp, timestamp));
        // TODO: add transports
        if (netId != 0) {
            buffer.append(", ").append(netId);
        }
        if (ifname != null) {
            buffer.append(", ").append(ifname);
        }
        for (int t : BitUtils.unpackBits(transports)) {
            buffer.append(", ").append(NetworkCapabilities.transportNameOf(t));
        }
        buffer.append("): ").append(data.toString());
        return buffer.toString();
    }
+30 −39
Original line number Diff line number Diff line
@@ -18,7 +18,8 @@ package android.net;

import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;

import com.android.internal.util.BitUtils;

import java.util.Objects;

@@ -279,7 +280,7 @@ public final class NetworkCapabilities implements Parcelable {
     * @hide
     */
    public int[] getCapabilities() {
        return enumerateBits(mNetworkCapabilities);
        return BitUtils.unpackBits(mNetworkCapabilities);
    }

    /**
@@ -295,19 +296,6 @@ public final class NetworkCapabilities implements Parcelable {
        return ((mNetworkCapabilities & (1 << capability)) != 0);
    }

    private int[] enumerateBits(long val) {
        int size = Long.bitCount(val);
        int[] result = new int[size];
        int index = 0;
        int resource = 0;
        while (val > 0) {
            if ((val & 1) == 1) result[index++] = resource;
            val = val >> 1;
            resource++;
        }
        return result;
    }

    private void combineNetCapabilities(NetworkCapabilities nc) {
        this.mNetworkCapabilities |= nc.mNetworkCapabilities;
    }
@@ -418,6 +406,15 @@ public final class NetworkCapabilities implements Parcelable {
    /** @hide */
    public static final int MAX_TRANSPORT = TRANSPORT_WIFI_AWARE;

    private static final String[] TRANSPORT_NAMES = {
        "CELLULAR",
        "WIFI",
        "BLUETOOTH",
        "ETHERNET",
        "VPN",
        "WIFI_AWARE"
    };

    /**
     * Adds the given transport type to this {@code NetworkCapability} instance.
     * Multiple transports may be applied sequentially.  Note that when searching
@@ -464,18 +461,7 @@ public final class NetworkCapabilities implements Parcelable {
     * @hide
     */
    public int[] getTransportTypes() {
        return enumerateBits(mTransportTypes);
    }

    /**
     * Gets all the transports set on this {@code NetworkCapability} instance.
     *
     * @return a bit field composed of up bits at indexes defined by
     * {@code NetworkCapabilities.TRANSPORT_*} values for this instance.
     * @hide
     */
    public long getTransports() {
        return mTransportTypes;
        return BitUtils.unpackBits(mTransportTypes);
    }

    /**
@@ -882,18 +868,23 @@ public final class NetworkCapabilities implements Parcelable {
     * @hide
     */
    public static String transportNamesOf(int[] types) {
        String transports = "";
        for (int i = 0; i < types.length;) {
            switch (types[i]) {
                case TRANSPORT_CELLULAR:    transports += "CELLULAR"; break;
                case TRANSPORT_WIFI:        transports += "WIFI"; break;
                case TRANSPORT_BLUETOOTH:   transports += "BLUETOOTH"; break;
                case TRANSPORT_ETHERNET:    transports += "ETHERNET"; break;
                case TRANSPORT_VPN:         transports += "VPN"; break;
                case TRANSPORT_WIFI_AWARE:  transports += "WIFI_AWARE"; break;
        if (types == null || types.length == 0) {
            return "";
        }
        StringBuilder transports = new StringBuilder();
        for (int t : types) {
            transports.append("|").append(transportNameOf(t));
        }
            if (++i < types.length) transports += "|";
        return transports.substring(1);
    }

    /**
     * @hide
     */
    public static String transportNameOf(int transport) {
        if (transport < 0 || TRANSPORT_NAMES.length <= transport) {
            return "UNKNOWN";
        }
        return transports;
        return TRANSPORT_NAMES[transport];
    }
}
+35 −50
Original line number Diff line number Diff line
@@ -16,53 +16,47 @@

package android.net.metrics;

import android.net.NetworkCapabilities;
import android.system.OsConstants;
import android.util.IntArray;
import android.util.SparseIntArray;
import com.android.internal.util.BitUtils;
import com.android.internal.util.TokenBucket;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.ConnectStatistics;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.Pair;

/**
 * A class that aggregates connect() statistics and helps build
 * IpConnectivityLogClass.ConnectStatistics instances.
 *
 * A class that aggregates connect() statistics.
 * {@hide}
 */
public class ConnectStats {
    private final static int EALREADY     = OsConstants.EALREADY;
    private final static int EINPROGRESS  = OsConstants.EINPROGRESS;

    /** Network id of the network associated with the event, or 0 if unspecified. */
    public final int netId;
    /** Transports of the network associated with the event, as defined in NetworkCapabilities. */
    public final long transports;
    /** How many events resulted in a given errno. */
    private final SparseIntArray mErrnos = new SparseIntArray();
    /** Latencies of blocking connects. TODO: add non-blocking connects latencies. */
    private final IntArray mLatencies = new IntArray();
    public final SparseIntArray errnos = new SparseIntArray();
    /** Latencies of successful blocking connects. TODO: add non-blocking connects latencies. */
    public final IntArray latencies = new IntArray();
    /** TokenBucket for rate limiting latency recording. */
    private final TokenBucket mLatencyTb;
    public final TokenBucket mLatencyTb;
    /** Maximum number of latency values recorded. */
    private final int mMaxLatencyRecords;
    public final int mMaxLatencyRecords;
    /** Total count of successful connects. */
    private int mConnectCount = 0;
    public int connectCount = 0;
    /** Total count of successful connects done in blocking mode. */
    private int mConnectBlockingCount = 0;
    public int connectBlockingCount = 0;
    /** Total count of successful connects with IPv6 socket address. */
    private int mIpv6ConnectCount = 0;
    public int ipv6ConnectCount = 0;

    public ConnectStats(TokenBucket tb, int maxLatencyRecords) {
    public ConnectStats(int netId, long transports, TokenBucket tb, int maxLatencyRecords) {
        this.netId = netId;
        this.transports = transports;
        mLatencyTb = tb;
        mMaxLatencyRecords = maxLatencyRecords;
    }

    public ConnectStatistics toProto() {
        ConnectStatistics stats = new ConnectStatistics();
        stats.connectCount = mConnectCount;
        stats.connectBlockingCount = mConnectBlockingCount;
        stats.ipv6AddrCount = mIpv6ConnectCount;
        stats.latenciesMs = mLatencies.toArray();
        stats.errnosCounters = toPairArrays(mErrnos);
        return stats;
    }

    public void addEvent(int errno, int latencyMs, String ipAddr) {
        if (isSuccess(errno)) {
            countConnect(errno, ipAddr);
@@ -73,12 +67,12 @@ public class ConnectStats {
    }

    private void countConnect(int errno, String ipAddr) {
        mConnectCount++;
        connectCount++;
        if (!isNonBlocking(errno)) {
            mConnectBlockingCount++;
            connectBlockingCount++;
        }
        if (isIPv6(ipAddr)) {
            mIpv6ConnectCount++;
            ipv6ConnectCount++;
        }
    }

@@ -91,16 +85,16 @@ public class ConnectStats {
            // Rate limited
            return;
        }
        if (mLatencies.size() >= mMaxLatencyRecords) {
        if (latencies.size() >= mMaxLatencyRecords) {
            // Hard limit the total number of latency measurements.
            return;
        }
        mLatencies.add(ms);
        latencies.add(ms);
    }

    private void countError(int errno) {
        final int newcount = mErrnos.get(errno, 0) + 1;
        mErrnos.put(errno, newcount);
        final int newcount = errnos.get(errno, 0) + 1;
        errnos.put(errno, newcount);
    }

    private static boolean isSuccess(int errno) {
@@ -117,27 +111,18 @@ public class ConnectStats {
        return ipAddr.contains(":");
    }

    private static Pair[] toPairArrays(SparseIntArray counts) {
        final int s = counts.size();
        Pair[] pairs = new Pair[s];
        for (int i = 0; i < s; i++) {
            Pair p = new Pair();
            p.key = counts.keyAt(i);
            p.value = counts.valueAt(i);
            pairs[i] = p;
        }
        return pairs;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder("ConnectStats(")
                .append(String.format("%d success, ", mConnectCount))
                .append(String.format("%d blocking, ", mConnectBlockingCount))
                .append(String.format("%d IPv6 dst", mIpv6ConnectCount));
        for (int i = 0; i < mErrnos.size(); i++) {
            String errno = OsConstants.errnoName(mErrnos.keyAt(i));
            int count = mErrnos.valueAt(i);
        StringBuilder builder = new StringBuilder("ConnectStats(").append(netId).append(", ");
        for (int t : BitUtils.unpackBits(transports)) {
            builder.append(NetworkCapabilities.transportNameOf(t)).append(", ");
        }
        builder.append(String.format("%d success, ", connectCount));
        builder.append(String.format("%d blocking, ", connectBlockingCount));
        builder.append(String.format("%d IPv6 dst", ipv6ConnectCount));
        for (int i = 0; i < errnos.size(); i++) {
            String errno = OsConstants.errnoName(errnos.keyAt(i));
            int count = errnos.valueAt(i);
            builder.append(String.format(", %s: %d", errno, count));
        }
        return builder.append(")").toString();
+47 −44
Original line number Diff line number Diff line
@@ -16,67 +16,70 @@

package android.net.metrics;

import android.os.Parcel;
import android.os.Parcelable;
import android.net.NetworkCapabilities;
import java.util.Arrays;
import com.android.internal.util.BitUtils;

/**
 * A DNS event recorded by NetdEventListenerService.
 * {@hide}
 */
final public class DnsEvent implements Parcelable {
    public final int netId;
final public class DnsEvent {

    private static final int SIZE_LIMIT = 20000;

    // The event type is currently only 1 or 2, so we store it as a byte.
    public final byte[] eventTypes;
    // Network id of the network associated with the event, or 0 if unspecified.
    public final int netId;
    // Transports of the network associated with the event, as defined in NetworkCapabilities.
    // It is the caller responsability to ensure the value of transports does not change between
    // calls to addResult.
    public final long transports;
    // The number of DNS queries recorded. Queries are stored in the structure-of-array style where
    // the eventTypes, returnCodes, and latenciesMs arrays have the same length and the i-th event
    // is spread across the three array at position i.
    public int eventCount;
    // The types of DNS queries as defined in INetdEventListener.
    public byte[] eventTypes;
    // Current getaddrinfo codes go from 1 to EAI_MAX = 15. gethostbyname returns errno, but there
    // are fewer than 255 errno values. So we store the result code in a byte as well.
    public final byte[] returnCodes;
    // The latency is an integer because a) short arrays aren't parcelable and b) a short can only
    // store a maximum latency of 32757 or 65535 ms, which is too short for pathologically slow
    // queries.
    public final int[] latenciesMs;
    public byte[] returnCodes;
    // Latencies in milliseconds of queries, stored as ints.
    public int[] latenciesMs;

    public DnsEvent(int netId, byte[] eventTypes, byte[] returnCodes, int[] latenciesMs) {
    public DnsEvent(int netId, long transports, int initialCapacity) {
        this.netId = netId;
        this.eventTypes = eventTypes;
        this.returnCodes = returnCodes;
        this.latenciesMs = latenciesMs;
        this.transports = transports;
        eventTypes = new byte[initialCapacity];
        returnCodes = new byte[initialCapacity];
        latenciesMs = new int[initialCapacity];
    }

    private DnsEvent(Parcel in) {
        this.netId = in.readInt();
        this.eventTypes = in.createByteArray();
        this.returnCodes = in.createByteArray();
        this.latenciesMs = in.createIntArray();
    public void addResult(byte eventType, byte returnCode, int latencyMs) {
        if (eventCount >= SIZE_LIMIT) {
            // TODO: implement better rate limiting that does not biases metrics.
            return;
        }

    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(netId);
        out.writeByteArray(eventTypes);
        out.writeByteArray(returnCodes);
        out.writeIntArray(latenciesMs);
        if (eventCount == eventTypes.length) {
            resize((int) (1.4 * eventCount));
        }

    @Override
    public int describeContents() {
        return 0;
        eventTypes[eventCount] = eventType;
        returnCodes[eventCount] = returnCode;
        latenciesMs[eventCount] = latencyMs;
        eventCount++;
    }

    @Override
    public String toString() {
        return String.format("DnsEvent(%d, %d events)", netId, eventTypes.length);
    public void resize(int newLength) {
        eventTypes = Arrays.copyOf(eventTypes, newLength);
        returnCodes = Arrays.copyOf(returnCodes, newLength);
        latenciesMs = Arrays.copyOf(latenciesMs, newLength);
    }

    public static final Parcelable.Creator<DnsEvent> CREATOR = new Parcelable.Creator<DnsEvent>() {
    @Override
        public DnsEvent createFromParcel(Parcel in) {
            return new DnsEvent(in);
    public String toString() {
        StringBuilder builder = new StringBuilder("DnsEvent(").append(netId).append(", ");
        for (int t : BitUtils.unpackBits(transports)) {
            builder.append(NetworkCapabilities.transportNameOf(t)).append(", ");
        }

        @Override
        public DnsEvent[] newArray(int size) {
            return new DnsEvent[size];
        return builder.append(eventCount).append(" events)").toString();
    }
    };
}
+3 −2
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.BitUtils;

/**
 * Class for logging IpConnectvity events with IpConnectivityMetrics
@@ -117,10 +118,10 @@ public class IpConnectivityLog {
     * @param data is a Parcelable instance representing the event.
     * @return true if the event was successfully logged.
     */
    public boolean log(int netid, long transports, Parcelable data) {
    public boolean log(int netid, int[] transports, Parcelable data) {
        ConnectivityMetricsEvent ev = makeEv(data);
        ev.netId = netid;
        ev.transports = transports;
        ev.transports = BitUtils.packBits(transports);
        return log(ev);
    }

Loading