1 /*
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 
17 package com.android.server.connectivity;
18 
19 import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO;
20 import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME;
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.fail;
24 import static org.mockito.ArgumentMatchers.any;
25 import static org.mockito.Mockito.doReturn;
26 import static org.mockito.Mockito.mock;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29 
30 import android.content.Context;
31 import android.net.ConnectivityManager;
32 import android.net.ConnectivityMetricsEvent;
33 import android.net.IIpConnectivityMetrics;
34 import android.net.IpPrefix;
35 import android.net.LinkAddress;
36 import android.net.LinkProperties;
37 import android.net.Network;
38 import android.net.NetworkCapabilities;
39 import android.net.RouteInfo;
40 import android.net.metrics.ApfProgramEvent;
41 import android.net.metrics.ApfStats;
42 import android.net.metrics.DhcpClientEvent;
43 import android.net.metrics.IpConnectivityLog;
44 import android.net.metrics.IpManagerEvent;
45 import android.net.metrics.IpReachabilityEvent;
46 import android.net.metrics.RaEvent;
47 import android.net.metrics.ValidationProbeEvent;
48 import android.os.Build;
49 import android.os.Parcelable;
50 import android.os.SystemClock;
51 import android.system.OsConstants;
52 import android.util.Base64;
53 import androidx.test.filters.SmallTest;
54 import com.android.internal.util.BitUtils;
55 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
56 import com.android.testutils.DevSdkIgnoreRule;
57 import com.android.testutils.DevSdkIgnoreRunner;
58 import java.io.PrintWriter;
59 import java.io.StringWriter;
60 import org.junit.Before;
61 import org.junit.Test;
62 import org.junit.runner.RunWith;
63 import org.mockito.ArgumentCaptor;
64 import org.mockito.Mock;
65 import org.mockito.MockitoAnnotations;
66 
67 @RunWith(DevSdkIgnoreRunner.class)
68 @SmallTest
69 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
70 public class IpConnectivityMetricsTest {
71     static final IpReachabilityEvent FAKE_EV =
72             new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED);
73 
74     private static final String EXAMPLE_IPV4 = "192.0.2.1";
75     private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1";
76 
77     private static final byte[] MAC_ADDR =
78             {(byte)0x84, (byte)0xc9, (byte)0xb2, (byte)0x6a, (byte)0xed, (byte)0x4b};
79     private static final long NET_HANDLE = new Network(4291).getNetworkHandle();
80 
81     @Mock Context mCtx;
82     @Mock IIpConnectivityMetrics mMockService;
83     @Mock ConnectivityManager mCm;
84 
85     IpConnectivityMetrics mService;
86     NetdEventListenerService mNetdListener;
87     private static final NetworkCapabilities CAPABILITIES_WIFI = new NetworkCapabilities.Builder()
88             .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
89             .build();
90     private static final NetworkCapabilities CAPABILITIES_CELL = new NetworkCapabilities.Builder()
91             .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
92             .build();
93 
94     @Before
setUp()95     public void setUp() {
96         MockitoAnnotations.initMocks(this);
97         mService = new IpConnectivityMetrics(mCtx, (ctx) -> 2000);
98         mNetdListener = new NetdEventListenerService(mCm);
99         mService.mNetdListener = mNetdListener;
100     }
101 
102     @Test
testBufferFlushing()103     public void testBufferFlushing() {
104         String output1 = getdump("flush");
105         assertEquals("", output1);
106 
107         new IpConnectivityLog(mService.impl).log(1, FAKE_EV);
108         String output2 = getdump("flush");
109         assertFalse("".equals(output2));
110 
111         String output3 = getdump("flush");
112         assertEquals("", output3);
113     }
114 
115     @Test
testRateLimiting()116     public void testRateLimiting() {
117         final IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
118         final ApfProgramEvent ev = new ApfProgramEvent.Builder().build();
119         final long fakeTimestamp = 1;
120 
121         int attempt = 100; // More than burst quota, but less than buffer size.
122         for (int i = 0; i < attempt; i++) {
123             logger.log(ev);
124         }
125 
126         String output1 = getdump("flush");
127         assertFalse("".equals(output1));
128 
129         for (int i = 0; i < attempt; i++) {
130             assertFalse("expected event to be dropped", logger.log(fakeTimestamp, ev));
131         }
132 
133         String output2 = getdump("flush");
134         assertEquals("", output2);
135     }
136 
logDefaultNetworkEvent(long timeMs, NetworkAgentInfo nai, NetworkAgentInfo oldNai)137     private void logDefaultNetworkEvent(long timeMs, NetworkAgentInfo nai,
138             NetworkAgentInfo oldNai) {
139         final Network network = (nai != null) ? nai.network() : null;
140         final boolean validated = (nai != null) ? nai.isValidated() : false;
141         final LinkProperties lp = (nai != null) ? nai.linkProperties : null;
142         final NetworkCapabilities nc = (nai != null) ? nai.networkCapabilities : null;
143 
144         final Network prevNetwork = (oldNai != null) ? oldNai.network() : null;
145         final LinkProperties prevLp = (oldNai != null) ? oldNai.linkProperties : null;
146         final NetworkCapabilities prevNc = (oldNai != null) ? oldNai.networkCapabilities : null;
147 
148         mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs, network, 0 /* legacyScore */,
149                 validated, lp, nc, prevNetwork, 0 /* prevLegacyScore */, prevLp, prevNc);
150     }
151     @Test
testDefaultNetworkEvents()152     public void testDefaultNetworkEvents() throws Exception {
153         final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
154         final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
155 
156         NetworkAgentInfo[][] defaultNetworks = {
157             // nothing -> cell
158             {null, makeNai(100, false, true, cell)},
159             // cell -> wifi
160             {makeNai(100, true, true, cell), makeNai(101, true, false, wifi)},
161             // wifi -> nothing
162             {makeNai(101, true, false, wifi), null},
163             // nothing -> cell
164             {null, makeNai(102, true, true, cell)},
165             // cell -> wifi
166             {makeNai(102, true, true, cell), makeNai(103, true, false, wifi)},
167         };
168 
169         long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
170         long durationMs = 1001;
171         for (NetworkAgentInfo[] pair : defaultNetworks) {
172             timeMs += durationMs;
173             durationMs += durationMs;
174             logDefaultNetworkEvent(timeMs, pair[1], pair[0]);
175         }
176 
177         String want = String.join("\n",
178                 "dropped_events: 0",
179                 "events <",
180                 "  if_name: \"\"",
181                 "  link_layer: 5",
182                 "  network_id: 0",
183                 "  time_ms: 0",
184                 "  transports: 0",
185                 "  default_network_event <",
186                 "    default_network_duration_ms: 1001",
187                 "    final_score: 0",
188                 "    initial_score: 0",
189                 "    ip_support: 0",
190                 "    no_default_network_duration_ms: 0",
191                 "    previous_default_network_link_layer: 0",
192                 "    previous_network_ip_support: 0",
193                 "    validation_duration_ms: 0",
194                 "  >",
195                 ">",
196                 "events <",
197                 "  if_name: \"\"",
198                 "  link_layer: 2",
199                 "  network_id: 100",
200                 "  time_ms: 0",
201                 "  transports: 1",
202                 "  default_network_event <",
203                 "    default_network_duration_ms: 2002",
204                 "    final_score: 0",
205                 "    initial_score: 0",
206                 "    ip_support: 3",
207                 "    no_default_network_duration_ms: 0",
208                 "    previous_default_network_link_layer: 0",
209                 "    previous_network_ip_support: 0",
210                 "    validation_duration_ms: 2002",
211                 "  >",
212                 ">",
213                 "events <",
214                 "  if_name: \"\"",
215                 "  link_layer: 4",
216                 "  network_id: 101",
217                 "  time_ms: 0",
218                 "  transports: 2",
219                 "  default_network_event <",
220                 "    default_network_duration_ms: 4004",
221                 "    final_score: 0",
222                 "    initial_score: 0",
223                 "    ip_support: 1",
224                 "    no_default_network_duration_ms: 0",
225                 "    previous_default_network_link_layer: 2",
226                 "    previous_network_ip_support: 0",
227                 "    validation_duration_ms: 4004",
228                 "  >",
229                 ">",
230                 "events <",
231                 "  if_name: \"\"",
232                 "  link_layer: 5",
233                 "  network_id: 0",
234                 "  time_ms: 0",
235                 "  transports: 0",
236                 "  default_network_event <",
237                 "    default_network_duration_ms: 8008",
238                 "    final_score: 0",
239                 "    initial_score: 0",
240                 "    ip_support: 0",
241                 "    no_default_network_duration_ms: 0",
242                 "    previous_default_network_link_layer: 4",
243                 "    previous_network_ip_support: 0",
244                 "    validation_duration_ms: 0",
245                 "  >",
246                 ">",
247                 "events <",
248                 "  if_name: \"\"",
249                 "  link_layer: 2",
250                 "  network_id: 102",
251                 "  time_ms: 0",
252                 "  transports: 1",
253                 "  default_network_event <",
254                 "    default_network_duration_ms: 16016",
255                 "    final_score: 0",
256                 "    initial_score: 0",
257                 "    ip_support: 3",
258                 "    no_default_network_duration_ms: 0",
259                 "    previous_default_network_link_layer: 4",
260                 "    previous_network_ip_support: 0",
261                 "    validation_duration_ms: 16016",
262                 "  >",
263                 ">",
264                 "version: 2\n");
265 
266         verifySerialization(want, getdump("flush"));
267     }
268 
269     @Test
testEndToEndLogging()270     public void testEndToEndLogging() throws Exception {
271         // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
272         IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
273 
274         ApfStats apfStats = new ApfStats.Builder()
275                 .setDurationMs(45000)
276                 .setReceivedRas(10)
277                 .setMatchingRas(2)
278                 .setDroppedRas(2)
279                 .setParseErrors(2)
280                 .setZeroLifetimeRas(1)
281                 .setProgramUpdates(4)
282                 .setProgramUpdatesAll(7)
283                 .setProgramUpdatesAllowingMulticast(3)
284                 .setMaxProgramSize(2048)
285                 .build();
286 
287         final ValidationProbeEvent validationEv = new ValidationProbeEvent.Builder()
288                 .setDurationMs(40730)
289                 .setProbeType(ValidationProbeEvent.PROBE_HTTP, true)
290                 .setReturnCode(204)
291                 .build();
292 
293         final DhcpClientEvent event = new DhcpClientEvent.Builder()
294                 .setMsg("SomeState")
295                 .setDurationMs(192)
296                 .build();
297         Parcelable[] events = {
298             new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED), event,
299             new IpManagerEvent(IpManagerEvent.PROVISIONING_OK, 5678),
300             validationEv,
301             apfStats,
302             new RaEvent(2000, 400, 300, -1, 1000, -1)
303         };
304 
305         for (int i = 0; i < events.length; i++) {
306             ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
307             ev.timestamp = 100 * (i + 1);
308             ev.ifname = "wlan0";
309             ev.data = events[i];
310             logger.log(ev);
311         }
312 
313         // netId, errno, latency, destination
314         connectEvent(100, OsConstants.EALREADY, 0, EXAMPLE_IPV4);
315         connectEvent(100, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6);
316         connectEvent(100, 0, 110, EXAMPLE_IPV4);
317         connectEvent(101, 0, 23, EXAMPLE_IPV4);
318         connectEvent(101, 0, 45, EXAMPLE_IPV6);
319         connectEvent(100, OsConstants.EAGAIN, 0, EXAMPLE_IPV4);
320 
321         // netId, type, return code, latency
322         dnsEvent(100, EVENT_GETADDRINFO, 0, 3456);
323         dnsEvent(100, EVENT_GETADDRINFO, 3, 45);
324         dnsEvent(100, EVENT_GETHOSTBYNAME, 0, 638);
325         dnsEvent(101, EVENT_GETADDRINFO, 0, 56);
326         dnsEvent(101, EVENT_GETHOSTBYNAME, 0, 34);
327 
328         // iface, uid
329         final byte[] mac = {0x48, 0x7c, 0x2b, 0x6a, 0x3e, 0x4b};
330         final String srcIp = "192.168.2.1";
331         final String dstIp = "192.168.2.23";
332         final int sport = 2356;
333         final int dport = 13489;
334         final long now = 1001L;
335         final int v4 = 0x800;
336         final int tcp = 6;
337         final int udp = 17;
338         wakeupEvent("wlan0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
339         wakeupEvent("wlan0", 10123, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
340         wakeupEvent("wlan0", 1000, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
341         wakeupEvent("wlan0", 10008, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
342         wakeupEvent("wlan0", -1, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
343         wakeupEvent("wlan0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
344 
345         long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
346         final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
347         final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
348         final NetworkAgentInfo cellNai = makeNai(100, false, true, cell);
349         final NetworkAgentInfo wifiNai = makeNai(101, true, false, wifi);
350         logDefaultNetworkEvent(timeMs + 200L, cellNai, null);
351         logDefaultNetworkEvent(timeMs + 300L, wifiNai, cellNai);
352 
353         String want = String.join("\n",
354                 "dropped_events: 0",
355                 "events <",
356                 "  if_name: \"\"",
357                 "  link_layer: 4",
358                 "  network_id: 0",
359                 "  time_ms: 100",
360                 "  transports: 0",
361                 "  ip_reachability_event <",
362                 "    event_type: 512",
363                 "    if_name: \"\"",
364                 "  >",
365                 ">",
366                 "events <",
367                 "  if_name: \"\"",
368                 "  link_layer: 4",
369                 "  network_id: 0",
370                 "  time_ms: 200",
371                 "  transports: 0",
372                 "  dhcp_event <",
373                 "    duration_ms: 192",
374                 "    if_name: \"\"",
375                 "    state_transition: \"SomeState\"",
376                 "  >",
377                 ">",
378                 "events <",
379                 "  if_name: \"\"",
380                 "  link_layer: 4",
381                 "  network_id: 0",
382                 "  time_ms: 300",
383                 "  transports: 0",
384                 "  ip_provisioning_event <",
385                 "    event_type: 1",
386                 "    if_name: \"\"",
387                 "    latency_ms: 5678",
388                 "  >",
389                 ">",
390                 "events <",
391                 "  if_name: \"\"",
392                 "  link_layer: 4",
393                 "  network_id: 0",
394                 "  time_ms: 400",
395                 "  transports: 0",
396                 "  validation_probe_event <",
397                 "    latency_ms: 40730",
398                 "    probe_result: 204",
399                 "    probe_type: 257",
400                 "  >",
401                 ">",
402                 "events <",
403                 "  if_name: \"\"",
404                 "  link_layer: 4",
405                 "  network_id: 0",
406                 "  time_ms: 500",
407                 "  transports: 0",
408                 "  apf_statistics <",
409                 "    dropped_ras: 2",
410                 "    duration_ms: 45000",
411                 "    matching_ras: 2",
412                 "    max_program_size: 2048",
413                 "    parse_errors: 2",
414                 "    program_updates: 4",
415                 "    program_updates_all: 7",
416                 "    program_updates_allowing_multicast: 3",
417                 "    received_ras: 10",
418                 "    total_packet_dropped: 0",
419                 "    total_packet_processed: 0",
420                 "    zero_lifetime_ras: 1",
421                 "  >",
422                 ">",
423                 "events <",
424                 "  if_name: \"\"",
425                 "  link_layer: 4",
426                 "  network_id: 0",
427                 "  time_ms: 600",
428                 "  transports: 0",
429                 "  ra_event <",
430                 "    dnssl_lifetime: -1",
431                 "    prefix_preferred_lifetime: 300",
432                 "    prefix_valid_lifetime: 400",
433                 "    rdnss_lifetime: 1000",
434                 "    route_info_lifetime: -1",
435                 "    router_lifetime: 2000",
436                 "  >",
437                 ">",
438                 "events <",
439                 "  if_name: \"\"",
440                 "  link_layer: 5",
441                 "  network_id: 0",
442                 "  time_ms: 0",
443                 "  transports: 0",
444                 "  default_network_event <",
445                 "    default_network_duration_ms: 200",
446                 "    final_score: 0",
447                 "    initial_score: 0",
448                 "    ip_support: 0",
449                 "    no_default_network_duration_ms: 0",
450                 "    previous_default_network_link_layer: 0",
451                 "    previous_network_ip_support: 0",
452                 "    validation_duration_ms: 0",
453                 "  >",
454                 ">",
455                 "events <",
456                 "  if_name: \"\"",
457                 "  link_layer: 2",
458                 "  network_id: 100",
459                 "  time_ms: 0",
460                 "  transports: 1",
461                 "  default_network_event <",
462                 "    default_network_duration_ms: 100",
463                 "    final_score: 0",
464                 "    initial_score: 0",
465                 "    ip_support: 2",
466                 "    no_default_network_duration_ms: 0",
467                 "    previous_default_network_link_layer: 0",
468                 "    previous_network_ip_support: 0",
469                 "    validation_duration_ms: 100",
470                 "  >",
471                 ">",
472                 "events <",
473                 "  if_name: \"\"",
474                 "  link_layer: 4",
475                 "  network_id: 100",
476                 "  time_ms: 0",
477                 "  transports: 2",
478                 "  connect_statistics <",
479                 "    connect_blocking_count: 1",
480                 "    connect_count: 3",
481                 "    errnos_counters <",
482                 "      key: 11",
483                 "      value: 1",
484                 "    >",
485                 "    ipv6_addr_count: 1",
486                 "    latencies_ms: 110",
487                 "  >",
488                 ">",
489                 "events <",
490                 "  if_name: \"\"",
491                 "  link_layer: 2",
492                 "  network_id: 101",
493                 "  time_ms: 0",
494                 "  transports: 1",
495                 "  connect_statistics <",
496                 "    connect_blocking_count: 2",
497                 "    connect_count: 2",
498                 "    ipv6_addr_count: 1",
499                 "    latencies_ms: 23",
500                 "    latencies_ms: 45",
501                 "  >",
502                 ">",
503                 "events <",
504                 "  if_name: \"\"",
505                 "  link_layer: 4",
506                 "  network_id: 100",
507                 "  time_ms: 0",
508                 "  transports: 2",
509                 "  dns_lookup_batch <",
510                 "    event_types: 1",
511                 "    event_types: 1",
512                 "    event_types: 2",
513                 "    getaddrinfo_error_count: 0",
514                 "    getaddrinfo_query_count: 0",
515                 "    gethostbyname_error_count: 0",
516                 "    gethostbyname_query_count: 0",
517                 "    latencies_ms: 3456",
518                 "    latencies_ms: 45",
519                 "    latencies_ms: 638",
520                 "    return_codes: 0",
521                 "    return_codes: 3",
522                 "    return_codes: 0",
523                 "  >",
524                 ">",
525                 "events <",
526                 "  if_name: \"\"",
527                 "  link_layer: 2",
528                 "  network_id: 101",
529                 "  time_ms: 0",
530                 "  transports: 1",
531                 "  dns_lookup_batch <",
532                 "    event_types: 1",
533                 "    event_types: 2",
534                 "    getaddrinfo_error_count: 0",
535                 "    getaddrinfo_query_count: 0",
536                 "    gethostbyname_error_count: 0",
537                 "    gethostbyname_query_count: 0",
538                 "    latencies_ms: 56",
539                 "    latencies_ms: 34",
540                 "    return_codes: 0",
541                 "    return_codes: 0",
542                 "  >",
543                 ">",
544                 "events <",
545                 "  if_name: \"\"",
546                 "  link_layer: 4",
547                 "  network_id: 0",
548                 "  time_ms: 0",
549                 "  transports: 0",
550                 "  wakeup_stats <",
551                 "    application_wakeups: 3",
552                 "    duration_sec: 0",
553                 "    ethertype_counts <",
554                 "      key: 2048",
555                 "      value: 6",
556                 "    >",
557                 "    ip_next_header_counts <",
558                 "      key: 6",
559                 "      value: 3",
560                 "    >",
561                 "    ip_next_header_counts <",
562                 "      key: 17",
563                 "      value: 3",
564                 "    >",
565                 "    l2_broadcast_count: 0",
566                 "    l2_multicast_count: 0",
567                 "    l2_unicast_count: 6",
568                 "    no_uid_wakeups: 1",
569                 "    non_application_wakeups: 0",
570                 "    root_wakeups: 0",
571                 "    system_wakeups: 2",
572                 "    total_wakeups: 6",
573                 "  >",
574                 ">",
575                 "version: 2\n");
576 
577         verifySerialization(want, getdump("flush"));
578     }
579 
getdump(String .... command)580     String getdump(String ... command) {
581         StringWriter buffer = new StringWriter();
582         PrintWriter writer = new PrintWriter(buffer);
583         mService.impl.dump(null, writer, command);
584         return buffer.toString();
585     }
586 
setCapabilities(int netId)587     private void setCapabilities(int netId) {
588         final ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallback =
589                 ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
590         verify(mCm).registerNetworkCallback(any(), networkCallback.capture());
591         networkCallback.getValue().onCapabilitiesChanged(new Network(netId),
592                 netId == 100 ? CAPABILITIES_WIFI : CAPABILITIES_CELL);
593     }
594 
connectEvent(int netId, int error, int latencyMs, String ipAddr)595     void connectEvent(int netId, int error, int latencyMs, String ipAddr) throws Exception {
596         setCapabilities(netId);
597         mNetdListener.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
598     }
599 
dnsEvent(int netId, int type, int result, int latency)600     void dnsEvent(int netId, int type, int result, int latency) throws Exception {
601         setCapabilities(netId);
602         mNetdListener.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
603     }
604 
wakeupEvent(String iface, int uid, int ether, int ip, byte[] mac, String srcIp, String dstIp, int sport, int dport, long now)605     void wakeupEvent(String iface, int uid, int ether, int ip, byte[] mac, String srcIp,
606             String dstIp, int sport, int dport, long now) throws Exception {
607         String prefix = NET_HANDLE + ":" + iface;
608         mNetdListener.onWakeupEvent(prefix, uid, ether, ip, mac, srcIp, dstIp, sport, dport, now);
609     }
610 
makeNai(int netId, boolean ipv4, boolean ipv6, long transports)611     NetworkAgentInfo makeNai(int netId, boolean ipv4, boolean ipv6, long transports) {
612         NetworkAgentInfo nai = mock(NetworkAgentInfo.class);
613         when(nai.network()).thenReturn(new Network(netId));
614         nai.linkProperties = new LinkProperties();
615         nai.networkCapabilities = new NetworkCapabilities();
616         nai.setValidated(true);
617         doReturn(true).when(nai).isValidated();
618         doReturn(SystemClock.elapsedRealtime()).when(nai).getFirstValidationTime();
619         doReturn(SystemClock.elapsedRealtime()).when(nai).getCurrentValidationTime();
620         for (int t : BitUtils.unpackBits(transports)) {
621             nai.networkCapabilities.addTransportType(t);
622         }
623         if (ipv4) {
624             nai.linkProperties.addLinkAddress(new LinkAddress("192.0.2.12/24"));
625             nai.linkProperties.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0")));
626         }
627         if (ipv6) {
628             nai.linkProperties.addLinkAddress(new LinkAddress("2001:db8:dead:beef:f00::a0/64"));
629             nai.linkProperties.addRoute(new RouteInfo(new IpPrefix("::/0")));
630         }
631         return nai;
632     }
633 
verifySerialization(String want, String output)634     static void verifySerialization(String want, String output) {
635         try {
636             byte[] got = Base64.decode(output, Base64.DEFAULT);
637             IpConnectivityLogClass.IpConnectivityLog log =
638                     IpConnectivityLogClass.IpConnectivityLog.parseFrom(got);
639             assertEquals(want, log.toString());
640         } catch (Exception e) {
641             fail(e.toString());
642         }
643     }
644 }
645