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;
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 {
@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) {
try {
List<IpConnectivityEvent> proto =
List<IpConnectivityEvent> protoInput =
IpConnectivityEventBuilder.toProto(Arrays.asList(input));
byte[] got = IpConnectivityEventBuilder.serialize(0, proto);
verifySerialization(want, protoInput.toArray(new IpConnectivityEvent[0]));
}
static void verifySerialization(String want, IpConnectivityEvent... input) {
try {
byte[] got = IpConnectivityEventBuilder.serialize(0, Arrays.asList(input));
IpConnectivityLog log = IpConnectivityLog.parseFrom(got);
assertEquals(want, log.toString());
} catch (Exception e) {

View File

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

View File

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