diff options
author | 2017-09-14 18:02:14 +0000 | |
---|---|---|
committer | 2017-09-14 18:02:14 +0000 | |
commit | 6bc5c97e964fc7730049727d1d4847cadaf42bb6 (patch) | |
tree | deea4d368c68604c2d23e46bf8afbfcdbf3dd9bf | |
parent | a51e0d3b933701e95bdce05ef97c9357964f0793 (diff) | |
parent | 7d16886c7e9246f09bc1855bc65bb309a2879357 (diff) |
Merge changes Ie2676b20,Ie8db6f85 am: 61901ddedd am: 4188432a7b
am: 7d16886c7e
Change-Id: Ifd0ace409909d258db3738e58126bbf1c48af5dc
8 files changed, 510 insertions, 23 deletions
diff --git a/core/java/android/net/metrics/WakeupEvent.java b/core/java/android/net/metrics/WakeupEvent.java new file mode 100644 index 000000000000..cbf3fc8c81da --- /dev/null +++ b/core/java/android/net/metrics/WakeupEvent.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.metrics; + +/** + * An event logged when NFLOG notifies userspace of a wakeup packet for + * watched interfaces. + * {@hide} + */ +public class WakeupEvent { + public String iface; + public long timestampMs; + public int uid; + + @Override + public String toString() { + return String.format("WakeupEvent(%tT.%tL, %s, uid: %d)", + timestampMs, timestampMs, iface, uid); + } +} diff --git a/core/java/android/net/metrics/WakeupStats.java b/core/java/android/net/metrics/WakeupStats.java new file mode 100644 index 000000000000..d520b9745918 --- /dev/null +++ b/core/java/android/net/metrics/WakeupStats.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.metrics; + +import android.os.Process; +import android.os.SystemClock; + +/** + * An event logged per interface and that aggregates WakeupEvents for that interface. + * {@hide} + */ +public class WakeupStats { + + private static final int NO_UID = -1; + + public final long creationTimeMs = SystemClock.elapsedRealtime(); + public final String iface; + + public long totalWakeups = 0; + public long rootWakeups = 0; + public long systemWakeups = 0; + public long nonApplicationWakeups = 0; + public long applicationWakeups = 0; + public long unroutedWakeups = 0; + public long durationSec = 0; + + public WakeupStats(String iface) { + this.iface = iface; + } + + /** Update durationSec with current time. */ + public void updateDuration() { + durationSec = (SystemClock.elapsedRealtime() - creationTimeMs) / 1000; + } + + /** Update wakeup counters for the given WakeupEvent. */ + public void countEvent(WakeupEvent ev) { + totalWakeups++; + switch (ev.uid) { + case Process.ROOT_UID: + rootWakeups++; + break; + case Process.SYSTEM_UID: + systemWakeups++; + break; + case NO_UID: + unroutedWakeups++; + break; + default: + if (ev.uid >= Process.FIRST_APPLICATION_UID) { + applicationWakeups++; + } else { + nonApplicationWakeups++; + } + break; + } + } + + @Override + public String toString() { + updateDuration(); + return new StringBuilder() + .append("WakeupStats(").append(iface) + .append(", total: ").append(totalWakeups) + .append(", root: ").append(rootWakeups) + .append(", system: ").append(systemWakeups) + .append(", apps: ").append(applicationWakeups) + .append(", non-apps: ").append(nonApplicationWakeups) + .append(", unrouted: ").append(unroutedWakeups) + .append(", ").append(durationSec).append("s)") + .toString(); + } +} diff --git a/proto/src/ipconnectivity.proto b/proto/src/ipconnectivity.proto index 885896f24283..777468a9e0d2 100644 --- a/proto/src/ipconnectivity.proto +++ b/proto/src/ipconnectivity.proto @@ -473,6 +473,38 @@ message NetworkStats { repeated Pair validation_states = 8; } +// Represents statistics from NFLOG wakeup events due to ingress packets. +// Since oc-mr1. +// Next tag: 8. +message WakeupStats { + // The time duration in seconds covered by these stats, for deriving + // exact wakeup rates. + optional int64 duration_sec = 1; + + // The total number of ingress packets waking up the device. + optional int64 total_wakeups = 2; + + // The total number of wakeup packets routed to a socket belonging to + // the root uid (uid 0). + optional int64 root_wakeups = 3; + + // The total number of wakeup packets routed to a socket belonging to + // the system server (uid 1000). + optional int64 system_wakeups = 4; + + // The total number of wakeup packets routed to a socket belonging to + // an application (uid > 9999). + optional int64 application_wakeups = 5; + + // The total number of wakeup packets routed to a socket belonging to another + // uid than the root uid, system uid, or an application uid (any uid in + // between [1001, 9999]. See android.os.Process for possible uids. + optional int64 non_application_wakeups = 6; + + // The total number of wakeup packets with no associated sockets. + optional int64 unrouted_wakeups = 7; +} + // Represents one of the IP connectivity event defined in this file. // Next tag: 20 message IpConnectivityEvent { @@ -547,6 +579,9 @@ message IpConnectivityEvent { // Network statistics. NetworkStats network_stats = 19; + + // Ingress packet wakeup statistics. + WakeupStats wakeup_stats = 20; }; }; diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java index ee382199438b..22330e66e126 100644 --- a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java +++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java @@ -38,6 +38,7 @@ import android.net.metrics.IpReachabilityEvent; import android.net.metrics.NetworkEvent; import android.net.metrics.RaEvent; import android.net.metrics.ValidationProbeEvent; +import android.net.metrics.WakeupStats; import android.os.Parcelable; import android.util.SparseArray; import android.util.SparseIntArray; @@ -115,6 +116,22 @@ final public class IpConnectivityEventBuilder { return out; } + public static IpConnectivityEvent toProto(WakeupStats in) { + IpConnectivityLogClass.WakeupStats wakeupStats = + new IpConnectivityLogClass.WakeupStats(); + in.updateDuration(); + wakeupStats.durationSec = in.durationSec; + wakeupStats.totalWakeups = in.totalWakeups; + wakeupStats.rootWakeups = in.rootWakeups; + wakeupStats.systemWakeups = in.systemWakeups; + wakeupStats.nonApplicationWakeups = in.nonApplicationWakeups; + wakeupStats.applicationWakeups = in.applicationWakeups; + wakeupStats.unroutedWakeups = in.unroutedWakeups; + final IpConnectivityEvent out = buildEvent(0, 0, in.iface); + out.setWakeupStats(wakeupStats); + return out; + } + private static IpConnectivityEvent buildEvent(int netId, long transports, String ifname) { final IpConnectivityEvent ev = new IpConnectivityEvent(); ev.networkId = netId; diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java index 4094083f138c..6f7ace2f6527 100644 --- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java +++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java @@ -16,6 +16,8 @@ package com.android.server.connectivity; +import static android.util.TimeUtils.NANOS_PER_MS; + import android.content.Context; import android.net.ConnectivityManager; import android.net.INetdEventCallback; @@ -25,9 +27,12 @@ import android.net.metrics.ConnectStats; import android.net.metrics.DnsEvent; import android.net.metrics.INetdEventListener; import android.net.metrics.IpConnectivityLog; +import android.net.metrics.WakeupEvent; +import android.net.metrics.WakeupStats; import android.os.RemoteException; import android.text.format.DateUtils; import android.util.Log; +import android.util.ArrayMap; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -59,12 +64,28 @@ public class NetdEventListenerService extends INetdEventListener.Stub { private static final int CONNECT_LATENCY_FILL_RATE = 15 * (int) DateUtils.SECOND_IN_MILLIS; private static final int CONNECT_LATENCY_MAXIMUM_RECORDS = 20000; + @VisibleForTesting + static final int WAKEUP_EVENT_BUFFER_LENGTH = 1024; + // TODO: dedup this String constant with the one used in + // ConnectivityService#wakeupModifyInterface(). + @VisibleForTesting + static final String WAKEUP_EVENT_IFACE_PREFIX = "iface:"; + // Sparse arrays of DNS and connect events, grouped by net id. @GuardedBy("this") private final SparseArray<DnsEvent> mDnsEvents = new SparseArray<>(); @GuardedBy("this") private final SparseArray<ConnectStats> mConnectEvents = new SparseArray<>(); + // Array of aggregated wakeup event stats, grouped by interface name. + @GuardedBy("this") + private final ArrayMap<String, WakeupStats> mWakeupStats = new ArrayMap<>(); + // Ring buffer array for storing packet wake up events sent by Netd. + @GuardedBy("this") + private final WakeupEvent[] mWakeupEvents = new WakeupEvent[WAKEUP_EVENT_BUFFER_LENGTH]; + @GuardedBy("this") + private long mWakeupEventCursor = 0; + private final ConnectivityManager mCm; @GuardedBy("this") @@ -137,11 +158,62 @@ public class NetdEventListenerService extends INetdEventListener.Stub { @Override public synchronized void onWakeupEvent(String prefix, int uid, int gid, long timestampNs) { + maybeVerboseLog("onWakeupEvent(%s, %d, %d, %sns)", prefix, uid, gid, timestampNs); + + // TODO: add ip protocol and port + + String iface = prefix.replaceFirst(WAKEUP_EVENT_IFACE_PREFIX, ""); + final long timestampMs; + if (timestampNs > 0) { + timestampMs = timestampNs / NANOS_PER_MS; + } else { + timestampMs = System.currentTimeMillis(); + } + + addWakupEvent(iface, timestampMs, uid); + } + + @GuardedBy("this") + private void addWakupEvent(String iface, long timestampMs, int uid) { + int index = wakeupEventIndex(mWakeupEventCursor); + mWakeupEventCursor++; + WakeupEvent event = new WakeupEvent(); + event.iface = iface; + event.timestampMs = timestampMs; + event.uid = uid; + mWakeupEvents[index] = event; + WakeupStats stats = mWakeupStats.get(iface); + if (stats == null) { + stats = new WakeupStats(iface); + mWakeupStats.put(iface, stats); + } + stats.countEvent(event); + } + + @GuardedBy("this") + private WakeupEvent[] getWakeupEvents() { + int length = (int) Math.min(mWakeupEventCursor, (long) mWakeupEvents.length); + WakeupEvent[] out = new WakeupEvent[length]; + // Reverse iteration from youngest event to oldest event. + long inCursor = mWakeupEventCursor - 1; + int outIdx = out.length - 1; + while (outIdx >= 0) { + out[outIdx--] = mWakeupEvents[wakeupEventIndex(inCursor--)]; + } + return out; + } + + private static int wakeupEventIndex(long cursor) { + return (int) Math.abs(cursor % WAKEUP_EVENT_BUFFER_LENGTH); } public synchronized void flushStatistics(List<IpConnectivityEvent> events) { flushProtos(events, mConnectEvents, IpConnectivityEventBuilder::toProto); flushProtos(events, mDnsEvents, IpConnectivityEventBuilder::toProto); + for (int i = 0; i < mWakeupStats.size(); i++) { + events.add(IpConnectivityEventBuilder.toProto(mWakeupStats.valueAt(i))); + } + mWakeupStats.clear(); } public synchronized void dump(PrintWriter writer) { @@ -153,13 +225,22 @@ public class NetdEventListenerService extends INetdEventListener.Stub { } public synchronized void list(PrintWriter pw) { - listEvents(pw, mConnectEvents, (x) -> x); - listEvents(pw, mDnsEvents, (x) -> x); + listEvents(pw, mConnectEvents, (x) -> x, "\n"); + listEvents(pw, mDnsEvents, (x) -> x, "\n"); + for (int i = 0; i < mWakeupStats.size(); i++) { + pw.println(mWakeupStats.valueAt(i)); + } + for (WakeupEvent wakeup : getWakeupEvents()) { + pw.println(wakeup); + } } public synchronized void listAsProtos(PrintWriter pw) { - listEvents(pw, mConnectEvents, IpConnectivityEventBuilder::toProto); - listEvents(pw, mDnsEvents, IpConnectivityEventBuilder::toProto); + listEvents(pw, mConnectEvents, IpConnectivityEventBuilder::toProto, ""); + listEvents(pw, mDnsEvents, IpConnectivityEventBuilder::toProto, ""); + for (int i = 0; i < mWakeupStats.size(); i++) { + pw.print(IpConnectivityEventBuilder.toProto(mWakeupStats.valueAt(i))); + } } private static <T> void flushProtos(List<IpConnectivityEvent> out, SparseArray<T> in, @@ -170,10 +251,13 @@ public class NetdEventListenerService extends INetdEventListener.Stub { in.clear(); } - public static <T> void listEvents( - PrintWriter pw, SparseArray<T> events, Function<T, Object> mapper) { + private static <T> void listEvents( + PrintWriter pw, SparseArray<T> events, Function<T, Object> mapper, String separator) { + // Proto derived Classes have toString method that adds a \n at the end. + // Let the caller control that by passing in the line separator explicitly. for (int i = 0; i < events.size(); i++) { - pw.println(mapper.apply(events.valueAt(i)).toString()); + pw.print(mapper.apply(events.valueAt(i))); + pw.print(separator); } } diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java index eff04ab5addd..f72a1c638ed5 100644 --- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java +++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java @@ -16,6 +16,8 @@ package com.android.server.connectivity; +import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO; +import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME; import static com.android.server.connectivity.MetricsTestUtil.aBool; import static com.android.server.connectivity.MetricsTestUtil.aByteArray; import static com.android.server.connectivity.MetricsTestUtil.aLong; @@ -31,29 +33,41 @@ import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClas import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.ETHERNET; import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.MULTIPLE; import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.WIFI; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import android.net.ConnectivityMetricsEvent; import android.net.metrics.ApfProgramEvent; import android.net.metrics.ApfStats; +import android.net.metrics.ConnectStats; import android.net.metrics.DefaultNetworkEvent; import android.net.metrics.DhcpClientEvent; import android.net.metrics.DhcpErrorEvent; import android.net.metrics.DnsEvent; +import android.net.metrics.DnsEvent; import android.net.metrics.IpManagerEvent; import android.net.metrics.IpReachabilityEvent; import android.net.metrics.NetworkEvent; import android.net.metrics.RaEvent; import android.net.metrics.ValidationProbeEvent; +import android.net.metrics.WakeupStats; +import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.SmallTest; + import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent; + import java.util.Arrays; import java.util.List; -import junit.framework.TestCase; + +import org.junit.runner.RunWith; +import org.junit.Test; // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto. -public class IpConnectivityEventBuilderTest extends TestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class IpConnectivityEventBuilderTest { - @SmallTest + @Test public void testLinkLayerInferrence() { ConnectivityMetricsEvent ev = describeIpEvent( aType(IpReachabilityEvent.class), @@ -182,7 +196,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { verifySerialization(want, ev); } - @SmallTest + @Test public void testDefaultNetworkEventSerialization() { ConnectivityMetricsEvent ev = describeIpEvent( aType(DefaultNetworkEvent.class), @@ -223,7 +237,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { verifySerialization(want, ev); } - @SmallTest + @Test public void testDhcpClientEventSerialization() { ConnectivityMetricsEvent ev = describeIpEvent( aType(DhcpClientEvent.class), @@ -249,7 +263,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { verifySerialization(want, ev); } - @SmallTest + @Test public void testDhcpErrorEventSerialization() { ConnectivityMetricsEvent ev = describeIpEvent( aType(DhcpErrorEvent.class), @@ -274,7 +288,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { verifySerialization(want, ev); } - @SmallTest + @Test public void testIpManagerEventSerialization() { ConnectivityMetricsEvent ev = describeIpEvent( aType(IpManagerEvent.class), @@ -300,7 +314,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { verifySerialization(want, ev); } - @SmallTest + @Test public void testIpReachabilityEventSerialization() { ConnectivityMetricsEvent ev = describeIpEvent( aType(IpReachabilityEvent.class), @@ -324,7 +338,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { verifySerialization(want, ev); } - @SmallTest + @Test public void testNetworkEventSerialization() { ConnectivityMetricsEvent ev = describeIpEvent( aType(NetworkEvent.class), @@ -353,7 +367,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { verifySerialization(want, ev); } - @SmallTest + @Test public void testValidationProbeEventSerialization() { ConnectivityMetricsEvent ev = describeIpEvent( aType(ValidationProbeEvent.class), @@ -380,7 +394,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { verifySerialization(want, ev); } - @SmallTest + @Test public void testApfProgramEventSerialization() { ConnectivityMetricsEvent ev = describeIpEvent( aType(ApfProgramEvent.class), @@ -414,7 +428,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { verifySerialization(want, ev); } - @SmallTest + @Test public void testApfStatsSerialization() { ConnectivityMetricsEvent ev = describeIpEvent( aType(ApfStats.class), @@ -457,7 +471,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { verifySerialization(want, ev); } - @SmallTest + @Test public void testRaEventSerialization() { ConnectivityMetricsEvent ev = describeIpEvent( aType(RaEvent.class), @@ -490,11 +504,49 @@ public class IpConnectivityEventBuilderTest extends TestCase { verifySerialization(want, ev); } + @Test + public void testWakeupStatsSerialization() { + WakeupStats stats = new WakeupStats("wlan0"); + stats.totalWakeups = 14; + stats.applicationWakeups = 5; + stats.nonApplicationWakeups = 1; + stats.rootWakeups = 2; + stats.systemWakeups = 3; + stats.unroutedWakeups = 3; + + IpConnectivityEvent got = IpConnectivityEventBuilder.toProto(stats); + String want = String.join("\n", + "dropped_events: 0", + "events <", + " if_name: \"\"", + " link_layer: 4", + " network_id: 0", + " time_ms: 0", + " transports: 0", + " wakeup_stats <", + " application_wakeups: 5", + " duration_sec: 0", + " non_application_wakeups: 1", + " root_wakeups: 2", + " system_wakeups: 3", + " total_wakeups: 14", + " unrouted_wakeups: 3", + " >", + ">", + "version: 2\n"); + + verifySerialization(want, got); + } + static void verifySerialization(String want, ConnectivityMetricsEvent... input) { + List<IpConnectivityEvent> protoInput = + IpConnectivityEventBuilder.toProto(Arrays.asList(input)); + verifySerialization(want, protoInput.toArray(new IpConnectivityEvent[0])); + } + + static void verifySerialization(String want, IpConnectivityEvent... input) { try { - List<IpConnectivityEvent> proto = - IpConnectivityEventBuilder.toProto(Arrays.asList(input)); - byte[] got = IpConnectivityEventBuilder.serialize(0, proto); + byte[] got = IpConnectivityEventBuilder.serialize(0, Arrays.asList(input)); IpConnectivityLog log = IpConnectivityLog.parseFrom(got); assertEquals(want, log.toString()); } catch (Exception e) { diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java index cc18b7f32208..ede5988cdc6d 100644 --- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java +++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java @@ -224,6 +224,15 @@ public class IpConnectivityMetricsTest { dnsEvent(101, EVENT_GETADDRINFO, 0, 56); dnsEvent(101, EVENT_GETHOSTBYNAME, 0, 34); + // iface, uid + wakeupEvent("wlan0", 1000); + wakeupEvent("rmnet0", 10123); + wakeupEvent("wlan0", 1000); + wakeupEvent("rmnet0", 10008); + wakeupEvent("wlan0", -1); + wakeupEvent("wlan0", 10008); + wakeupEvent("rmnet0", 1000); + String want = String.join("\n", "dropped_events: 0", "events <", @@ -405,6 +414,38 @@ public class IpConnectivityMetricsTest { " return_codes: 0", " >", ">", + "events <", + " if_name: \"\"", + " link_layer: 2", + " network_id: 0", + " time_ms: 0", + " transports: 0", + " wakeup_stats <", + " application_wakeups: 2", + " duration_sec: 0", + " non_application_wakeups: 0", + " root_wakeups: 0", + " system_wakeups: 1", + " total_wakeups: 3", + " unrouted_wakeups: 0", + " >", + ">", + "events <", + " if_name: \"\"", + " link_layer: 4", + " network_id: 0", + " time_ms: 0", + " transports: 0", + " wakeup_stats <", + " application_wakeups: 1", + " duration_sec: 0", + " non_application_wakeups: 0", + " root_wakeups: 0", + " system_wakeups: 2", + " total_wakeups: 4", + " unrouted_wakeups: 1", + " >", + ">", "version: 2\n"); verifySerialization(want, getdump("flush")); @@ -425,6 +466,11 @@ public class IpConnectivityMetricsTest { mNetdListener.onDnsEvent(netId, type, result, latency, "", null, 0, 0); } + void wakeupEvent(String iface, int uid) throws Exception { + String prefix = NetdEventListenerService.WAKEUP_EVENT_IFACE_PREFIX + iface; + mNetdListener.onWakeupEvent(prefix, uid, uid, 0); + } + List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception { ArgumentCaptor<ConnectivityMetricsEvent> captor = ArgumentCaptor.forClass(ConnectivityMetricsEvent.class); diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java index 46f395eae214..2b105e5c92ee 100644 --- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java +++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java @@ -19,6 +19,7 @@ package com.android.server.connectivity; import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO; import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; @@ -37,9 +38,11 @@ import android.support.test.runner.AndroidJUnit4; import android.system.OsConstants; import android.test.suitebuilder.annotation.SmallTest; import android.util.Base64; + import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.DNSLookupBatch; import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent; import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog; + import java.io.FileOutputStream; import java.io.PrintWriter; import java.io.StringWriter; @@ -47,6 +50,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -75,6 +79,118 @@ public class NetdEventListenerServiceTest { } @Test + public void testWakeupEventLogging() throws Exception { + final int BUFFER_LENGTH = NetdEventListenerService.WAKEUP_EVENT_BUFFER_LENGTH; + + // Assert no events + String[] events1 = listNetdEvent(); + assertEquals(new String[]{""}, events1); + + long now = System.currentTimeMillis(); + String prefix = "iface:wlan0"; + int[] uids = { 10001, 10002, 10004, 1000, 10052, 10023, 10002, 10123, 10004 }; + for (int uid : uids) { + mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, now); + } + + String[] events2 = listNetdEvent(); + int expectedLength2 = uids.length + 1; // +1 for the WakeupStats line + assertEquals(expectedLength2, events2.length); + assertContains(events2[0], "WakeupStats"); + assertContains(events2[0], "wlan0"); + for (int i = 0; i < uids.length; i++) { + String got = events2[i+1]; + assertContains(got, "WakeupEvent"); + assertContains(got, "wlan0"); + assertContains(got, "uid: " + uids[i]); + } + + int uid = 20000; + for (int i = 0; i < BUFFER_LENGTH * 2; i++) { + long ts = now + 10; + mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, ts); + } + + String[] events3 = listNetdEvent(); + int expectedLength3 = BUFFER_LENGTH + 1; // +1 for the WakeupStats line + assertEquals(expectedLength3, events3.length); + assertContains(events2[0], "WakeupStats"); + assertContains(events2[0], "wlan0"); + for (int i = 1; i < expectedLength3; i++) { + String got = events3[i]; + assertContains(got, "WakeupEvent"); + assertContains(got, "wlan0"); + assertContains(got, "uid: " + uid); + } + + uid = 45678; + mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, now); + + String[] events4 = listNetdEvent(); + String lastEvent = events4[events4.length - 1]; + assertContains(lastEvent, "WakeupEvent"); + assertContains(lastEvent, "wlan0"); + assertContains(lastEvent, "uid: " + uid); + } + + @Test + public void testWakeupStatsLogging() throws Exception { + wakeupEvent("wlan0", 1000); + wakeupEvent("rmnet0", 10123); + wakeupEvent("wlan0", 1000); + wakeupEvent("rmnet0", 10008); + wakeupEvent("wlan0", -1); + wakeupEvent("wlan0", 10008); + wakeupEvent("rmnet0", 1000); + wakeupEvent("wlan0", 10004); + wakeupEvent("wlan0", 1000); + wakeupEvent("wlan0", 0); + wakeupEvent("wlan0", -1); + wakeupEvent("rmnet0", 10052); + wakeupEvent("wlan0", 0); + wakeupEvent("rmnet0", 1000); + wakeupEvent("wlan0", 1010); + + String got = flushStatistics(); + String want = String.join("\n", + "dropped_events: 0", + "events <", + " if_name: \"\"", + " link_layer: 2", + " network_id: 0", + " time_ms: 0", + " transports: 0", + " wakeup_stats <", + " application_wakeups: 3", + " duration_sec: 0", + " non_application_wakeups: 0", + " root_wakeups: 0", + " system_wakeups: 2", + " total_wakeups: 5", + " unrouted_wakeups: 0", + " >", + ">", + "events <", + " if_name: \"\"", + " link_layer: 4", + " network_id: 0", + " time_ms: 0", + " transports: 0", + " wakeup_stats <", + " application_wakeups: 2", + " duration_sec: 0", + " non_application_wakeups: 1", + " root_wakeups: 2", + " system_wakeups: 3", + " total_wakeups: 10", + " unrouted_wakeups: 2", + " >", + ">", + "version: 2\n"); + assertEquals(want, got); + } + + @Test public void testDnsLogging() throws Exception { asyncDump(100); @@ -297,6 +413,11 @@ public class NetdEventListenerServiceTest { mNetdEventListenerService.onDnsEvent(netId, type, result, latency, "", null, 0, 0); } + void wakeupEvent(String iface, int uid) throws Exception { + String prefix = NetdEventListenerService.WAKEUP_EVENT_IFACE_PREFIX + iface; + mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, 0); + } + void asyncDump(long durationMs) throws Exception { final long stop = System.currentTimeMillis() + durationMs; final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null")); @@ -329,4 +450,15 @@ public class NetdEventListenerServiceTest { } return log.toString(); } + + String[] listNetdEvent() throws Exception { + StringWriter buffer = new StringWriter(); + PrintWriter writer = new PrintWriter(buffer); + mNetdEventListenerService.list(writer); + return buffer.toString().split("\\n"); + } + + static void assertContains(String got, String want) { + assertTrue(got + " did not contain \"" + want + "\"", got.contains(want)); + } } |