diff options
author | 2017-09-05 13:34:48 +0900 | |
---|---|---|
committer | 2017-09-14 13:29:56 +0900 | |
commit | 60c9f63b66926745603978e1bd6372b3a44561d1 (patch) | |
tree | d86e49aebd595a3965696bb42cbaa4a4ef19f0d9 | |
parent | f562ac34a51da55e4d15e34f0cd1cb597e7d926c (diff) |
Connectivity metrics: add WakeupStats events
This patch defines a new WakeupStats event in ipconnectivity.proto and
populates these events from the NFLOG wakeup events stored in
NetdEventListenerService.
There is one WakeupStats object per known interface on which ingress
packets arrive and may wake the system up.
Example from $ adb shell dumpsys connmetrics list:
UPDATEME
...
WakeupStats(wlan0, total: 58, root: 0, system: 3, apps: 38, non-apps: 0, unrouted: 17, 6111s)
WakeupEvent(13:36:31.686, iface wlan0, uid -1)
WakeupEvent(13:38:50.846, iface wlan0, uid -1)
WakeupEvent(13:39:16.676, iface wlan0, uid 10065)
WakeupEvent(13:40:32.144, iface wlan0, uid 1000)
WakeupEvent(13:40:35.827, iface wlan0, uid 1000)
WakeupEvent(13:40:47.913, iface wlan0, uid 10004)
WakeupEvent(13:40:52.622, iface wlan0, uid 10014)
WakeupEvent(13:41:06.036, iface wlan0, uid 10004)
...
Bug: 34901696
Bug: 62179647
Test: runtest frameworks-net
Change-Id: Ie2676b20bfb411a1902f4942643df0c20e268d99
7 files changed, 377 insertions, 39 deletions
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 01fb860e92d6..d997a80cda83 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 833457cd618b..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; @@ -26,9 +28,11 @@ 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; @@ -62,8 +66,10 @@ public class NetdEventListenerService extends INetdEventListener.Stub { @VisibleForTesting static final int WAKEUP_EVENT_BUFFER_LENGTH = 1024; - - private static final String WAKEUP_EVENT_IFACE_PREFIX = "iface:"; + // 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") @@ -71,6 +77,9 @@ public class NetdEventListenerService extends INetdEventListener.Stub { @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]; @@ -154,9 +163,12 @@ public class NetdEventListenerService extends INetdEventListener.Stub { // TODO: add ip protocol and port String iface = prefix.replaceFirst(WAKEUP_EVENT_IFACE_PREFIX, ""); - long timestampMs = timestampNs / 1000000; - // FIXME: Netd timestampNs is always 0. - timestampMs = System.currentTimeMillis(); + final long timestampMs; + if (timestampNs > 0) { + timestampMs = timestampNs / NANOS_PER_MS; + } else { + timestampMs = System.currentTimeMillis(); + } addWakupEvent(iface, timestampMs, uid); } @@ -170,6 +182,12 @@ public class NetdEventListenerService extends INetdEventListener.Stub { 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") @@ -192,6 +210,10 @@ public class NetdEventListenerService extends INetdEventListener.Stub { 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) { @@ -203,14 +225,22 @@ public class NetdEventListenerService extends INetdEventListener.Stub { } public synchronized void list(PrintWriter pw) { - listEvents(pw, mConnectEvents, (x) -> x); - listEvents(pw, mDnsEvents, (x) -> x); - listWakeupEvents(pw, getWakeupEvents()); + 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, @@ -222,15 +252,12 @@ public class NetdEventListenerService extends INetdEventListener.Stub { } private static <T> void listEvents( - PrintWriter pw, SparseArray<T> events, Function<T, Object> mapper) { + 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()); - } - } - - private static void listWakeupEvents(PrintWriter pw, WakeupEvent[] events) { - for (WakeupEvent wakeup : events) { - pw.println(wakeup); + 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 3a93b9432ca2..2b105e5c92ee 100644 --- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java +++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java @@ -38,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; @@ -48,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; @@ -91,9 +94,13 @@ public class NetdEventListenerServiceTest { } String[] events2 = listNetdEvent(); - assertEquals(uids.length, events2.length); + 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]; + String got = events2[i+1]; + assertContains(got, "WakeupEvent"); assertContains(got, "wlan0"); assertContains(got, "uid: " + uids[i]); } @@ -104,10 +111,14 @@ public class NetdEventListenerServiceTest { mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, ts); } - // Assert there are BUFFER_LENGTH events all with uid 20000 String[] events3 = listNetdEvent(); - assertEquals(BUFFER_LENGTH, events3.length); - for (String got : events3) { + 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); } @@ -117,11 +128,69 @@ public class NetdEventListenerServiceTest { 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); @@ -344,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")); |