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

Commit 69c9402a authored by Hugo Benichi's avatar Hugo Benichi Committed by Gerrit Code Review
Browse files

Merge "DefaultNetworkEvent metrics: rehaul"

parents 6d14940a 380a0638
Loading
Loading
Loading
Loading
+47 −19
Original line number Diff line number Diff line
@@ -20,44 +20,72 @@ import static android.net.ConnectivityManager.NETID_UNSET;

import android.net.NetworkCapabilities;

import com.android.internal.util.BitUtils;

import java.util.StringJoiner;

/**
 * An event recorded by ConnectivityService when there is a change in the default network.
 * {@hide}
 */
public class DefaultNetworkEvent {

    // The ID of the network that has become the new default or NETID_UNSET if none.
    // The creation time in milliseconds of this DefaultNetworkEvent.
    public final long creationTimeMs;
    // The network ID of the network or NETID_UNSET if none.
    public int netId = NETID_UNSET;
    // The list of transport types of the new default network, for example TRANSPORT_WIFI, as
    // defined in NetworkCapabilities.java.
    public int[] transportTypes = new int[0];
    // The ID of the network that was the default before or NETID_UNSET if none.
    public int prevNetId = NETID_UNSET;
    // Whether the previous network had IPv4/IPv6 connectivity.
    public boolean prevIPv4;
    public boolean prevIPv6;
    // The list of transport types, as defined in NetworkCapabilities.java.
    public int transports;
    // The list of transport types of the last previous default network.
    public int previousTransports;
    // Whether the network has IPv4/IPv6 connectivity.
    public boolean ipv4;
    public boolean ipv6;
    // The initial network score when this network became the default network.
    public int initialScore;
    // The initial network score when this network stopped being the default network.
    public int finalScore;
    // The total duration in milliseconds this network was the default network.
    public long durationMs;
    // The total duration in milliseconds this network was the default network and was validated.
    public long validatedMs;

    public DefaultNetworkEvent(long timeMs) {
        creationTimeMs = timeMs;
    }

    /** Update the durationMs of this DefaultNetworkEvent for the given current time. */
    public void updateDuration(long timeMs) {
        durationMs = timeMs - creationTimeMs;
    }

