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 com.android.server.connectivity.MetricsTestUtil.aLong;
20 import static com.android.server.connectivity.MetricsTestUtil.aString;
21 import static com.android.server.connectivity.MetricsTestUtil.aType;
22 import static com.android.server.connectivity.MetricsTestUtil.anInt;
23 import static com.android.server.connectivity.MetricsTestUtil.describeIpEvent;
24 import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.BLUETOOTH;
25 import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.CELLULAR;
26 import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
27 import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.MULTIPLE;
28 import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.WIFI;
29 
30 import static org.junit.Assert.assertEquals;
31 import static org.junit.Assert.fail;
32 
33 import android.net.ConnectivityMetricsEvent;
34 import android.net.metrics.ApfProgramEvent;
35 import android.net.metrics.ApfStats;
36 import android.net.metrics.DefaultNetworkEvent;
37 import android.net.metrics.DhcpClientEvent;
38 import android.net.metrics.DhcpErrorEvent;
39 import android.net.metrics.IpManagerEvent;
40 import android.net.metrics.IpReachabilityEvent;
41 import android.net.metrics.NetworkEvent;
42 import android.net.metrics.RaEvent;
43 import android.net.metrics.ValidationProbeEvent;
44 import android.net.metrics.WakeupStats;
45 import android.test.suitebuilder.annotation.SmallTest;
46 
47 import androidx.test.runner.AndroidJUnit4;
48 
49 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
50 
51 import org.junit.Test;
52 import org.junit.runner.RunWith;
53 
54 import java.util.Arrays;
55 import java.util.List;
56 
57 // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
58 @RunWith(AndroidJUnit4.class)
59 @SmallTest
60 public class IpConnectivityEventBuilderTest {
61 
62     @Test
testLinkLayerInferrence()63     public void testLinkLayerInferrence() {
64         ConnectivityMetricsEvent ev = describeIpEvent(
65                 aType(IpReachabilityEvent.class),
66                 anInt(IpReachabilityEvent.NUD_FAILED));
67 
68         String want = String.join("\n",
69                 "dropped_events: 0",
70                 "events <",
71                 "  if_name: \"\"",
72                 "  link_layer: 0",
73                 "  network_id: 0",
74                 "  time_ms: 1",
75                 "  transports: 0",
76                 "  ip_reachability_event <",
77                 "    event_type: 512",
78                 "    if_name: \"\"",
79                 "  >",
80                 ">",
81                 "version: 2\n");
82         verifySerialization(want, ev);
83 
84         ev.netId = 123;
85         ev.transports = 3; // transports have priority for inferrence of link layer
86         ev.ifname = "wlan0";
87         want = String.join("\n",
88                 "dropped_events: 0",
89                 "events <",
90                 "  if_name: \"\"",
91                 String.format("  link_layer: %d", MULTIPLE),
92                 "  network_id: 123",
93                 "  time_ms: 1",
94                 "  transports: 3",
95                 "  ip_reachability_event <",
96                 "    event_type: 512",
97                 "    if_name: \"\"",
98                 "  >",
99                 ">",
100                 "version: 2\n");
101         verifySerialization(want, ev);
102 
103         ev.transports = 1;
104         ev.ifname = null;
105         want = String.join("\n",
106                 "dropped_events: 0",
107                 "events <",
108                 "  if_name: \"\"",
109                 String.format("  link_layer: %d", CELLULAR),
110                 "  network_id: 123",
111                 "  time_ms: 1",
112                 "  transports: 1",
113                 "  ip_reachability_event <",
114                 "    event_type: 512",
115                 "    if_name: \"\"",
116                 "  >",
117                 ">",
118                 "version: 2\n");
119         verifySerialization(want, ev);
120 
121         ev.transports = 0;
122         ev.ifname = "not_inferred";
123         want = String.join("\n",
124                 "dropped_events: 0",
125                 "events <",
126                 "  if_name: \"not_inferred\"",
127                 "  link_layer: 0",
128                 "  network_id: 123",
129                 "  time_ms: 1",
130                 "  transports: 0",
131                 "  ip_reachability_event <",
132                 "    event_type: 512",
133                 "    if_name: \"\"",
134                 "  >",
135                 ">",
136                 "version: 2\n");
137         verifySerialization(want, ev);
138 
139         ev.ifname = "bt-pan";
140         want = String.join("\n",
141                 "dropped_events: 0",
142                 "events <",
143                 "  if_name: \"\"",
144                 String.format("  link_layer: %d", BLUETOOTH),
145                 "  network_id: 123",
146                 "  time_ms: 1",
147                 "  transports: 0",
148                 "  ip_reachability_event <",
149                 "    event_type: 512",
150                 "    if_name: \"\"",
151                 "  >",
152                 ">",
153                 "version: 2\n");
154         verifySerialization(want, ev);
155 
156         ev.ifname = "rmnet_ipa0";
157         want = String.join("\n",
158                 "dropped_events: 0",
159                 "events <",
160                 "  if_name: \"\"",
161                 String.format("  link_layer: %d", CELLULAR),
162                 "  network_id: 123",
163                 "  time_ms: 1",
164                 "  transports: 0",
165                 "  ip_reachability_event <",
166                 "    event_type: 512",
167                 "    if_name: \"\"",
168                 "  >",
169                 ">",
170                 "version: 2\n");
171         verifySerialization(want, ev);
172 
173         ev.ifname = "wlan0";
174         want = String.join("\n",
175                 "dropped_events: 0",
176                 "events <",
177                 "  if_name: \"\"",
178                 String.format("  link_layer: %d", WIFI),
179                 "  network_id: 123",
180                 "  time_ms: 1",
181                 "  transports: 0",
182                 "  ip_reachability_event <",
183                 "    event_type: 512",
184                 "    if_name: \"\"",
185                 "  >",
186                 ">",
187                 "version: 2\n");
188         verifySerialization(want, ev);
189     }
190 
191     @Test
testDefaultNetworkEventSerialization()192     public void testDefaultNetworkEventSerialization() {
193         DefaultNetworkEvent ev = new DefaultNetworkEvent(1001);
194         ev.netId = 102;
195         ev.transports = 2;
196         ev.previousTransports = 4;
197         ev.ipv4 = true;
198         ev.initialScore = 20;
199         ev.finalScore = 60;
200         ev.durationMs = 54;
201         ev.validatedMs = 27;
202 
203         String want = String.join("\n",
204                 "dropped_events: 0",
205                 "events <",
206                 "  if_name: \"\"",
207                 "  link_layer: 4",
208                 "  network_id: 102",
209                 "  time_ms: 0",
210                 "  transports: 2",
211                 "  default_network_event <",
212                 "    default_network_duration_ms: 54",
213                 "    final_score: 60",
214                 "    initial_score: 20",
215                 "    ip_support: 1",
216                 "    no_default_network_duration_ms: 0",
217                 "    previous_default_network_link_layer: 1",
218                 "    previous_network_ip_support: 0",
219                 "    validation_duration_ms: 27",
220                 "  >",
221                 ">",
222                 "version: 2\n");
223 
224         verifySerialization(want, IpConnectivityEventBuilder.toProto(ev));
225     }
226 
227     @Test
testDhcpClientEventSerialization()228     public void testDhcpClientEventSerialization() {
229         ConnectivityMetricsEvent ev = describeIpEvent(
230                 aType(DhcpClientEvent.class),
231                 aString("SomeState"),
232                 anInt(192));
233 
234         String want = String.join("\n",
235                 "dropped_events: 0",
236                 "events <",
237                 "  if_name: \"\"",
238                 "  link_layer: 0",
239                 "  network_id: 0",
240                 "  time_ms: 1",
241                 "  transports: 0",
242                 "  dhcp_event <",
243                 "    duration_ms: 192",
244                 "    if_name: \"\"",
245                 "    state_transition: \"SomeState\"",
246                 "  >",
247                 ">",
248                 "version: 2\n");
249 
250         verifySerialization(want, ev);
251     }
252 
253     @Test
testDhcpErrorEventSerialization()254     public void testDhcpErrorEventSerialization() {
255         ConnectivityMetricsEvent ev = describeIpEvent(
256                 aType(DhcpErrorEvent.class),
257                 anInt(DhcpErrorEvent.L4_NOT_UDP));
258 
259         String want = String.join("\n",
260                 "dropped_events: 0",
261                 "events <",
262                 "  if_name: \"\"",
263                 "  link_layer: 0",
264                 "  network_id: 0",
265                 "  time_ms: 1",
266                 "  transports: 0",
267                 "  dhcp_event <",
268                 "    duration_ms: 0",
269                 "    if_name: \"\"",
270                 "    error_code: 50397184",
271                 "  >",
272                 ">",
273                 "version: 2\n");
274 
275         verifySerialization(want, ev);
276     }
277 
278     @Test
testIpManagerEventSerialization()279     public void testIpManagerEventSerialization() {
280         ConnectivityMetricsEvent ev = describeIpEvent(
281                 aType(IpManagerEvent.class),
282                 anInt(IpManagerEvent.PROVISIONING_OK),
283                 aLong(5678));
284 
285         String want = String.join("\n",
286                 "dropped_events: 0",
287                 "events <",
288                 "  if_name: \"\"",
289                 "  link_layer: 0",
290                 "  network_id: 0",
291                 "  time_ms: 1",
292                 "  transports: 0",
293                 "  ip_provisioning_event <",
294                 "    event_type: 1",
295                 "    if_name: \"\"",
296                 "    latency_ms: 5678",
297                 "  >",
298                 ">",
299                 "version: 2\n");
300 
301         verifySerialization(want, ev);
302     }
303 
304     @Test
testIpReachabilityEventSerialization()305     public void testIpReachabilityEventSerialization() {
306         ConnectivityMetricsEvent ev = describeIpEvent(
307                 aType(IpReachabilityEvent.class),
308                 anInt(IpReachabilityEvent.NUD_FAILED));
309 
310         String want = String.join("\n",
311                 "dropped_events: 0",
312                 "events <",
313                 "  if_name: \"\"",
314                 "  link_layer: 0",
315                 "  network_id: 0",
316                 "  time_ms: 1",
317                 "  transports: 0",
318                 "  ip_reachability_event <",
319                 "    event_type: 512",
320                 "    if_name: \"\"",
321                 "  >",
322                 ">",
323                 "version: 2\n");
324 
325         verifySerialization(want, ev);
326     }
327 
328     @Test
testNetworkEventSerialization()329     public void testNetworkEventSerialization() {
330         ConnectivityMetricsEvent ev = describeIpEvent(
331                 aType(NetworkEvent.class),
332                 anInt(5),
333                 aLong(20410));
334 
335         String want = String.join("\n",
336                 "dropped_events: 0",
337                 "events <",
338                 "  if_name: \"\"",
339                 "  link_layer: 0",
340                 "  network_id: 0",
341                 "  time_ms: 1",
342                 "  transports: 0",
343                 "  network_event <",
344                 "    event_type: 5",
345                 "    latency_ms: 20410",
346                 "  >",
347                 ">",
348                 "version: 2\n");
349 
350         verifySerialization(want, ev);
351     }
352 
353     @Test
testValidationProbeEventSerialization()354     public void testValidationProbeEventSerialization() {
355         ConnectivityMetricsEvent ev = describeIpEvent(
356                 aType(ValidationProbeEvent.class),
357                 aLong(40730),
358                 anInt(ValidationProbeEvent.PROBE_HTTP),
359                 anInt(204));
360 
361         String want = String.join("\n",
362                 "dropped_events: 0",
363                 "events <",
364                 "  if_name: \"\"",
365                 "  link_layer: 0",
366                 "  network_id: 0",
367                 "  time_ms: 1",
368                 "  transports: 0",
369                 "  validation_probe_event <",
370                 "    latency_ms: 40730",
371                 "    probe_result: 204",
372                 "    probe_type: 1",
373                 "  >",
374                 ">",
375                 "version: 2\n");
376 
377         verifySerialization(want, ev);
378     }
379 
380     @Test
testApfProgramEventSerialization()381     public void testApfProgramEventSerialization() {
382         ConnectivityMetricsEvent ev = describeIpEvent(
383                 aType(ApfProgramEvent.class),
384                 aLong(200),
385                 aLong(18),
386                 anInt(7),
387                 anInt(9),
388                 anInt(2048),
389                 anInt(3));
390 
391         String want = String.join("\n",
392                 "dropped_events: 0",
393                 "events <",
394                 "  if_name: \"\"",
395                 "  link_layer: 0",
396                 "  network_id: 0",
397                 "  time_ms: 1",
398                 "  transports: 0",
399                 "  apf_program_event <",
400                 "    current_ras: 9",
401                 "    drop_multicast: true",
402                 "    effective_lifetime: 18",
403                 "    filtered_ras: 7",
404                 "    has_ipv4_addr: true",
405                 "    lifetime: 200",
406                 "    program_length: 2048",
407                 "  >",
408                 ">",
409                 "version: 2\n");
410 
411         verifySerialization(want, ev);
412     }
413 
414     @Test
testApfStatsSerialization()415     public void testApfStatsSerialization() {
416         ConnectivityMetricsEvent ev = describeIpEvent(
417                 aType(ApfStats.class),
418                 aLong(45000),
419                 anInt(10),
420                 anInt(2),
421                 anInt(2),
422                 anInt(1),
423                 anInt(2),
424                 anInt(4),
425                 anInt(7),
426                 anInt(3),
427                 anInt(2048));
428 
429         String want = String.join("\n",
430                 "dropped_events: 0",
431                 "events <",
432                 "  if_name: \"\"",
433                 "  link_layer: 0",
434                 "  network_id: 0",
435                 "  time_ms: 1",
436                 "  transports: 0",
437                 "  apf_statistics <",
438                 "    dropped_ras: 2",
439                 "    duration_ms: 45000",
440                 "    matching_ras: 2",
441                 "    max_program_size: 2048",
442                 "    parse_errors: 2",
443                 "    program_updates: 4",
444                 "    program_updates_all: 7",
445                 "    program_updates_allowing_multicast: 3",
446                 "    received_ras: 10",
447                 "    total_packet_dropped: 0",
448                 "    total_packet_processed: 0",
449                 "    zero_lifetime_ras: 1",
450                 "  >",
451                 ">",
452                 "version: 2\n");
453 
454         verifySerialization(want, ev);
455     }
456 
457     @Test
testRaEventSerialization()458     public void testRaEventSerialization() {
459         ConnectivityMetricsEvent ev = describeIpEvent(
460                 aType(RaEvent.class),
461                 aLong(2000),
462                 aLong(400),
463                 aLong(300),
464                 aLong(-1),
465                 aLong(1000),
466                 aLong(-1));
467 
468         String want = String.join("\n",
469                 "dropped_events: 0",
470                 "events <",
471                 "  if_name: \"\"",
472                 "  link_layer: 0",
473                 "  network_id: 0",
474                 "  time_ms: 1",
475                 "  transports: 0",
476                 "  ra_event <",
477                 "    dnssl_lifetime: -1",
478                 "    prefix_preferred_lifetime: 300",
479                 "    prefix_valid_lifetime: 400",
480                 "    rdnss_lifetime: 1000",
481                 "    route_info_lifetime: -1",
482                 "    router_lifetime: 2000",
483                 "  >",
484                 ">",
485                 "version: 2\n");
486 
487         verifySerialization(want, ev);
488     }
489 
490     @Test
testWakeupStatsSerialization()491     public void testWakeupStatsSerialization() {
492         WakeupStats stats = new WakeupStats("wlan0");
493         stats.totalWakeups = 14;
494         stats.applicationWakeups = 5;
495         stats.nonApplicationWakeups = 1;
496         stats.rootWakeups = 2;
497         stats.systemWakeups = 3;
498         stats.noUidWakeups = 3;
499         stats.l2UnicastCount = 5;
500         stats.l2MulticastCount = 1;
501         stats.l2BroadcastCount = 2;
502         stats.ethertypes.put(0x800, 3);
503         stats.ethertypes.put(0x86dd, 3);
504         stats.ipNextHeaders.put(6, 5);
505 
506 
507         IpConnectivityEvent got = IpConnectivityEventBuilder.toProto(stats);
508         String want = String.join("\n",
509                 "dropped_events: 0",
510                 "events <",
511                 "  if_name: \"\"",
512                 "  link_layer: 4",
513                 "  network_id: 0",
514                 "  time_ms: 0",
515                 "  transports: 0",
516                 "  wakeup_stats <",
517                 "    application_wakeups: 5",
518                 "    duration_sec: 0",
519                 "    ethertype_counts <",
520                 "      key: 2048",
521                 "      value: 3",
522                 "    >",
523                 "    ethertype_counts <",
524                 "      key: 34525",
525                 "      value: 3",
526                 "    >",
527                 "    ip_next_header_counts <",
528                 "      key: 6",
529                 "      value: 5",
530                 "    >",
531                 "    l2_broadcast_count: 2",
532                 "    l2_multicast_count: 1",
533                 "    l2_unicast_count: 5",
534                 "    no_uid_wakeups: 3",
535                 "    non_application_wakeups: 1",
536                 "    root_wakeups: 2",
537                 "    system_wakeups: 3",
538                 "    total_wakeups: 14",
539                 "  >",
540                 ">",
541                 "version: 2\n");
542 
543         verifySerialization(want, got);
544     }
545 
verifySerialization(String want, ConnectivityMetricsEvent... input)546     static void verifySerialization(String want, ConnectivityMetricsEvent... input) {
547         List<IpConnectivityEvent> protoInput =
548                 IpConnectivityEventBuilder.toProto(Arrays.asList(input));
549         verifySerialization(want, protoInput.toArray(new IpConnectivityEvent[0]));
550     }
551 
verifySerialization(String want, IpConnectivityEvent... input)552     static void verifySerialization(String want, IpConnectivityEvent... input) {
553         try {
554             byte[] got = IpConnectivityEventBuilder.serialize(0, Arrays.asList(input));
555             IpConnectivityLog log = IpConnectivityLog.parseFrom(got);
556             assertEquals(want, log.toString());
557         } catch (Exception e) {
558             fail(e.toString());
559         }
560     }
561 }
562