From 611f62c6b99b3dfe9e95793ddef3edd13913a32b Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Tue, 5 Sep 2017 13:34:48 +0900 Subject: [PATCH] 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: ... 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 Merged-In: Ie2676b20bfb411a1902f4942643df0c20e268d99 (cherry pick from commit 60c9f63b66926745603978e1bd6372b3a44561d1) Change-Id: I3087f446fc998fc1ca895d975b80c4a1dd029bf3 --- .../IpConnectivityEventBuilderTest.java | 84 +++++++++++++++---- .../IpConnectivityMetricsTest.java | 46 ++++++++++ .../NetdEventListenerServiceTest.java | 84 +++++++++++++++++-- 3 files changed, 193 insertions(+), 21 deletions(-) diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java index eff04ab5ad..f72a1c638e 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 protoInput = + IpConnectivityEventBuilder.toProto(Arrays.asList(input)); + verifySerialization(want, protoInput.toArray(new IpConnectivityEvent[0])); + } + + static void verifySerialization(String want, IpConnectivityEvent... input) { try { - List 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 cc18b7f322..ede5988cdc 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 verifyEvents(int n, int timeoutMs) throws Exception { ArgumentCaptor 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 3a93b9432c..2b105e5c92 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,10 +128,68 @@ 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"));