Merge "DefaultNetworkEvent metrics: rehaul"

This commit is contained in:
Hugo Benichi
2017-11-06 07:09:49 +00:00
committed by Gerrit Code Review
10 changed files with 365 additions and 271 deletions

View File

@@ -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";

View File

@@ -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.

View File

@@ -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();
}

View File

@@ -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));
}
}

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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));
}

View File

@@ -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");

View File

@@ -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 <",

View File

@@ -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);
}
}