    @Override
    public String toString() {
        String prevNetwork = String.valueOf(prevNetId);
        String newNetwork = String.valueOf(netId);
        if (prevNetId != 0) {
            prevNetwork += ":" + ipSupport();
        StringJoiner j = new StringJoiner(", ", "DefaultNetworkEvent(", ")");
        j.add("netId=" + netId);
        for (int t : BitUtils.unpackBits(transports)) {
            j.add(NetworkCapabilities.transportNameOf(t));
        }
        j.add("ip=" + ipSupport());
        if (initialScore > 0) {
            j.add("initial_score=" + initialScore);
        }
        if (netId != 0) {
            newNetwork += ":" + NetworkCapabilities.transportNamesOf(transportTypes);
        if (finalScore > 0) {
            j.add("final_score=" + finalScore);
        }
        return String.format("DefaultNetworkEvent(%s -> %s)", prevNetwork, newNetwork);
        j.add(String.format("duration=%.0fs", durationMs / 1000.0));
        j.add(String.format("validation=%4.1f%%", (validatedMs * 100.0) / durationMs));
        return j.toString();
    }

    private String ipSupport() {
        if (prevIPv4 && prevIPv6) {
        if (ipv4 && ipv6) {
            return "IPv4v6";
        }
        if (prevIPv6) {
        if (ipv6) {
            return "IPv6";
        }
        if (prevIPv4) {
        if (ipv4) {
            return "IPv4";
        }
        return "NONE";
+25 −11
Original line number Diff line number Diff line
@@ -50,9 +50,10 @@ message Pair {
  optional int32 value = 2;
};

// An event record when the system default network disconnects or the system
// switches to a new default network.
// Next tag: 10.
// An event recorded when the system default network disconnects or the system
// switches to a new default network. An event is also recorded to cover gaps
// without a default network.
// Next tag: 12
message DefaultNetworkEvent {

  // Reason why this network stopped being the default.
@@ -72,26 +73,34 @@ message DefaultNetworkEvent {
  };

  // Duration in milliseconds when this network was the default.
  // Since version 4
  // Since P.
  optional int64 default_network_duration_ms = 5;

  // Duration in milliseconds without a default network before this network
  // became the default.
  // Since version 4
  optional int64 no_default_network_duration_ms = 6;
  // Duration in milliseconds when this default network Internet access was
  // validated. This field is equal to 0 for DefaultNetworkEvents representing
  // lack of a default network.
  // Since P.
  optional int64 validation_duration_ms = 11;

  // Network score of this network when it became the default network.
  // Since version 4
  // Or 0 if this event represents a period without a default network.
  // Since P.
  optional int64 initial_score = 7;

  // Network score of this network when it stopped being the default network.
  // Since version 4
  // Or 0 if this event represents a period without a default network.
  // Since P.
  optional int64 final_score = 8;

  // Best available information about IP support of this default network.
  // Since version 4
  // Or NONE if this event represents a period without a default network.
  // Since P.
  optional IPSupport ip_support = 9;

  // LinkLayer of the previous default network. Ignores any previous period
  // without a default network.
  // Since P
  optional LinkLayer previous_default_network_link_layer = 10;

  // Deprecated fields

@@ -112,6 +121,11 @@ message DefaultNetworkEvent {
  // TRANSPORT_* constants as defined in NetworkCapabilities.
  // Deprecated since version 3. Replaced by top-level transports field.
  repeated int32 transport_types = 4 [deprecated = true];

  // Duration in milliseconds without a default network. This field is non-zero
  // only for DefaultNetworkEvents representing lack of a default network.
  // Since P.
  optional int64 no_default_network_duration_ms = 6 [deprecated = true];
};

// Logs IpReachabilityMonitor probe events and NUD_FAILED events.
+8 −2
Original line number Diff line number Diff line
@@ -2113,9 +2113,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
                        final boolean valid =
                                (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
                        final boolean wasValidated = nai.lastValidated;
                        final boolean wasDefault = isDefaultNetwork(nai);
                        if (DBG) log(nai.name() + " validation " + (valid ? "passed" : "failed") +
                                (msg.obj == null ? "" : " with redirect to " + (String)msg.obj));
                        if (valid != nai.lastValidated) {
                            if (wasDefault) {
                                metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity(
                                        SystemClock.elapsedRealtime(), valid);
                            }
                            final int oldScore = nai.getCurrentScore();
                            nai.lastValidated = valid;
                            nai.everValidated |= valid;
@@ -2287,7 +2292,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
                // Let rematchAllNetworksAndRequests() below record a new default network event
                // if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
                // whose timestamps tell how long it takes to recover a default network.
                metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(null, nai);
                long now = SystemClock.elapsedRealtime();
                metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
            }
            notifyIfacesChangedForNetworkStats();
            // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
@@ -5041,7 +5047,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
            makeDefault(newNetwork);
            // Log 0 -> X and Y -> X default network transitions, where X is the new default.
            metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
                    newNetwork, oldDefaultNetwork);
                    now, newNetwork, oldDefaultNetwork);
            // Have a new default network, release the transition wakelock in
            scheduleReleaseNetworkTransitionWakelock();
        }
+102 −15
Original line number Diff line number Diff line
@@ -18,9 +18,11 @@ package com.android.server.connectivity;

import android.net.LinkProperties;
import android.net.metrics.DefaultNetworkEvent;
import android.net.metrics.IpConnectivityLog;
import android.os.SystemClock;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.BitUtils;
import com.android.internal.util.RingBuffer;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;

import java.io.PrintWriter;
@@ -35,19 +37,49 @@ public class DefaultNetworkMetrics {

    private static final int ROLLING_LOG_SIZE = 64;

    public final long creationTimeMs = SystemClock.elapsedRealtime();

    // Event buffer used for metrics upload. The buffer is cleared when events are collected.
    @GuardedBy("this")
    private final List<DefaultNetworkEvent> mEvents = new ArrayList<>();

    // Rolling event buffer used for dumpsys and bugreports.
    @GuardedBy("this")
    private final RingBuffer<DefaultNetworkEvent> mEventsLog =
            new RingBuffer(DefaultNetworkEvent.class, ROLLING_LOG_SIZE);

    // Information about the current status of the default network.
    @GuardedBy("this")
    private DefaultNetworkEvent mCurrentDefaultNetwork;
    @GuardedBy("this")
    private boolean mIsCurrentlyValid;
    @GuardedBy("this")
    private long mLastValidationTimeMs;
    // Transport information about the last default network.
    @GuardedBy("this")
    private int mLastTransports;

    public DefaultNetworkMetrics() {
        newDefaultNetwork(creationTimeMs, null);
    }

    public synchronized void listEvents(PrintWriter pw) {
        pw.println("default network events:");
        long localTimeMs = System.currentTimeMillis();
        for (DefaultNetworkEvent ev : mEvents) {
            pw.println(ev);
        long timeMs = SystemClock.elapsedRealtime();
        for (DefaultNetworkEvent ev : mEventsLog.toArray()) {
            printEvent(localTimeMs, pw, ev);
        }
        mCurrentDefaultNetwork.updateDuration(timeMs);
        if (mIsCurrentlyValid) {
            updateValidationTime(timeMs);
            mLastValidationTimeMs = timeMs;
        }
        printEvent(localTimeMs, pw, mCurrentDefaultNetwork);
    }

    public synchronized void listEventsAsProto(PrintWriter pw) {
        for (DefaultNetworkEvent ev : mEvents) {
        for (DefaultNetworkEvent ev : mEventsLog.toArray()) {
            pw.print(IpConnectivityEventBuilder.toProto(ev));
        }
    }
@@ -59,20 +91,75 @@ public class DefaultNetworkMetrics {
        mEvents.clear();
    }

    public synchronized void logDefaultNetworkValidity(long timeMs, boolean isValid) {
        if (!isValid && mIsCurrentlyValid) {
            mIsCurrentlyValid = false;
            updateValidationTime(timeMs);
        }

        if (isValid && !mIsCurrentlyValid) {
            mIsCurrentlyValid = true;
            mLastValidationTimeMs = timeMs;
        }
    }

    private void updateValidationTime(long timeMs) {
        mCurrentDefaultNetwork.validatedMs += timeMs - mLastValidationTimeMs;
    }

    public synchronized void logDefaultNetworkEvent(
            NetworkAgentInfo newNai, NetworkAgentInfo prevNai) {
        DefaultNetworkEvent ev = new DefaultNetworkEvent();
            long timeMs, NetworkAgentInfo newNai, NetworkAgentInfo oldNai) {
        logCurrentDefaultNetwork(timeMs, oldNai);
        newDefaultNetwork(timeMs, newNai);
    }

    private void logCurrentDefaultNetwork(long timeMs, NetworkAgentInfo oldNai) {
        DefaultNetworkEvent ev = mCurrentDefaultNetwork;
        ev.updateDuration(timeMs);
        ev.previousTransports = mLastTransports;
        // oldNai is null if the system had no default network before the transition.
        if (oldNai != null) {
            // The system acquired a new default network.
            fillLinkInfo(ev, oldNai);
            ev.finalScore = oldNai.getCurrentScore();
            ev.validatedMs = ev.durationMs;
        }
        // Only change transport of the previous default network if the event currently logged
        // corresponds to an existing default network, and not to the absence of a default network.
        // This allows to log pairs of transports for successive default networks regardless of
        // whether or not the system experienced a period without any default network.
        if (ev.transports != 0) {
            mLastTransports = ev.transports;
        }
        mEvents.add(ev);
        mEventsLog.append(ev);
    }

    private void newDefaultNetwork(long timeMs, NetworkAgentInfo newNai) {
        DefaultNetworkEvent ev = new DefaultNetworkEvent(timeMs);
        ev.durationMs = timeMs;
        // newNai is null if the system has no default network after the transition.
        if (newNai != null) {
            ev.netId = newNai.network().netId;
            ev.transportTypes = newNai.networkCapabilities.getTransportTypes();
            fillLinkInfo(ev, newNai);
            ev.initialScore = newNai.getCurrentScore();
            if (newNai.lastValidated) {
                mIsCurrentlyValid = true;
                mLastValidationTimeMs = timeMs;
            }
        }
        if (prevNai != null) {
            ev.prevNetId = prevNai.network().netId;
            final LinkProperties lp = prevNai.linkProperties;
            ev.prevIPv4 = lp.hasIPv4Address() && lp.hasIPv4DefaultRoute();
            ev.prevIPv6 = lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute();
        mCurrentDefaultNetwork = ev;
    }

        mEvents.add(ev);
    private static void fillLinkInfo(DefaultNetworkEvent ev, NetworkAgentInfo nai) {
        LinkProperties lp = nai.linkProperties;
        ev.netId = nai.network().netId;
        ev.transports |= BitUtils.packBits(nai.networkCapabilities.getTransportTypes());
        ev.ipv4 |= lp.hasIPv4Address() && lp.hasIPv4DefaultRoute();
        ev.ipv6 |= lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute();
    }

    private static void printEvent(long localTimeMs, PrintWriter pw, DefaultNetworkEvent ev) {
        long localCreationTimeMs = localTimeMs - ev.durationMs;
        pw.println(String.format("%tT.%tL: %s", localCreationTimeMs, localCreationTimeMs, ev));
    }
}
+15 −8
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;

import android.net.ConnectivityManager;
import android.net.ConnectivityMetricsEvent;
import android.net.metrics.ApfProgramEvent;
import android.net.metrics.ApfStats;
@@ -135,11 +136,17 @@ final public class IpConnectivityEventBuilder {
    public static IpConnectivityEvent toProto(DefaultNetworkEvent in) {
        IpConnectivityLogClass.DefaultNetworkEvent ev =
                new IpConnectivityLogClass.DefaultNetworkEvent();
        ev.networkId = netIdOf(in.netId);
        ev.previousNetworkId = netIdOf(in.prevNetId);
        ev.transportTypes = in.transportTypes;
        ev.previousNetworkIpSupport = ipSupportOf(in);
        final IpConnectivityEvent out = buildEvent(in.netId, 0, null);
        ev.finalScore = in.finalScore;
        ev.initialScore = in.initialScore;
        ev.ipSupport = ipSupportOf(in);
        ev.defaultNetworkDurationMs = in.durationMs;
        ev.validationDurationMs = in.validatedMs;
        ev.previousDefaultNetworkLinkLayer = transportsToLinkLayer(in.previousTransports);
        final IpConnectivityEvent out = buildEvent(in.netId, in.transports, null);
        if (in.transports == 0) {
            // Set link layer to NONE for events representing the absence of a default network.
            out.linkLayer = IpConnectivityLogClass.NONE;
        }
        out.setDefaultNetworkEvent(ev);
        return out;
    }
@@ -321,13 +328,13 @@ final public class IpConnectivityEventBuilder {
    }

    private static int ipSupportOf(DefaultNetworkEvent in) {
        if (in.prevIPv4 && in.prevIPv6) {
        if (in.ipv4 && in.ipv6) {
            return IpConnectivityLogClass.DefaultNetworkEvent.DUAL;
        }
        if (in.prevIPv6) {
        if (in.ipv6) {
            return IpConnectivityLogClass.DefaultNetworkEvent.IPV6;
        }
        if (in.prevIPv4) {
        if (in.ipv4) {
            return IpConnectivityLogClass.DefaultNetworkEvent.IPV4;
        }
        return IpConnectivityLogClass.DefaultNetworkEvent.NONE;
Loading