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