blob: e4117b848a35ea83dc2c96c004cde9a3e226224a [file] [log] [blame]
Hugo Benichi5e055182016-06-01 08:50:38 +09001/*
2 * Copyright (C) 2016, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.connectivity;
18
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090019import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO;
20import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME;
Brett Chabot1ae2aa62019-03-04 14:14:56 -080021
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090022import static org.junit.Assert.assertEquals;
Hugo Benichif562ac32017-09-04 13:24:43 +090023import static org.junit.Assert.assertTrue;
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090024import static org.junit.Assert.fail;
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090025import static org.mockito.Mockito.mock;
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090026import static org.mockito.Mockito.when;
Hugo Benichi5e055182016-06-01 08:50:38 +090027
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090028import android.content.Context;
29import android.net.ConnectivityManager;
30import android.net.Network;
31import android.net.NetworkCapabilities;
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090032import android.system.OsConstants;
33import android.test.suitebuilder.annotation.SmallTest;
34import android.util.Base64;
Hugo Benichi60c9f632017-09-05 13:34:48 +090035
Brett Chabot1ae2aa62019-03-04 14:14:56 -080036import androidx.test.runner.AndroidJUnit4;
37
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090038import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
39import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
Hugo Benichi60c9f632017-09-05 13:34:48 +090040
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090041import org.junit.Before;
42import org.junit.Test;
43import org.junit.runner.RunWith;
Hugo Benichi5e055182016-06-01 08:50:38 +090044
Brett Chabot1ae2aa62019-03-04 14:14:56 -080045import java.io.FileOutputStream;
46import java.io.PrintWriter;
47import java.io.StringWriter;
48import java.util.Arrays;
49import java.util.Comparator;
50import java.util.List;
51
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090052@RunWith(AndroidJUnit4.class)
53@SmallTest
54public class NetdEventListenerServiceTest {
Hugo Benichi0d4a3982016-11-25 11:24:22 +090055 private static final String EXAMPLE_IPV4 = "192.0.2.1";
56 private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1";
57
Hugo Benichid921bce2017-10-12 21:33:40 +090058 private static final byte[] MAC_ADDR =
59 {(byte)0x84, (byte)0xc9, (byte)0xb2, (byte)0x6a, (byte)0xed, (byte)0x4b};
60
61 NetdEventListenerService mService;
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090062 ConnectivityManager mCm;
Hugo Benichi5e055182016-06-01 08:50:38 +090063
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090064 @Before
Hugo Benichi5e055182016-06-01 08:50:38 +090065 public void setUp() {
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090066 NetworkCapabilities ncWifi = new NetworkCapabilities();
67 NetworkCapabilities ncCell = new NetworkCapabilities();
68 ncWifi.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
69 ncCell.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
Hugo Benichi5e055182016-06-01 08:50:38 +090070
Hugo Benichi5eb90532017-03-23 18:38:22 +090071 mCm = mock(ConnectivityManager.class);
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090072 when(mCm.getNetworkCapabilities(new Network(100))).thenReturn(ncWifi);
73 when(mCm.getNetworkCapabilities(new Network(101))).thenReturn(ncCell);
Hugo Benichi5e055182016-06-01 08:50:38 +090074
Hugo Benichid921bce2017-10-12 21:33:40 +090075 mService = new NetdEventListenerService(mCm);
Hugo Benichi5eb90532017-03-23 18:38:22 +090076 }
77
78 @Test
Hugo Benichif562ac32017-09-04 13:24:43 +090079 public void testWakeupEventLogging() throws Exception {
80 final int BUFFER_LENGTH = NetdEventListenerService.WAKEUP_EVENT_BUFFER_LENGTH;
Hugo Benichid921bce2017-10-12 21:33:40 +090081 final long now = System.currentTimeMillis();
82 final String iface = "wlan0";
83 final byte[] mac = MAC_ADDR;
84 final String srcIp = "192.168.2.1";
85 final String dstIp = "192.168.2.23";
86 final String srcIp6 = "2001:db8:4:fd00:a585:13d1:6a23:4fb4";
87 final String dstIp6 = "2001:db8:4006:807::200a";
88 final int sport = 2356;
89 final int dport = 13489;
90
91 final int v4 = 0x800;
92 final int v6 = 0x86dd;
93 final int tcp = 6;
94 final int udp = 17;
95 final int icmp6 = 58;
Hugo Benichif562ac32017-09-04 13:24:43 +090096
Hugo Benichi380a0632017-10-20 09:25:29 +090097 // Baseline without any event
98 String[] baseline = listNetdEvent();
Hugo Benichif562ac32017-09-04 13:24:43 +090099
Hugo Benichid921bce2017-10-12 21:33:40 +0900100 int[] uids = {10001, 10002, 10004, 1000, 10052, 10023, 10002, 10123, 10004};
101 wakeupEvent(iface, uids[0], v4, tcp, mac, srcIp, dstIp, sport, dport, now);
102 wakeupEvent(iface, uids[1], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
103 wakeupEvent(iface, uids[2], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
104 wakeupEvent(iface, uids[3], v4, icmp6, mac, srcIp, dstIp, sport, dport, now);
105 wakeupEvent(iface, uids[4], v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
106 wakeupEvent(iface, uids[5], v4, tcp, mac, srcIp, dstIp, sport, dport, now);
107 wakeupEvent(iface, uids[6], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
108 wakeupEvent(iface, uids[7], v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
109 wakeupEvent(iface, uids[8], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
Hugo Benichif562ac32017-09-04 13:24:43 +0900110
Hugo Benichi380a0632017-10-20 09:25:29 +0900111 String[] events2 = remove(listNetdEvent(), baseline);
Hugo Benichi60c9f632017-09-05 13:34:48 +0900112 int expectedLength2 = uids.length + 1; // +1 for the WakeupStats line
113 assertEquals(expectedLength2, events2.length);
114 assertContains(events2[0], "WakeupStats");
115 assertContains(events2[0], "wlan0");
Hugo Benichid921bce2017-10-12 21:33:40 +0900116 assertContains(events2[0], "0x800");
117 assertContains(events2[0], "0x86dd");
Hugo Benichif562ac32017-09-04 13:24:43 +0900118 for (int i = 0; i < uids.length; i++) {
Hugo Benichi60c9f632017-09-05 13:34:48 +0900119 String got = events2[i+1];
120 assertContains(got, "WakeupEvent");
Hugo Benichif562ac32017-09-04 13:24:43 +0900121 assertContains(got, "wlan0");
122 assertContains(got, "uid: " + uids[i]);
123 }
124
125 int uid = 20000;
126 for (int i = 0; i < BUFFER_LENGTH * 2; i++) {
127 long ts = now + 10;
Hugo Benichid921bce2017-10-12 21:33:40 +0900128 wakeupEvent(iface, uid, 0x800, 6, mac, srcIp, dstIp, 23, 24, ts);
Hugo Benichif562ac32017-09-04 13:24:43 +0900129 }
130
Hugo Benichi380a0632017-10-20 09:25:29 +0900131 String[] events3 = remove(listNetdEvent(), baseline);
Hugo Benichi60c9f632017-09-05 13:34:48 +0900132 int expectedLength3 = BUFFER_LENGTH + 1; // +1 for the WakeupStats line
133 assertEquals(expectedLength3, events3.length);
134 assertContains(events2[0], "WakeupStats");
135 assertContains(events2[0], "wlan0");
136 for (int i = 1; i < expectedLength3; i++) {
137 String got = events3[i];
138 assertContains(got, "WakeupEvent");
Hugo Benichif562ac32017-09-04 13:24:43 +0900139 assertContains(got, "wlan0");
140 assertContains(got, "uid: " + uid);
141 }
142
143 uid = 45678;
Hugo Benichid921bce2017-10-12 21:33:40 +0900144 wakeupEvent(iface, uid, 0x800, 6, mac, srcIp, dstIp, 23, 24, now);
Hugo Benichif562ac32017-09-04 13:24:43 +0900145
Hugo Benichi380a0632017-10-20 09:25:29 +0900146 String[] events4 = remove(listNetdEvent(), baseline);
Hugo Benichif562ac32017-09-04 13:24:43 +0900147 String lastEvent = events4[events4.length - 1];
Hugo Benichi60c9f632017-09-05 13:34:48 +0900148 assertContains(lastEvent, "WakeupEvent");
Hugo Benichif562ac32017-09-04 13:24:43 +0900149 assertContains(lastEvent, "wlan0");
150 assertContains(lastEvent, "uid: " + uid);
151 }
152
153 @Test
Hugo Benichi60c9f632017-09-05 13:34:48 +0900154 public void testWakeupStatsLogging() throws Exception {
Hugo Benichid921bce2017-10-12 21:33:40 +0900155 final byte[] mac = MAC_ADDR;
156 final String srcIp = "192.168.2.1";
157 final String dstIp = "192.168.2.23";
158 final String srcIp6 = "2401:fa00:4:fd00:a585:13d1:6a23:4fb4";
159 final String dstIp6 = "2404:6800:4006:807::200a";
160 final int sport = 2356;
161 final int dport = 13489;
162 final long now = 1001L;
163
164 final int v4 = 0x800;
165 final int v6 = 0x86dd;
166 final int tcp = 6;
167 final int udp = 17;
168 final int icmp6 = 58;
169
170 wakeupEvent("wlan0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
171 wakeupEvent("rmnet0", 10123, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
172 wakeupEvent("wlan0", 1000, v4, udp, mac, srcIp, dstIp, sport, dport, now);
173 wakeupEvent("rmnet0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
174 wakeupEvent("wlan0", -1, v6, icmp6, mac, srcIp6, dstIp6, sport, dport, now);
175 wakeupEvent("wlan0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
176 wakeupEvent("rmnet0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
177 wakeupEvent("wlan0", 10004, v4, udp, mac, srcIp, dstIp, sport, dport, now);
178 wakeupEvent("wlan0", 1000, v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
179 wakeupEvent("wlan0", 0, v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
180 wakeupEvent("wlan0", -1, v6, icmp6, mac, srcIp6, dstIp6, sport, dport, now);
181 wakeupEvent("rmnet0", 10052, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
182 wakeupEvent("wlan0", 0, v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
183 wakeupEvent("rmnet0", 1000, v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
184 wakeupEvent("wlan0", 1010, v4, udp, mac, srcIp, dstIp, sport, dport, now);
Hugo Benichi60c9f632017-09-05 13:34:48 +0900185
186 String got = flushStatistics();
187 String want = String.join("\n",
188 "dropped_events: 0",
189 "events <",
190 " if_name: \"\"",
191 " link_layer: 2",
192 " network_id: 0",
193 " time_ms: 0",
194 " transports: 0",
195 " wakeup_stats <",
196 " application_wakeups: 3",
197 " duration_sec: 0",
Hugo Benichid921bce2017-10-12 21:33:40 +0900198 " ethertype_counts <",
199 " key: 2048",
200 " value: 4",
201 " >",
202 " ethertype_counts <",
203 " key: 34525",
204 " value: 1",
205 " >",
206 " ip_next_header_counts <",
207 " key: 6",
208 " value: 5",
209 " >",
210 " l2_broadcast_count: 0",
211 " l2_multicast_count: 0",
212 " l2_unicast_count: 5",
Hugo Benichi175b5742017-09-19 13:15:26 +0900213 " no_uid_wakeups: 0",
Hugo Benichi60c9f632017-09-05 13:34:48 +0900214 " non_application_wakeups: 0",
215 " root_wakeups: 0",
216 " system_wakeups: 2",
217 " total_wakeups: 5",
Hugo Benichi60c9f632017-09-05 13:34:48 +0900218 " >",
219 ">",
220 "events <",
221 " if_name: \"\"",
222 " link_layer: 4",
223 " network_id: 0",
224 " time_ms: 0",
225 " transports: 0",
226 " wakeup_stats <",
227 " application_wakeups: 2",
228 " duration_sec: 0",
Hugo Benichid921bce2017-10-12 21:33:40 +0900229 " ethertype_counts <",
230 " key: 2048",
231 " value: 5",
232 " >",
233 " ethertype_counts <",
234 " key: 34525",
235 " value: 5",
236 " >",
237 " ip_next_header_counts <",
238 " key: 6",
239 " value: 3",
240 " >",
241 " ip_next_header_counts <",
242 " key: 17",
243 " value: 5",
244 " >",
245 " ip_next_header_counts <",
246 " key: 58",
247 " value: 2",
248 " >",
249 " l2_broadcast_count: 0",
250 " l2_multicast_count: 0",
251 " l2_unicast_count: 10",
Hugo Benichi175b5742017-09-19 13:15:26 +0900252 " no_uid_wakeups: 2",
Hugo Benichi60c9f632017-09-05 13:34:48 +0900253 " non_application_wakeups: 1",
254 " root_wakeups: 2",
255 " system_wakeups: 3",
256 " total_wakeups: 10",
Hugo Benichi60c9f632017-09-05 13:34:48 +0900257 " >",
258 ">",
259 "version: 2\n");
260 assertEquals(want, got);
261 }
262
263 @Test
Hugo Benichi5eb90532017-03-23 18:38:22 +0900264 public void testDnsLogging() throws Exception {
265 asyncDump(100);
266
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900267 dnsEvent(100, EVENT_GETADDRINFO, 0, 3456);
268 dnsEvent(100, EVENT_GETADDRINFO, 0, 267);
269 dnsEvent(100, EVENT_GETHOSTBYNAME, 22, 1230);
270 dnsEvent(100, EVENT_GETADDRINFO, 3, 45);
271 dnsEvent(100, EVENT_GETADDRINFO, 1, 2111);
272 dnsEvent(100, EVENT_GETADDRINFO, 0, 450);
273 dnsEvent(100, EVENT_GETHOSTBYNAME, 200, 638);
274 dnsEvent(100, EVENT_GETHOSTBYNAME, 178, 1300);
275 dnsEvent(101, EVENT_GETADDRINFO, 0, 56);
276 dnsEvent(101, EVENT_GETADDRINFO, 0, 78);
277 dnsEvent(101, EVENT_GETADDRINFO, 0, 14);
278 dnsEvent(101, EVENT_GETHOSTBYNAME, 0, 56);
279 dnsEvent(101, EVENT_GETADDRINFO, 0, 78);
280 dnsEvent(101, EVENT_GETADDRINFO, 0, 14);
Hugo Benichi5e055182016-06-01 08:50:38 +0900281
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900282 String got = flushStatistics();
283 String want = String.join("\n",
284 "dropped_events: 0",
285 "events <",
286 " if_name: \"\"",
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900287 " link_layer: 4",
288 " network_id: 100",
289 " time_ms: 0",
290 " transports: 2",
291 " dns_lookup_batch <",
292 " event_types: 1",
293 " event_types: 1",
294 " event_types: 2",
295 " event_types: 1",
296 " event_types: 1",
297 " event_types: 1",
298 " event_types: 2",
299 " event_types: 2",
Hugo Benichi4eccf782017-07-18 14:28:27 +0900300 " getaddrinfo_error_count: 0",
301 " getaddrinfo_query_count: 0",
302 " gethostbyname_error_count: 0",
303 " gethostbyname_query_count: 0",
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900304 " latencies_ms: 3456",
305 " latencies_ms: 267",
306 " latencies_ms: 1230",
307 " latencies_ms: 45",
308 " latencies_ms: 2111",
309 " latencies_ms: 450",
310 " latencies_ms: 638",
311 " latencies_ms: 1300",
312 " return_codes: 0",
313 " return_codes: 0",
314 " return_codes: 22",
315 " return_codes: 3",
316 " return_codes: 1",
317 " return_codes: 0",
318 " return_codes: 200",
319 " return_codes: 178",
320 " >",
321 ">",
322 "events <",
323 " if_name: \"\"",
324 " link_layer: 2",
325 " network_id: 101",
326 " time_ms: 0",
327 " transports: 1",
328 " dns_lookup_batch <",
329 " event_types: 1",
330 " event_types: 1",
331 " event_types: 1",
332 " event_types: 2",
333 " event_types: 1",
334 " event_types: 1",
Hugo Benichi4eccf782017-07-18 14:28:27 +0900335 " getaddrinfo_error_count: 0",
336 " getaddrinfo_query_count: 0",
337 " gethostbyname_error_count: 0",
338 " gethostbyname_query_count: 0",
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900339 " latencies_ms: 56",
340 " latencies_ms: 78",
341 " latencies_ms: 14",
342 " latencies_ms: 56",
343 " latencies_ms: 78",
344 " latencies_ms: 14",
345 " return_codes: 0",
346 " return_codes: 0",
347 " return_codes: 0",
348 " return_codes: 0",
349 " return_codes: 0",
350 " return_codes: 0",
351 " >",
352 ">",
353 "version: 2\n");
354 assertEquals(want, got);
Hugo Benichi5e055182016-06-01 08:50:38 +0900355 }
356
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900357 @Test
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900358 public void testConnectLogging() throws Exception {
Hugo Benichi5eb90532017-03-23 18:38:22 +0900359 asyncDump(100);
360
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900361 final int OK = 0;
362 Thread[] logActions = {
363 // ignored
Hugo Benichi5eb90532017-03-23 18:38:22 +0900364 connectEventAction(100, OsConstants.EALREADY, 0, EXAMPLE_IPV4),
365 connectEventAction(100, OsConstants.EALREADY, 0, EXAMPLE_IPV6),
366 connectEventAction(100, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV4),
367 connectEventAction(101, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6),
368 connectEventAction(101, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6),
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900369 // valid latencies
Hugo Benichi5eb90532017-03-23 18:38:22 +0900370 connectEventAction(100, OK, 110, EXAMPLE_IPV4),
371 connectEventAction(100, OK, 23, EXAMPLE_IPV4),
372 connectEventAction(100, OK, 45, EXAMPLE_IPV4),
373 connectEventAction(101, OK, 56, EXAMPLE_IPV4),
374 connectEventAction(101, OK, 523, EXAMPLE_IPV6),
375 connectEventAction(101, OK, 214, EXAMPLE_IPV6),
376 connectEventAction(101, OK, 67, EXAMPLE_IPV6),
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900377 // errors
Hugo Benichi5eb90532017-03-23 18:38:22 +0900378 connectEventAction(100, OsConstants.EPERM, 0, EXAMPLE_IPV4),
379 connectEventAction(101, OsConstants.EPERM, 0, EXAMPLE_IPV4),
380 connectEventAction(100, OsConstants.EAGAIN, 0, EXAMPLE_IPV4),
381 connectEventAction(100, OsConstants.EACCES, 0, EXAMPLE_IPV4),
382 connectEventAction(101, OsConstants.EACCES, 0, EXAMPLE_IPV4),
383 connectEventAction(101, OsConstants.EACCES, 0, EXAMPLE_IPV6),
384 connectEventAction(100, OsConstants.EADDRINUSE, 0, EXAMPLE_IPV4),
385 connectEventAction(101, OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV4),
386 connectEventAction(100, OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV6),
387 connectEventAction(100, OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV6),
388 connectEventAction(101, OsConstants.ECONNREFUSED, 0, EXAMPLE_IPV4),
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900389 };
390
391 for (Thread t : logActions) {
392 t.start();
393 }
394 for (Thread t : logActions) {
395 t.join();
396 }
397
Hugo Benichi5eb90532017-03-23 18:38:22 +0900398 String got = flushStatistics();
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900399 String want = String.join("\n",
Hugo Benichi5eb90532017-03-23 18:38:22 +0900400 "dropped_events: 0",
401 "events <",
402 " if_name: \"\"",
403 " link_layer: 4",
404 " network_id: 100",
405 " time_ms: 0",
406 " transports: 2",
407 " connect_statistics <",
408 " connect_blocking_count: 3",
409 " connect_count: 6",
410 " errnos_counters <",
411 " key: 1",
412 " value: 1",
413 " >",
414 " errnos_counters <",
415 " key: 11",
416 " value: 1",
417 " >",
418 " errnos_counters <",
419 " key: 13",
420 " value: 1",
421 " >",
422 " errnos_counters <",
423 " key: 98",
424 " value: 1",
425 " >",
426 " errnos_counters <",
427 " key: 110",
428 " value: 2",
429 " >",
430 " ipv6_addr_count: 1",
431 " latencies_ms: 23",
432 " latencies_ms: 45",
433 " latencies_ms: 110",
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900434 " >",
Hugo Benichi5eb90532017-03-23 18:38:22 +0900435 ">",
436 "events <",
437 " if_name: \"\"",
438 " link_layer: 2",
439 " network_id: 101",
440 " time_ms: 0",
441 " transports: 1",
442 " connect_statistics <",
443 " connect_blocking_count: 4",
444 " connect_count: 6",
445 " errnos_counters <",
446 " key: 1",
447 " value: 1",
448 " >",
449 " errnos_counters <",
450 " key: 13",
451 " value: 2",
452 " >",
453 " errnos_counters <",
454 " key: 110",
455 " value: 1",
456 " >",
457 " errnos_counters <",
458 " key: 111",
459 " value: 1",
460 " >",
461 " ipv6_addr_count: 5",
462 " latencies_ms: 56",
463 " latencies_ms: 67",
464 " latencies_ms: 214",
465 " latencies_ms: 523",
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900466 " >",
Hugo Benichi5eb90532017-03-23 18:38:22 +0900467 ">",
468 "version: 2\n");
469 assertEquals(want, got);
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900470 }
471
Hugo Benichi5eb90532017-03-23 18:38:22 +0900472 Thread connectEventAction(int netId, int error, int latencyMs, String ipAddr) {
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900473 return new Thread(() -> {
474 try {
Hugo Benichid921bce2017-10-12 21:33:40 +0900475 mService.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900476 } catch (Exception e) {
477 fail(e.toString());
478 }
479 });
480 }
481
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900482 void dnsEvent(int netId, int type, int result, int latency) throws Exception {
Hugo Benichid921bce2017-10-12 21:33:40 +0900483 mService.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900484 }
485
Hugo Benichid921bce2017-10-12 21:33:40 +0900486 void wakeupEvent(String iface, int uid, int ether, int ip, byte[] mac, String srcIp,
487 String dstIp, int sport, int dport, long now) throws Exception {
Hugo Benichi60c9f632017-09-05 13:34:48 +0900488 String prefix = NetdEventListenerService.WAKEUP_EVENT_IFACE_PREFIX + iface;
Hugo Benichid921bce2017-10-12 21:33:40 +0900489 mService.onWakeupEvent(prefix, uid, ether, ip, mac, srcIp, dstIp, sport, dport, now);
Hugo Benichi60c9f632017-09-05 13:34:48 +0900490 }
491
Hugo Benichi5eb90532017-03-23 18:38:22 +0900492 void asyncDump(long durationMs) throws Exception {
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900493 final long stop = System.currentTimeMillis() + durationMs;
494 final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
Hugo Benichi5eb90532017-03-23 18:38:22 +0900495 new Thread(() -> {
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900496 while (System.currentTimeMillis() < stop) {
Hugo Benichid921bce2017-10-12 21:33:40 +0900497 mService.list(pw);
Michal Karpinskidd9bb4f2016-10-12 14:59:26 +0100498 }
Hugo Benichi5eb90532017-03-23 18:38:22 +0900499 }).start();
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900500 }
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900501
502 // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
503 String flushStatistics() throws Exception {
504 IpConnectivityMetrics metricsService =
505 new IpConnectivityMetrics(mock(Context.class), (ctx) -> 2000);
Hugo Benichid921bce2017-10-12 21:33:40 +0900506 metricsService.mNetdListener = mService;
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900507
508 StringWriter buffer = new StringWriter();
509 PrintWriter writer = new PrintWriter(buffer);
510 metricsService.impl.dump(null, writer, new String[]{"flush"});
511 byte[] bytes = Base64.decode(buffer.toString(), Base64.DEFAULT);
Hugo Benichi5eb90532017-03-23 18:38:22 +0900512 IpConnectivityLog log = IpConnectivityLog.parseFrom(bytes);
513 for (IpConnectivityEvent ev : log.events) {
514 if (ev.getConnectStatistics() == null) {
515 continue;
516 }
517 // Sort repeated fields of connect() events arriving in non-deterministic order.
518 Arrays.sort(ev.getConnectStatistics().latenciesMs);
519 Arrays.sort(ev.getConnectStatistics().errnosCounters,
520 Comparator.comparingInt((p) -> p.key));
521 }
522 return log.toString();
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900523 }
Hugo Benichif562ac32017-09-04 13:24:43 +0900524
525 String[] listNetdEvent() throws Exception {
526 StringWriter buffer = new StringWriter();
527 PrintWriter writer = new PrintWriter(buffer);
Hugo Benichid921bce2017-10-12 21:33:40 +0900528 mService.list(writer);
Hugo Benichif562ac32017-09-04 13:24:43 +0900529 return buffer.toString().split("\\n");
530 }
531
532 static void assertContains(String got, String want) {
533 assertTrue(got + " did not contain \"" + want + "\"", got.contains(want));
534 }
Hugo Benichi380a0632017-10-20 09:25:29 +0900535
536 static <T> T[] remove(T[] array, T[] filtered) {
537 List<T> c = Arrays.asList(filtered);
538 int next = 0;
539 for (int i = 0; i < array.length; i++) {
540 if (c.contains(array[i])) {
541 continue;
542 }
543 array[next++] = array[i];
544 }
545 return Arrays.copyOf(array, next);
546 }
Hugo Benichi5e055182016-06-01 08:50:38 +0900547}