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
This commit is contained in:
Hugo Benichi
2017-09-05 13:34:48 +09:00
parent 8b3f87160b
commit 611f62c6b9
3 changed files with 193 additions and 21 deletions

View File

@@ -16,6 +16,8 @@
package com.android.server.connectivity; 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.aBool;
import static com.android.server.connectivity.MetricsTestUtil.aByteArray; import static com.android.server.connectivity.MetricsTestUtil.aByteArray;
import static com.android.server.connectivity.MetricsTestUtil.aLong; 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.ETHERNET;
import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.MULTIPLE; import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.MULTIPLE;
import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.WIFI; 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.ConnectivityMetricsEvent;
import android.net.metrics.ApfProgramEvent; import android.net.metrics.ApfProgramEvent;
import android.net.metrics.ApfStats; import android.net.metrics.ApfStats;
import android.net.metrics.ConnectStats;
import android.net.metrics.DefaultNetworkEvent; import android.net.metrics.DefaultNetworkEvent;
import android.net.metrics.DhcpClientEvent; import android.net.metrics.DhcpClientEvent;
import android.net.metrics.DhcpErrorEvent; import android.net.metrics.DhcpErrorEvent;
import android.net.metrics.DnsEvent; import android.net.metrics.DnsEvent;
import android.net.metrics.DnsEvent;
import android.net.metrics.IpManagerEvent; import android.net.metrics.IpManagerEvent;
import android.net.metrics.IpReachabilityEvent; import android.net.metrics.IpReachabilityEvent;
import android.net.metrics.NetworkEvent; import android.net.metrics.NetworkEvent;
import android.net.metrics.RaEvent; import android.net.metrics.RaEvent;
import android.net.metrics.ValidationProbeEvent; import android.net.metrics.ValidationProbeEvent;
import android.net.metrics.WakeupStats;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.SmallTest;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent; import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; 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. // 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() { public void testLinkLayerInferrence() {
ConnectivityMetricsEvent ev = describeIpEvent( ConnectivityMetricsEvent ev = describeIpEvent(
aType(IpReachabilityEvent.class), aType(IpReachabilityEvent.class),
@@ -182,7 +196,7 @@ public class IpConnectivityEventBuilderTest extends TestCase {
verifySerialization(want, ev); verifySerialization(want, ev);
} }
@SmallTest @Test
public void testDefaultNetworkEventSerialization() { public void testDefaultNetworkEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent( ConnectivityMetricsEvent ev = describeIpEvent(
aType(DefaultNetworkEvent.class), aType(DefaultNetworkEvent.class),
@@ -223,7 +237,7 @@ public class IpConnectivityEventBuilderTest extends TestCase {
verifySerialization(want, ev); verifySerialization(want, ev);
} }
@SmallTest @Test
public void testDhcpClientEventSerialization() { public void testDhcpClientEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent( ConnectivityMetricsEvent ev = describeIpEvent(
aType(DhcpClientEvent.class), aType(DhcpClientEvent.class),
@@ -249,7 +263,7 @@ public class IpConnectivityEventBuilderTest extends TestCase {
verifySerialization(want, ev); verifySerialization(want, ev);
} }
@SmallTest @Test
public void testDhcpErrorEventSerialization() { public void testDhcpErrorEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent( ConnectivityMetricsEvent ev = describeIpEvent(
aType(DhcpErrorEvent.class), aType(DhcpErrorEvent.class),
@@ -274,7 +288,7 @@ public class IpConnectivityEventBuilderTest extends TestCase {
verifySerialization(want, ev); verifySerialization(want, ev);
} }
@SmallTest @Test
public void testIpManagerEventSerialization() { public void testIpManagerEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent( ConnectivityMetricsEvent ev = describeIpEvent(
aType(IpManagerEvent.class), aType(IpManagerEvent.class),
@@ -300,7 +314,7 @@ public class IpConnectivityEventBuilderTest extends TestCase {
verifySerialization(want, ev); verifySerialization(want, ev);
} }
@SmallTest @Test
public void testIpReachabilityEventSerialization() { public void testIpReachabilityEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent( ConnectivityMetricsEvent ev = describeIpEvent(
aType(IpReachabilityEvent.class), aType(IpReachabilityEvent.class),
@@ -324,7 +338,7 @@ public class IpConnectivityEventBuilderTest extends TestCase {
verifySerialization(want, ev); verifySerialization(want, ev);
} }
@SmallTest @Test
public void testNetworkEventSerialization() { public void testNetworkEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent( ConnectivityMetricsEvent ev = describeIpEvent(
aType(NetworkEvent.class), aType(NetworkEvent.class),
@@ -353,7 +367,7 @@ public class IpConnectivityEventBuilderTest extends TestCase {
verifySerialization(want, ev); verifySerialization(want, ev);
} }
@SmallTest @Test
public void testValidationProbeEventSerialization() { public void testValidationProbeEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent( ConnectivityMetricsEvent ev = describeIpEvent(
aType(ValidationProbeEvent.class), aType(ValidationProbeEvent.class),
@@ -380,7 +394,7 @@ public class IpConnectivityEventBuilderTest extends TestCase {
verifySerialization(want, ev); verifySerialization(want, ev);
} }
@SmallTest @Test
public void testApfProgramEventSerialization() { public void testApfProgramEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent( ConnectivityMetricsEvent ev = describeIpEvent(
aType(ApfProgramEvent.class), aType(ApfProgramEvent.class),
@@ -414,7 +428,7 @@ public class IpConnectivityEventBuilderTest extends TestCase {
verifySerialization(want, ev); verifySerialization(want, ev);
} }
@SmallTest @Test
public void testApfStatsSerialization() { public void testApfStatsSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent( ConnectivityMetricsEvent ev = describeIpEvent(
aType(ApfStats.class), aType(ApfStats.class),
@@ -457,7 +471,7 @@ public class IpConnectivityEventBuilderTest extends TestCase {
verifySerialization(want, ev); verifySerialization(want, ev);
} }
@SmallTest @Test
public void testRaEventSerialization() { public void testRaEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent( ConnectivityMetricsEvent ev = describeIpEvent(
aType(RaEvent.class), aType(RaEvent.class),
@@ -490,11 +504,49 @@ public class IpConnectivityEventBuilderTest extends TestCase {
verifySerialization(want, ev); 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) { 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 { try {
List<IpConnectivityEvent> proto = byte[] got = IpConnectivityEventBuilder.serialize(0, Arrays.asList(input));
IpConnectivityEventBuilder.toProto(Arrays.asList(input));
byte[] got = IpConnectivityEventBuilder.serialize(0, proto);
IpConnectivityLog log = IpConnectivityLog.parseFrom(got); IpConnectivityLog log = IpConnectivityLog.parseFrom(got);
assertEquals(want, log.toString()); assertEquals(want, log.toString());
} catch (Exception e) { } catch (Exception e) {

View File

@@ -224,6 +224,15 @@ public class IpConnectivityMetricsTest {
dnsEvent(101, EVENT_GETADDRINFO, 0, 56); dnsEvent(101, EVENT_GETADDRINFO, 0, 56);
dnsEvent(101, EVENT_GETHOSTBYNAME, 0, 34); 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", String want = String.join("\n",
"dropped_events: 0", "dropped_events: 0",
"events <", "events <",
@@ -405,6 +414,38 @@ public class IpConnectivityMetricsTest {
" return_codes: 0", " 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"); "version: 2\n");
verifySerialization(want, getdump("flush")); verifySerialization(want, getdump("flush"));
@@ -425,6 +466,11 @@ public class IpConnectivityMetricsTest {
mNetdListener.onDnsEvent(netId, type, result, latency, "", null, 0, 0); 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 { List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
ArgumentCaptor<ConnectivityMetricsEvent> captor = ArgumentCaptor<ConnectivityMetricsEvent> captor =
ArgumentCaptor.forClass(ConnectivityMetricsEvent.class); ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);

View File

@@ -38,9 +38,11 @@ import android.support.test.runner.AndroidJUnit4;
import android.system.OsConstants; import android.system.OsConstants;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.SmallTest;
import android.util.Base64; import android.util.Base64;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.DNSLookupBatch; 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.IpConnectivityEvent;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog; import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
@@ -48,6 +50,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -91,9 +94,13 @@ public class NetdEventListenerServiceTest {
} }
String[] events2 = listNetdEvent(); 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++) { 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, "wlan0");
assertContains(got, "uid: " + uids[i]); assertContains(got, "uid: " + uids[i]);
} }
@@ -104,10 +111,14 @@ public class NetdEventListenerServiceTest {
mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, ts); mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, ts);
} }
// Assert there are BUFFER_LENGTH events all with uid 20000
String[] events3 = listNetdEvent(); String[] events3 = listNetdEvent();
assertEquals(BUFFER_LENGTH, events3.length); int expectedLength3 = BUFFER_LENGTH + 1; // +1 for the WakeupStats line
for (String got : events3) { 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, "wlan0");
assertContains(got, "uid: " + uid); assertContains(got, "uid: " + uid);
} }
@@ -117,10 +128,68 @@ public class NetdEventListenerServiceTest {
String[] events4 = listNetdEvent(); String[] events4 = listNetdEvent();
String lastEvent = events4[events4.length - 1]; String lastEvent = events4[events4.length - 1];
assertContains(lastEvent, "WakeupEvent");
assertContains(lastEvent, "wlan0"); assertContains(lastEvent, "wlan0");
assertContains(lastEvent, "uid: " + uid); 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 @Test
public void testDnsLogging() throws Exception { public void testDnsLogging() throws Exception {
asyncDump(100); asyncDump(100);
@@ -344,6 +413,11 @@ public class NetdEventListenerServiceTest {
mNetdEventListenerService.onDnsEvent(netId, type, result, latency, "", null, 0, 0); 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 { void asyncDump(long durationMs) throws Exception {
final long stop = System.currentTimeMillis() + durationMs; final long stop = System.currentTimeMillis() + durationMs;
final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null")); final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));