1 /*
2  * Copyright (C) 2023 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.networkstack.metrics;
18 
19 import android.net.apf.ApfCounterTracker.Counter;
20 import android.stats.connectivity.CounterName;
21 
22 import androidx.annotation.VisibleForTesting;
23 
24 /**
25  * Class to record the network stack ApfSessionInfo metrics into statsd.
26  *
27  * This class is not thread-safe, and should always be accessed from the same thread.
28  *
29  * @hide
30  */
31 public class ApfSessionInfoMetrics {
32     // Define the maximum size of the counter list
33     public static final int MAX_NUM_OF_COUNTERS = Counter.class.getEnumConstants().length - 1;
34     private final ApfSessionInfoReported.Builder mStatsBuilder =
35             ApfSessionInfoReported.newBuilder();
36     private final ApfCounterList.Builder mApfCounterListBuilder = ApfCounterList.newBuilder();
37 
38     /**
39      * Write the version to mStatsBuilder.
40      */
setVersion(final int version)41     public void setVersion(final int version) {
42         mStatsBuilder.setVersion(version);
43     }
44 
45     /**
46      * Write the memory size to mStatsBuilder.
47      */
setMemorySize(final int memorySize)48     public void setMemorySize(final int memorySize) {
49         mStatsBuilder.setMemorySize(memorySize);
50     }
51 
52     /**
53      * Add an APF counter to the metrics builder.
54      */
addApfCounter(final Counter counter, final long value)55     public void addApfCounter(final Counter counter, final long value) {
56         if (mApfCounterListBuilder.getApfCounterCount() >= MAX_NUM_OF_COUNTERS) return;
57         final ApfCounter.Builder apfCounterBuilder = ApfCounter.newBuilder()
58                 .setCounterName(apfFilterCounterToEnum(counter))
59                 .setCounterValue(value);
60 
61         mApfCounterListBuilder.addApfCounter(apfCounterBuilder);
62     }
63 
64     /**
65      * Write the session duration to mStatsBuilder.
66      */
setApfSessionDurationSeconds(final int durationSeconds)67     public void setApfSessionDurationSeconds(final int durationSeconds) {
68         mStatsBuilder.setApfSessionDurationSeconds(durationSeconds);
69     }
70 
71     /**
72      * Write the number of times APF program updated to mStatsBuilder.
73      */
setNumOfTimesApfProgramUpdated(final int updatedTimes)74     public void setNumOfTimesApfProgramUpdated(final int updatedTimes) {
75         mStatsBuilder.setNumOfTimesApfProgramUpdated(updatedTimes);
76     }
77 
78     /**
79      * Write the maximum program size to mStatsBuilder.
80      */
setMaxProgramSize(final int programSize)81     public void setMaxProgramSize(final int programSize) {
82         mStatsBuilder.setMaxProgramSize(programSize);
83     }
84 
85     /**
86      * Write the ApfSessionInfoReported proto into statsd.
87      */
statsWrite()88     public ApfSessionInfoReported statsWrite() {
89         mStatsBuilder.setApfCounterList(mApfCounterListBuilder);
90         final ApfSessionInfoReported stats = mStatsBuilder.build();
91         final byte[] apfCounterList = stats.getApfCounterList().toByteArray();
92         NetworkStackStatsLog.write(NetworkStackStatsLog.APF_SESSION_INFO_REPORTED,
93                 stats.getVersion(),
94                 stats.getMemorySize(),
95                 apfCounterList,
96                 stats.getApfSessionDurationSeconds(),
97                 stats.getNumOfTimesApfProgramUpdated(),
98                 stats.getMaxProgramSize());
99         return stats;
100     }
101 
102     /**
103      *  Map ApfCounterTracker.Counter to {@link CounterName}.
104      */
105     @VisibleForTesting
apfFilterCounterToEnum(final Counter counter)106     public static CounterName apfFilterCounterToEnum(final Counter counter) {
107         switch(counter) {
108             case TOTAL_PACKETS:
109                 return CounterName.CN_TOTAL_PACKETS;
110             case PASSED_ARP:
111                 return CounterName.CN_PASSED_ARP;
112             case PASSED_DHCP:
113                 return CounterName.CN_PASSED_DHCP;
114             case PASSED_IPV4:
115                 return CounterName.CN_PASSED_IPV4;
116             case PASSED_IPV6_NON_ICMP:
117                 return CounterName.CN_PASSED_IPV6_NON_ICMP;
118             case PASSED_IPV4_UNICAST:
119                 return CounterName.CN_PASSED_IPV4_UNICAST;
120             case PASSED_IPV6_ICMP:
121                 return CounterName.CN_PASSED_IPV6_ICMP;
122             case PASSED_IPV6_UNICAST_NON_ICMP:
123                 return CounterName.CN_PASSED_IPV6_UNICAST_NON_ICMP;
124             // PASSED_ARP_NON_IPV4 and PASSED_ARP_UNKNOWN were deprecated in ApfFilter:
125             //     PASSED_ARP_NON_IPV4 ==> DROPPED_ARP_NON_IPV4
126             //     PASSED_ARP_UNKNOWN  ==> DROPPED_ARP_UNKNOWN
127             // They are not supported in the metrics.
128             case PASSED_ARP_NON_IPV4:
129             case PASSED_ARP_UNKNOWN:
130                 return CounterName.CN_UNKNOWN;
131             case PASSED_ARP_UNICAST_REPLY:
132                 return CounterName.CN_PASSED_ARP_UNICAST_REPLY;
133             case PASSED_NON_IP_UNICAST:
134                 return CounterName.CN_PASSED_NON_IP_UNICAST;
135             case PASSED_MDNS:
136                 return CounterName.CN_PASSED_MDNS;
137             case DROPPED_ETH_BROADCAST:
138                 return CounterName.CN_DROPPED_ETH_BROADCAST;
139             case DROPPED_RA:
140                 return CounterName.CN_DROPPED_RA;
141             case DROPPED_GARP_REPLY:
142                 return CounterName.CN_DROPPED_GARP_REPLY;
143             case DROPPED_ARP_OTHER_HOST:
144                 return CounterName.CN_DROPPED_ARP_OTHER_HOST;
145             case DROPPED_IPV4_L2_BROADCAST:
146                 return CounterName.CN_DROPPED_IPV4_L2_BROADCAST;
147             case DROPPED_IPV4_BROADCAST_ADDR:
148                 return CounterName.CN_DROPPED_IPV4_BROADCAST_ADDR;
149             case DROPPED_IPV4_BROADCAST_NET:
150                 return CounterName.CN_DROPPED_IPV4_BROADCAST_NET;
151             case DROPPED_IPV4_MULTICAST:
152                 return CounterName.CN_DROPPED_IPV4_MULTICAST;
153             case DROPPED_IPV6_ROUTER_SOLICITATION:
154                 return CounterName.CN_DROPPED_IPV6_ROUTER_SOLICITATION;
155             case DROPPED_IPV6_MULTICAST_NA:
156                 return CounterName.CN_DROPPED_IPV6_MULTICAST_NA;
157             case DROPPED_IPV6_MULTICAST:
158                 return CounterName.CN_DROPPED_IPV6_MULTICAST;
159             case DROPPED_IPV6_MULTICAST_PING:
160                 return CounterName.CN_DROPPED_IPV6_MULTICAST_PING;
161             case DROPPED_IPV6_NON_ICMP_MULTICAST:
162                 return CounterName.CN_DROPPED_IPV6_NON_ICMP_MULTICAST;
163             case DROPPED_802_3_FRAME:
164                 return CounterName.CN_DROPPED_802_3_FRAME;
165             case DROPPED_ETHERTYPE_NOT_ALLOWED:
166                 return CounterName.CN_DROPPED_ETHERTYPE_DENYLISTED;
167             case DROPPED_ARP_REPLY_SPA_NO_HOST:
168                 return CounterName.CN_DROPPED_ARP_REPLY_SPA_NO_HOST;
169             case DROPPED_IPV4_KEEPALIVE_ACK:
170                 return CounterName.CN_DROPPED_IPV4_KEEPALIVE_ACK;
171             case DROPPED_IPV6_KEEPALIVE_ACK:
172                 return CounterName.CN_DROPPED_IPV6_KEEPALIVE_ACK;
173             case DROPPED_IPV4_NATT_KEEPALIVE:
174                 return CounterName.CN_DROPPED_IPV4_NATT_KEEPALIVE;
175             case DROPPED_MDNS:
176                 return CounterName.CN_DROPPED_MDNS;
177             case DROPPED_IPV4_TCP_PORT7_UNICAST:
178                 // TODO: Not supported yet in the metrics backend.
179                 return CounterName.CN_UNKNOWN;
180             case DROPPED_ARP_NON_IPV4:
181                 return CounterName.CN_DROPPED_ARP_NON_IPV4;
182             case DROPPED_ARP_UNKNOWN:
183                 return CounterName.CN_DROPPED_ARP_UNKNOWN;
184             default:
185                 return CounterName.CN_UNKNOWN;
186         }
187     }
188 }
189