Merge "DefaultNetworkEvent metrics: rehaul"
This commit is contained in:
@@ -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));
|
||||
}
|
||||
if (netId != 0) {
|
||||
newNetwork += ":" + NetworkCapabilities.transportNamesOf(transportTypes);
|
||||
j.add("ip=" + ipSupport());
|
||||
if (initialScore > 0) {
|
||||
j.add("initial_score=" + initialScore);
|
||||
}
|
||||
return String.format("DefaultNetworkEvent(%s -> %s)", prevNetwork, newNetwork);
|
||||
if (finalScore > 0) {
|
||||
j.add("final_score=" + finalScore);
|
||||
}
|
||||
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";
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 logDefaultNetworkEvent(
|
||||
NetworkAgentInfo newNai, NetworkAgentInfo prevNai) {
|
||||
DefaultNetworkEvent ev = new DefaultNetworkEvent();
|
||||
if (newNai != null) {
|
||||
ev.netId = newNai.network().netId;
|
||||
ev.transportTypes = newNai.networkCapabilities.getTransportTypes();
|
||||
}
|
||||
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();
|
||||
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(
|
||||
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) {
|
||||
fillLinkInfo(ev, newNai);
|
||||
ev.initialScore = newNai.getCurrentScore();
|
||||
if (newNai.lastValidated) {
|
||||
mIsCurrentlyValid = true;
|
||||
mLastValidationTimeMs = timeMs;
|
||||
}
|
||||
}
|
||||
mCurrentDefaultNetwork = 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -45,6 +45,7 @@ import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.ToIntFunction;
|
||||
|
||||
@@ -214,86 +215,66 @@ final public class IpConnectivityMetrics extends SystemService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the event buffer and prints its content as a protobuf serialized byte array
|
||||
* Clear the event buffer and prints its content as a protobuf serialized byte array
|
||||
* inside a base64 encoded string.
|
||||
*/
|
||||
private void cmdFlush(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
private void cmdFlush(PrintWriter pw) {
|
||||
pw.print(flushEncodedOutput());
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the content of the event buffer, either using the events ASCII representation
|
||||
* or using protobuf text format.
|
||||
* Print the content of the rolling event buffer in human readable format.
|
||||
* Also print network dns/connect statistics and recent default network events.
|
||||
*/
|
||||
private void cmdList(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
final ArrayList<ConnectivityMetricsEvent> events;
|
||||
synchronized (mLock) {
|
||||
events = new ArrayList(mBuffer);
|
||||
}
|
||||
|
||||
if (args.length > 1 && args[1].equals("proto")) {
|
||||
for (IpConnectivityEvent ev : IpConnectivityEventBuilder.toProto(events)) {
|
||||
pw.print(ev.toString());
|
||||
}
|
||||
if (mNetdListener != null) {
|
||||
mNetdListener.listAsProtos(pw);
|
||||
}
|
||||
mDefaultNetworkMetrics.listEventsAsProto(pw);
|
||||
return;
|
||||
}
|
||||
|
||||
private void cmdList(PrintWriter pw) {
|
||||
pw.println("metrics events:");
|
||||
final List<ConnectivityMetricsEvent> events = getEvents();
|
||||
for (ConnectivityMetricsEvent ev : events) {
|
||||
pw.println(ev.toString());
|
||||
}
|
||||
pw.println("");
|
||||
if (mNetdListener != null) {
|
||||
mNetdListener.list(pw);
|
||||
}
|
||||
pw.println("");
|
||||
mDefaultNetworkMetrics.listEvents(pw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints for bug reports the content of the rolling event log and the
|
||||
* content of Netd event listener.
|
||||
/*
|
||||
* Print the content of the rolling event buffer in text proto format.
|
||||
*/
|
||||
private void cmdDumpsys(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
final ConnectivityMetricsEvent[] events;
|
||||
synchronized (mLock) {
|
||||
events = mEventLog.toArray();
|
||||
}
|
||||
for (ConnectivityMetricsEvent ev : events) {
|
||||
pw.println(ev.toString());
|
||||
private void cmdListAsProto(PrintWriter pw) {
|
||||
final List<ConnectivityMetricsEvent> events = getEvents();
|
||||
for (IpConnectivityEvent ev : IpConnectivityEventBuilder.toProto(events)) {
|
||||
pw.print(ev.toString());
|
||||
}
|
||||
if (mNetdListener != null) {
|
||||
mNetdListener.list(pw);
|
||||
mNetdListener.listAsProtos(pw);
|
||||
}
|
||||
mDefaultNetworkMetrics.listEvents(pw);
|
||||
mDefaultNetworkMetrics.listEventsAsProto(pw);
|
||||
}
|
||||
|
||||
private void cmdStats(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
/*
|
||||
* Return a copy of metrics events stored in buffer for metrics uploading.
|
||||
*/
|
||||
private List<ConnectivityMetricsEvent> getEvents() {
|
||||
synchronized (mLock) {
|
||||
pw.println("Buffered events: " + mBuffer.size());
|
||||
pw.println("Buffer capacity: " + mCapacity);
|
||||
pw.println("Dropped events: " + mDropped);
|
||||
return Arrays.asList(mEventLog.toArray());
|
||||
}
|
||||
if (mNetdListener != null) {
|
||||
mNetdListener.dump(pw);
|
||||
}
|
||||
}
|
||||
|
||||
private void cmdDefault(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
if (args.length == 0) {
|
||||
pw.println("No command");
|
||||
return;
|
||||
}
|
||||
pw.println("Unknown command " + TextUtils.join(" ", args));
|
||||
}
|
||||
|
||||
public final class Impl extends IIpConnectivityMetrics.Stub {
|
||||
static final String CMD_FLUSH = "flush";
|
||||
static final String CMD_LIST = "list";
|
||||
static final String CMD_STATS = "stats";
|
||||
static final String CMD_DUMPSYS = "-a"; // dumpsys.cpp dumps services with "-a" as arguments
|
||||
static final String CMD_DEFAULT = CMD_STATS;
|
||||
// Dump and flushes the metrics event buffer in base64 encoded serialized proto output.
|
||||
static final String CMD_FLUSH = "flush";
|
||||
// Dump the rolling buffer of metrics event in human readable proto text format.
|
||||
static final String CMD_PROTO = "proto";
|
||||
// Dump the rolling buffer of metrics event and pretty print events using a human readable
|
||||
// format. Also print network dns/connect statistics and default network event time series.
|
||||
static final String CMD_LIST = "list";
|
||||
// By default any other argument will fall into the default case which is remapped to the
|
||||
// "list" command. This includes most notably bug reports collected by dumpsys.cpp with
|
||||
// the "-a" argument.
|
||||
static final String CMD_DEFAULT = CMD_LIST;
|
||||
|
||||
@Override
|
||||
public int logEvent(ConnectivityMetricsEvent event) {
|
||||
@@ -308,19 +289,15 @@ final public class IpConnectivityMetrics extends SystemService {
|
||||
final String cmd = (args.length > 0) ? args[0] : CMD_DEFAULT;
|
||||
switch (cmd) {
|
||||
case CMD_FLUSH:
|
||||
cmdFlush(fd, pw, args);
|
||||
cmdFlush(pw);
|
||||
return;
|
||||
case CMD_DUMPSYS:
|
||||
cmdDumpsys(fd, pw, args);
|
||||
return;
|
||||
case CMD_LIST:
|
||||
cmdList(fd, pw, args);
|
||||
return;
|
||||
case CMD_STATS:
|
||||
cmdStats(fd, pw, args);
|
||||
case CMD_PROTO:
|
||||
cmdListAsProto(pw);
|
||||
return;
|
||||
case CMD_LIST: // fallthrough
|
||||
default:
|
||||
cmdDefault(fd, pw, args);
|
||||
cmdList(pw);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -243,24 +243,21 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
|
||||
mWakeupStats.clear();
|
||||
}
|
||||
|
||||
public synchronized void dump(PrintWriter writer) {
|
||||
IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
|
||||
pw.println(TAG + ":");
|
||||
pw.increaseIndent();
|
||||
list(pw);
|
||||
pw.decreaseIndent();
|
||||
}
|
||||
|
||||
public synchronized void list(PrintWriter pw) {
|
||||
pw.println("dns/connect events:");
|
||||
for (int i = 0; i < mNetworkMetrics.size(); i++) {
|
||||
pw.println(mNetworkMetrics.valueAt(i).connectMetrics);
|
||||
}
|
||||
for (int i = 0; i < mNetworkMetrics.size(); i++) {
|
||||
pw.println(mNetworkMetrics.valueAt(i).dnsMetrics);
|
||||
}
|
||||
pw.println("");
|
||||
pw.println("network statistics:");
|
||||
for (NetworkMetricsSnapshot s : getNetworkMetricsSnapshots()) {
|
||||
pw.println(s);
|
||||
}
|
||||
pw.println("");
|
||||
pw.println("packet wakeup events:");
|
||||
for (int i = 0; i < mWakeupStats.size(); i++) {
|
||||
pw.println(mWakeupStats.valueAt(i));
|
||||
}
|
||||
|
||||
@@ -198,37 +198,33 @@ public class IpConnectivityEventBuilderTest {
|
||||
|
||||
@Test
|
||||
public void testDefaultNetworkEventSerialization() {
|
||||
DefaultNetworkEvent ev = new DefaultNetworkEvent();
|
||||
DefaultNetworkEvent ev = new DefaultNetworkEvent(1001);
|
||||
ev.netId = 102;
|
||||
ev.prevNetId = 101;
|
||||
ev.transportTypes = new int[]{1, 2, 3};
|
||||
ev.prevIPv4 = true;
|
||||
ev.prevIPv6 = true;
|
||||
ev.transports = 2;
|
||||
ev.previousTransports = 4;
|
||||
ev.ipv4 = true;
|
||||
ev.initialScore = 20;
|
||||
ev.finalScore = 60;
|
||||
ev.durationMs = 54;
|
||||
ev.validatedMs = 27;
|
||||
|
||||
String want = String.join("\n",
|
||||
"dropped_events: 0",
|
||||
"events <",
|
||||
" if_name: \"\"",
|
||||
" link_layer: 0",
|
||||
" link_layer: 4",
|
||||
" network_id: 102",
|
||||
" time_ms: 0",
|
||||
" transports: 0",
|
||||
" transports: 2",
|
||||
" default_network_event <",
|
||||
" default_network_duration_ms: 0",
|
||||
" final_score: 0",
|
||||
" initial_score: 0",
|
||||
" ip_support: 0",
|
||||
" network_id <",
|
||||
" network_id: 102",
|
||||
" >",
|
||||
" default_network_duration_ms: 54",
|
||||
" final_score: 60",
|
||||
" initial_score: 20",
|
||||
" ip_support: 1",
|
||||
" no_default_network_duration_ms: 0",
|
||||
" previous_network_id <",
|
||||
" network_id: 101",
|
||||
" >",
|
||||
" previous_network_ip_support: 3",
|
||||
" transport_types: 1",
|
||||
" transport_types: 2",
|
||||
" transport_types: 3",
|
||||
" previous_default_network_link_layer: 1",
|
||||
" previous_network_ip_support: 0",
|
||||
" validation_duration_ms: 27",
|
||||
" >",
|
||||
">",
|
||||
"version: 2\n");
|
||||
|
||||
@@ -188,119 +188,99 @@ public class IpConnectivityMetricsTest {
|
||||
{makeNai(102, 50, true, true, cell), makeNai(103, 20, true, false, wifi)},
|
||||
};
|
||||
|
||||
long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
|
||||
long durationMs = 1001;
|
||||
for (NetworkAgentInfo[] pair : defaultNetworks) {
|
||||
mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(pair[1], pair[0]);
|
||||
timeMs += durationMs;
|
||||
durationMs += durationMs;
|
||||
mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs, pair[1], pair[0]);
|
||||
}
|
||||
|
||||
String want = String.join("\n",
|
||||
"dropped_events: 0",
|
||||
"events <",
|
||||
" if_name: \"\"",
|
||||
" link_layer: 0",
|
||||
" network_id: 100",
|
||||
" time_ms: 0",
|
||||
" transports: 0",
|
||||
" default_network_event <",
|
||||
" default_network_duration_ms: 0",
|
||||
" final_score: 0",
|
||||
" initial_score: 0",
|
||||
" ip_support: 0",
|
||||
" network_id <",
|
||||
" network_id: 100",
|
||||
" >",
|
||||
" no_default_network_duration_ms: 0",
|
||||
" previous_network_id <",
|
||||
" network_id: 0",
|
||||
" >",
|
||||
" previous_network_ip_support: 0",
|
||||
" transport_types: 0",
|
||||
" >",
|
||||
">",
|
||||
"events <",
|
||||
" if_name: \"\"",
|
||||
" link_layer: 0",
|
||||
" network_id: 101",
|
||||
" time_ms: 0",
|
||||
" transports: 0",
|
||||
" default_network_event <",
|
||||
" default_network_duration_ms: 0",
|
||||
" final_score: 0",
|
||||
" initial_score: 0",
|
||||
" ip_support: 0",
|
||||
" network_id <",
|
||||
" network_id: 101",
|
||||
" >",
|
||||
" no_default_network_duration_ms: 0",
|
||||
" previous_network_id <",
|
||||
" network_id: 100",
|
||||
" >",
|
||||
" previous_network_ip_support: 3",
|
||||
" transport_types: 1",
|
||||
" >",
|
||||
">",
|
||||
"events <",
|
||||
" if_name: \"\"",
|
||||
" link_layer: 0",
|
||||
" link_layer: 5",
|
||||
" network_id: 0",
|
||||
" time_ms: 0",
|
||||
" transports: 0",
|
||||
" default_network_event <",
|
||||
" default_network_duration_ms: 0",
|
||||
" default_network_duration_ms: 1001",
|
||||
" final_score: 0",
|
||||
" initial_score: 0",
|
||||
" ip_support: 0",
|
||||
" network_id <",
|
||||
" network_id: 0",
|
||||
" >",
|
||||
" no_default_network_duration_ms: 0",
|
||||
" previous_network_id <",
|
||||
" network_id: 101",
|
||||
" >",
|
||||
" previous_network_ip_support: 1",
|
||||
" previous_default_network_link_layer: 0",
|
||||
" previous_network_ip_support: 0",
|
||||
" validation_duration_ms: 0",
|
||||
" >",
|
||||
">",
|
||||
"events <",
|
||||
" if_name: \"\"",
|
||||
" link_layer: 0",
|
||||
" link_layer: 2",
|
||||
" network_id: 100",
|
||||
" time_ms: 0",
|
||||
" transports: 1",
|
||||
" default_network_event <",
|
||||
" default_network_duration_ms: 2002",
|
||||
" final_score: 50",
|
||||
" initial_score: 10",
|
||||
" ip_support: 3",
|
||||
" no_default_network_duration_ms: 0",
|
||||
" previous_default_network_link_layer: 0",
|
||||
" previous_network_ip_support: 0",
|
||||
" validation_duration_ms: 2002",
|
||||
" >",
|
||||
">",
|
||||
"events <",
|
||||
" if_name: \"\"",
|
||||
" link_layer: 4",
|
||||
" network_id: 101",
|
||||
" time_ms: 0",
|
||||
" transports: 2",
|
||||
" default_network_event <",
|
||||
" default_network_duration_ms: 4004",
|
||||
" final_score: 60",
|
||||
" initial_score: 20",
|
||||
" ip_support: 1",
|
||||
" no_default_network_duration_ms: 0",
|
||||
" previous_default_network_link_layer: 2",
|
||||
" previous_network_ip_support: 0",
|
||||
" validation_duration_ms: 4004",
|
||||
" >",
|
||||
">",
|
||||
"events <",
|
||||
" if_name: \"\"",
|
||||
" link_layer: 5",
|
||||
" network_id: 0",
|
||||
" time_ms: 0",
|
||||
" transports: 0",
|
||||
" default_network_event <",
|
||||
" default_network_duration_ms: 8008",
|
||||
" final_score: 0",
|
||||
" initial_score: 0",
|
||||
" ip_support: 0",
|
||||
" no_default_network_duration_ms: 0",
|
||||
" previous_default_network_link_layer: 4",
|
||||
" previous_network_ip_support: 0",
|
||||
" validation_duration_ms: 0",
|
||||
" >",
|
||||
">",
|
||||
"events <",
|
||||
" if_name: \"\"",
|
||||
" link_layer: 2",
|
||||
" network_id: 102",
|
||||
" time_ms: 0",
|
||||
" transports: 0",
|
||||
" transports: 1",
|
||||
" default_network_event <",
|
||||
" default_network_duration_ms: 0",
|
||||
" final_score: 0",
|
||||
" initial_score: 0",
|
||||
" ip_support: 0",
|
||||
" network_id <",
|
||||
" network_id: 102",
|
||||
" >",
|
||||
" default_network_duration_ms: 16016",
|
||||
" final_score: 50",
|
||||
" initial_score: 10",
|
||||
" ip_support: 3",
|
||||
" no_default_network_duration_ms: 0",
|
||||
" previous_network_id <",
|
||||
" network_id: 0",
|
||||
" >",
|
||||
" previous_default_network_link_layer: 4",
|
||||
" previous_network_ip_support: 0",
|
||||
" transport_types: 0",
|
||||
" >",
|
||||
">",
|
||||
"events <",
|
||||
" if_name: \"\"",
|
||||
" link_layer: 0",
|
||||
" network_id: 103",
|
||||
" time_ms: 0",
|
||||
" transports: 0",
|
||||
" default_network_event <",
|
||||
" default_network_duration_ms: 0",
|
||||
" final_score: 0",
|
||||
" initial_score: 0",
|
||||
" ip_support: 0",
|
||||
" network_id <",
|
||||
" network_id: 103",
|
||||
" >",
|
||||
" no_default_network_duration_ms: 0",
|
||||
" previous_network_id <",
|
||||
" network_id: 102",
|
||||
" >",
|
||||
" previous_network_ip_support: 3",
|
||||
" transport_types: 1",
|
||||
" validation_duration_ms: 16016",
|
||||
" >",
|
||||
">",
|
||||
"version: 2\n");
|
||||
@@ -379,12 +359,13 @@ public class IpConnectivityMetricsTest {
|
||||
wakeupEvent("wlan0", 10008);
|
||||
wakeupEvent("rmnet0", 1000);
|
||||
|
||||
long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
|
||||
final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
|
||||
final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
|
||||
NetworkAgentInfo cellNai = makeNai(100, 50, false, true, cell);
|
||||
NetworkAgentInfo wifiNai = makeNai(101, 60, true, false, wifi);
|
||||
mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(cellNai, null);
|
||||
mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(wifiNai, cellNai);
|
||||
mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs + 200, cellNai, null);
|
||||
mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs + 300, wifiNai, cellNai);
|
||||
|
||||
String want = String.join("\n",
|
||||
"dropped_events: 0",
|
||||
@@ -473,46 +454,36 @@ public class IpConnectivityMetricsTest {
|
||||
">",
|
||||
"events <",
|
||||
" if_name: \"\"",
|
||||
" link_layer: 0",
|
||||
" network_id: 100",
|
||||
" link_layer: 5",
|
||||
" network_id: 0",
|
||||
" time_ms: 0",
|
||||
" transports: 0",
|
||||
" default_network_event <",
|
||||
" default_network_duration_ms: 0",
|
||||
" default_network_duration_ms: 200",
|
||||
" final_score: 0",
|
||||
" initial_score: 0",
|
||||
" ip_support: 0",
|
||||
" network_id <",
|
||||
" network_id: 100",
|
||||
" >",
|
||||
" no_default_network_duration_ms: 0",
|
||||
" previous_network_id <",
|
||||
" network_id: 0",
|
||||
" >",
|
||||
" previous_default_network_link_layer: 0",
|
||||
" previous_network_ip_support: 0",
|
||||
" transport_types: 0",
|
||||
" validation_duration_ms: 0",
|
||||
" >",
|
||||
">",
|
||||
"events <",
|
||||
" if_name: \"\"",
|
||||
" link_layer: 0",
|
||||
" network_id: 101",
|
||||
" link_layer: 2",
|
||||
" network_id: 100",
|
||||
" time_ms: 0",
|
||||
" transports: 0",
|
||||
" transports: 1",
|
||||
" default_network_event <",
|
||||
" default_network_duration_ms: 0",
|
||||
" final_score: 0",
|
||||
" initial_score: 0",
|
||||
" ip_support: 0",
|
||||
" network_id <",
|
||||
" network_id: 101",
|
||||
" >",
|
||||
" default_network_duration_ms: 100",
|
||||
" final_score: 50",
|
||||
" initial_score: 50",
|
||||
" ip_support: 2",
|
||||
" no_default_network_duration_ms: 0",
|
||||
" previous_network_id <",
|
||||
" network_id: 100",
|
||||
" >",
|
||||
" previous_network_ip_support: 2",
|
||||
" transport_types: 1",
|
||||
" previous_default_network_link_layer: 0",
|
||||
" previous_network_ip_support: 0",
|
||||
" validation_duration_ms: 100",
|
||||
" >",
|
||||
">",
|
||||
"events <",
|
||||
|
||||
@@ -82,9 +82,8 @@ public class NetdEventListenerServiceTest {
|
||||
public void testWakeupEventLogging() throws Exception {
|
||||
final int BUFFER_LENGTH = NetdEventListenerService.WAKEUP_EVENT_BUFFER_LENGTH;
|
||||
|
||||
// Assert no events
|
||||
String[] events1 = listNetdEvent();
|
||||
assertEquals(new String[]{""}, events1);
|
||||
// Baseline without any event
|
||||
String[] baseline = listNetdEvent();
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
String prefix = "iface:wlan0";
|
||||
@@ -93,7 +92,7 @@ public class NetdEventListenerServiceTest {
|
||||
mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, now);
|
||||
}
|
||||
|
||||
String[] events2 = listNetdEvent();
|
||||
String[] events2 = remove(listNetdEvent(), baseline);
|
||||
int expectedLength2 = uids.length + 1; // +1 for the WakeupStats line
|
||||
assertEquals(expectedLength2, events2.length);
|
||||
assertContains(events2[0], "WakeupStats");
|
||||
@@ -111,7 +110,7 @@ public class NetdEventListenerServiceTest {
|
||||
mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, ts);
|
||||
}
|
||||
|
||||
String[] events3 = listNetdEvent();
|
||||
String[] events3 = remove(listNetdEvent(), baseline);
|
||||
int expectedLength3 = BUFFER_LENGTH + 1; // +1 for the WakeupStats line
|
||||
assertEquals(expectedLength3, events3.length);
|
||||
assertContains(events2[0], "WakeupStats");
|
||||
@@ -126,7 +125,7 @@ public class NetdEventListenerServiceTest {
|
||||
uid = 45678;
|
||||
mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, now);
|
||||
|
||||
String[] events4 = listNetdEvent();
|
||||
String[] events4 = remove(listNetdEvent(), baseline);
|
||||
String lastEvent = events4[events4.length - 1];
|
||||
assertContains(lastEvent, "WakeupEvent");
|
||||
assertContains(lastEvent, "wlan0");
|
||||
@@ -423,7 +422,7 @@ public class NetdEventListenerServiceTest {
|
||||
final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
|
||||
new Thread(() -> {
|
||||
while (System.currentTimeMillis() < stop) {
|
||||
mNetdEventListenerService.dump(pw);
|
||||
mNetdEventListenerService.list(pw);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
@@ -461,4 +460,16 @@ public class NetdEventListenerServiceTest {
|
||||
static void assertContains(String got, String want) {
|
||||
assertTrue(got + " did not contain \"" + want + "\"", got.contains(want));
|
||||
}
|
||||
|
||||
static <T> T[] remove(T[] array, T[] filtered) {
|
||||
List<T> c = Arrays.asList(filtered);
|
||||
int next = 0;
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (c.contains(array[i])) {
|
||||
continue;
|
||||
}
|
||||
array[next++] = array[i];
|
||||
}
|
||||
return Arrays.copyOf(array, next);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user