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
This commit is contained in:
@@ -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) {
|
||||
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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"));
|
||||
|
||||
Reference in New Issue
Block a user