1 /*
2  * Copyright (C) 2019 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.wifi;
18 
19 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION;
20 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_BUSY;
21 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK;
22 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_CONFIGURATION;
23 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION;
24 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_ENROLLEE_FAILED_TO_SCAN_NETWORK_CHANNEL;
25 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION;
26 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_GENERIC;
27 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK;
28 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_INVALID_URI;
29 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE;
30 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED;
31 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_TIMEOUT;
32 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_URI_GENERATION;
33 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED;
34 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT;
35 
36 import android.net.wifi.EasyConnectStatusCallback;
37 import android.util.SparseIntArray;
38 
39 import com.android.internal.annotations.VisibleForTesting;
40 import com.android.server.wifi.proto.nano.WifiMetricsProto;
41 import com.android.server.wifi.util.IntHistogram;
42 
43 import java.io.PrintWriter;
44 
45 /**
46  * Provides metrics for Wi-Fi Easy Connect (DPP). Metrics include number of initiator requests,
47  * number of successes, failures and time completion histogram.
48  */
49 public class DppMetrics {
50     private final WifiMetricsProto.WifiDppLog mWifiDppLogProto = new WifiMetricsProto.WifiDppLog();
51 
52     // Easy-Connect (DPP) Metrics
53     // Histogram for DPP operation time. Indicates the following 5 buckets (in seconds):
54     //   < 1
55     //   [1, 10)
56     //   [10, 25)
57     //   [25, 39)
58     //   >= 39  - which means timeout.
59     @VisibleForTesting
60     public static final int[] DPP_OPERATION_TIME = {1, 10, 25, 39};
61     private IntHistogram mHistogramDppOperationTime = new IntHistogram(DPP_OPERATION_TIME);
62 
63     // Failure codes
64     private SparseIntArray mHistogramDppFailureCode = new SparseIntArray();
65 
66     // Configurator success codes
67     private SparseIntArray mHistogramDppConfiguratorSuccessCode = new SparseIntArray();
68 
69     private final Object mLock = new Object();
70 
71     /**
72      * Update DPP Configurator-Initiator requests
73      */
updateDppConfiguratorInitiatorRequests()74     public void updateDppConfiguratorInitiatorRequests() {
75         synchronized (mLock) {
76             mWifiDppLogProto.numDppConfiguratorInitiatorRequests++;
77         }
78     }
79 
80     /**
81      * Update DPP Enrollee-Initiator requests
82      */
updateDppEnrolleeInitiatorRequests()83     public void updateDppEnrolleeInitiatorRequests() {
84         synchronized (mLock) {
85             mWifiDppLogProto.numDppEnrolleeInitiatorRequests++;
86         }
87     }
88 
89     /**
90      * Update DPP Enrollee-Responder requests
91      */
updateDppEnrolleeResponderRequests()92     public void updateDppEnrolleeResponderRequests() {
93         synchronized (mLock) {
94             mWifiDppLogProto.numDppEnrolleeResponderRequests++;
95         }
96     }
97 
98     /**
99      * Update DPP Enrollee-Responder success counter
100      */
updateDppEnrolleeResponderSuccess()101     public void updateDppEnrolleeResponderSuccess() {
102         synchronized (mLock) {
103             mWifiDppLogProto.numDppEnrolleeResponderSuccess++;
104         }
105     }
106 
107     /**
108      * Update DPP Enrollee success counter
109      */
updateDppEnrolleeSuccess()110     public void updateDppEnrolleeSuccess() {
111         synchronized (mLock) {
112             mWifiDppLogProto.numDppEnrolleeSuccess++;
113         }
114     }
115 
116     /**
117      * Update number of DPP R1 capable enrollee responder devices.
118      */
updateDppR1CapableEnrolleeResponderDevices()119     public void updateDppR1CapableEnrolleeResponderDevices() {
120         synchronized (mLock) {
121             mWifiDppLogProto.numDppR1CapableEnrolleeResponderDevices++;
122         }
123     }
124 
125     /**
126      * Update number of DPP R2 capable enrollee responder devices.
127      */
updateDppR2CapableEnrolleeResponderDevices()128     public void updateDppR2CapableEnrolleeResponderDevices() {
129         synchronized (mLock) {
130             mWifiDppLogProto.numDppR2CapableEnrolleeResponderDevices++;
131         }
132     }
133 
134     /**
135      * Update number of times DPP R2 compatibility check detected
136      * that enrollee responder device is incompatible with the
137      * network.
138      */
updateDppR2EnrolleeResponderIncompatibleConfiguration()139     public void updateDppR2EnrolleeResponderIncompatibleConfiguration() {
140         synchronized (mLock) {
141             mWifiDppLogProto.numDppR2EnrolleeResponderIncompatibleConfiguration++;
142         }
143     }
144 
145     /**
146      * Update DPP Configurator success counter
147      */
updateDppConfiguratorSuccess( @asyConnectStatusCallback.EasyConnectSuccessStatusCode int code)148     public void updateDppConfiguratorSuccess(
149             @EasyConnectStatusCallback.EasyConnectSuccessStatusCode int code) {
150         synchronized (mLock) {
151             switch (code) {
152                 case EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT:
153                     mHistogramDppConfiguratorSuccessCode.put(WifiMetricsProto.WifiDppLog
154                                     .EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT,
155                             mHistogramDppConfiguratorSuccessCode.get(WifiMetricsProto.WifiDppLog
156                                     .EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT) + 1);
157                     break;
158                 case EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED:
159                     mHistogramDppConfiguratorSuccessCode.put(WifiMetricsProto.WifiDppLog
160                                     .EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED,
161                             mHistogramDppConfiguratorSuccessCode.get(WifiMetricsProto.WifiDppLog
162                                     .EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED) + 1);
163                     break;
164                 default:
165                     break;
166             }
167         }
168     }
169 
170     /**
171      * Update DPP failure counters
172      */
updateDppFailure(@asyConnectStatusCallback.EasyConnectFailureStatusCode int code)173     public void updateDppFailure(@EasyConnectStatusCallback.EasyConnectFailureStatusCode int code) {
174         synchronized (mLock) {
175             switch (code) {
176                 case EASY_CONNECT_EVENT_FAILURE_INVALID_URI:
177                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
178                                     .EASY_CONNECT_EVENT_FAILURE_INVALID_URI,
179                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
180                                     .EASY_CONNECT_EVENT_FAILURE_INVALID_URI) + 1);
181                     break;
182                 case EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION:
183                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
184                                     .EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION,
185                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
186                                     .EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION) + 1);
187                     break;
188                 case EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE:
189                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
190                                     .EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE,
191                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
192                                     .EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE) + 1);
193                     break;
194                 case EASY_CONNECT_EVENT_FAILURE_CONFIGURATION:
195                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
196                                     .EASY_CONNECT_EVENT_FAILURE_CONFIGURATION,
197                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
198                                     .EASY_CONNECT_EVENT_FAILURE_CONFIGURATION) + 1);
199                     break;
200                 case EASY_CONNECT_EVENT_FAILURE_BUSY:
201                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
202                                     .EASY_CONNECT_EVENT_FAILURE_BUSY,
203                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
204                                     .EASY_CONNECT_EVENT_FAILURE_BUSY) + 1);
205                     break;
206                 case EASY_CONNECT_EVENT_FAILURE_TIMEOUT:
207                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
208                                     .EASY_CONNECT_EVENT_FAILURE_TIMEOUT,
209                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
210                                     .EASY_CONNECT_EVENT_FAILURE_TIMEOUT) + 1);
211                     break;
212                 case EASY_CONNECT_EVENT_FAILURE_GENERIC:
213                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
214                                     .EASY_CONNECT_EVENT_FAILURE_GENERIC,
215                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
216                                     .EASY_CONNECT_EVENT_FAILURE_GENERIC) + 1);
217                     break;
218                 case EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED:
219                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
220                                     .EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED,
221                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
222                                     .EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED) + 1);
223                     break;
224                 case EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK:
225                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
226                                     .EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK,
227                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
228                                     .EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK) + 1);
229                     break;
230                 case EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK:
231                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
232                                     .EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK,
233                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
234                                     .EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK) + 1);
235                     break;
236                 case EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION:
237                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
238                                     .EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION,
239                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
240                                     .EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION) + 1);
241                     break;
242                 case EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION:
243                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
244                                     .EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION,
245                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
246                                     .EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION)
247                                     + 1);
248                     break;
249                 case EASY_CONNECT_EVENT_FAILURE_URI_GENERATION:
250                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
251                                     .EASY_CONNECT_EVENT_FAILURE_URI_GENERATION,
252                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
253                                     .EASY_CONNECT_EVENT_FAILURE_URI_GENERATION) + 1);
254                     break;
255                 case EASY_CONNECT_EVENT_FAILURE_ENROLLEE_FAILED_TO_SCAN_NETWORK_CHANNEL:
256                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
257                             .EASY_CONNECT_EVENT_FAILURE_ENROLLEE_FAILED_TO_SCAN_NETWORK_CHANNEL,
258                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
259                             .EASY_CONNECT_EVENT_FAILURE_ENROLLEE_FAILED_TO_SCAN_NETWORK_CHANNEL)
260                             + 1);
261                     break;
262                 default:
263                     break;
264             }
265         }
266     }
267 
268     /**
269      * Update DPP operation time
270      *
271      * @param timeMs Time it took to complete the operation, in milliseconds
272      */
updateDppOperationTime(int timeMs)273     public void updateDppOperationTime(int timeMs) {
274         synchronized (mLock) {
275             mHistogramDppOperationTime.increment(timeMs / 1000);
276         }
277     }
278 
279     /**
280      * Dump all DPP metrics
281      *
282      * @param pw PrintWriter handle
283      */
dump(PrintWriter pw)284     public void dump(PrintWriter pw) {
285         synchronized (mLock) {
286             pw.println("---Easy Connect/DPP metrics---");
287             pw.println("mWifiDppLogProto.numDppConfiguratorInitiatorRequests="
288                     + mWifiDppLogProto.numDppConfiguratorInitiatorRequests);
289             pw.println("mWifiDppLogProto.numDppEnrolleeInitiatorRequests="
290                     + mWifiDppLogProto.numDppEnrolleeInitiatorRequests);
291             pw.println("mWifiDppLogProto.numDppEnrolleeResponderRequests="
292                     + mWifiDppLogProto.numDppEnrolleeResponderRequests);
293             pw.println("mWifiDppLogProto.numDppEnrolleeResponderSuccess="
294                     + mWifiDppLogProto.numDppEnrolleeResponderSuccess);
295             pw.println("mWifiDppLogProto.numDppEnrolleeSuccess="
296                     + mWifiDppLogProto.numDppEnrolleeSuccess);
297             pw.println("mWifiDppLogProto.numDppR1CapableEnrolleeResponderDevices="
298                     + mWifiDppLogProto.numDppR1CapableEnrolleeResponderDevices);
299             pw.println("mWifiDppLogProto.numDppR2CapableEnrolleeResponderDevices="
300                     + mWifiDppLogProto.numDppR2CapableEnrolleeResponderDevices);
301             pw.println("mWifiDppLogProto.numDppR2EnrolleeResponderIncompatibleConfiguration="
302                     + mWifiDppLogProto.numDppR2EnrolleeResponderIncompatibleConfiguration);
303 
304             if (mHistogramDppFailureCode.size() > 0) {
305                 pw.println("mHistogramDppFailureCode=");
306                 pw.println(mHistogramDppFailureCode);
307             }
308 
309             if (mHistogramDppConfiguratorSuccessCode.size() > 0) {
310                 pw.println("mHistogramDppConfiguratorSuccessCode=");
311                 pw.println(mHistogramDppConfiguratorSuccessCode);
312             }
313 
314             if (mHistogramDppOperationTime.numNonEmptyBuckets() > 0) {
315                 pw.println("mHistogramDppOperationTime=");
316                 pw.println(mHistogramDppOperationTime);
317             }
318             pw.println("---End of Easy Connect/DPP metrics---");
319         }
320     }
321 
322     /**
323      * Clear all DPP metrics
324      */
clear()325     public void clear() {
326         synchronized (mLock) {
327             mWifiDppLogProto.numDppConfiguratorInitiatorRequests = 0;
328             mWifiDppLogProto.numDppEnrolleeInitiatorRequests = 0;
329             mWifiDppLogProto.numDppEnrolleeResponderRequests = 0;
330             mWifiDppLogProto.numDppEnrolleeResponderSuccess = 0;
331             mWifiDppLogProto.numDppEnrolleeSuccess = 0;
332             mWifiDppLogProto.numDppR1CapableEnrolleeResponderDevices = 0;
333             mWifiDppLogProto.numDppR2CapableEnrolleeResponderDevices = 0;
334             mWifiDppLogProto.numDppR2EnrolleeResponderIncompatibleConfiguration = 0;
335             mHistogramDppFailureCode.clear();
336             mHistogramDppOperationTime.clear();
337             mHistogramDppConfiguratorSuccessCode.clear();
338         }
339     }
340 
consolidateDppFailure( SparseIntArray data)341     private WifiMetricsProto.WifiDppLog.DppFailureStatusHistogramBucket[] consolidateDppFailure(
342             SparseIntArray data) {
343         WifiMetricsProto.WifiDppLog.DppFailureStatusHistogramBucket[]
344                 dppFailureStatusHistogramBuckets =
345                 new WifiMetricsProto.WifiDppLog.DppFailureStatusHistogramBucket[data.size()];
346 
347         for (int i = 0; i < data.size(); i++) {
348             dppFailureStatusHistogramBuckets[i] =
349                     new WifiMetricsProto.WifiDppLog.DppFailureStatusHistogramBucket();
350             dppFailureStatusHistogramBuckets[i].dppStatusType = data.keyAt(i);
351             dppFailureStatusHistogramBuckets[i].count = data.valueAt(i);
352         }
353 
354         return dppFailureStatusHistogramBuckets;
355     }
356 
357     private WifiMetricsProto.WifiDppLog.DppConfiguratorSuccessStatusHistogramBucket[]
consolidateDppSuccess( SparseIntArray data)358             consolidateDppSuccess(
359             SparseIntArray data) {
360         WifiMetricsProto.WifiDppLog.DppConfiguratorSuccessStatusHistogramBucket[]
361                 dppConfiguratorSuccessStatusHistogramBuckets =
362                 new WifiMetricsProto.WifiDppLog
363                         .DppConfiguratorSuccessStatusHistogramBucket[data.size()];
364 
365         for (int i = 0; i < data.size(); i++) {
366             dppConfiguratorSuccessStatusHistogramBuckets[i] =
367                     new WifiMetricsProto.WifiDppLog.DppConfiguratorSuccessStatusHistogramBucket();
368             dppConfiguratorSuccessStatusHistogramBuckets[i].dppStatusType = data.keyAt(i);
369             dppConfiguratorSuccessStatusHistogramBuckets[i].count = data.valueAt(i);
370         }
371 
372         return dppConfiguratorSuccessStatusHistogramBuckets;
373     }
374 
375     /**
376      * Consolidate all metrics into the proto.
377      */
consolidateProto()378     public WifiMetricsProto.WifiDppLog consolidateProto() {
379         WifiMetricsProto.WifiDppLog log = new WifiMetricsProto.WifiDppLog();
380         synchronized (mLock) {
381             log.numDppConfiguratorInitiatorRequests =
382                     mWifiDppLogProto.numDppConfiguratorInitiatorRequests;
383             log.numDppEnrolleeInitiatorRequests = mWifiDppLogProto.numDppEnrolleeInitiatorRequests;
384             log.numDppEnrolleeResponderRequests = mWifiDppLogProto.numDppEnrolleeResponderRequests;
385             log.numDppEnrolleeResponderSuccess = mWifiDppLogProto.numDppEnrolleeResponderSuccess;
386             log.numDppEnrolleeSuccess = mWifiDppLogProto.numDppEnrolleeSuccess;
387             log.numDppR1CapableEnrolleeResponderDevices =
388                     mWifiDppLogProto.numDppR1CapableEnrolleeResponderDevices;
389             log.numDppR2CapableEnrolleeResponderDevices =
390                     mWifiDppLogProto.numDppR2CapableEnrolleeResponderDevices;
391             log.numDppR2EnrolleeResponderIncompatibleConfiguration =
392                     mWifiDppLogProto.numDppR2EnrolleeResponderIncompatibleConfiguration;
393             log.dppFailureCode = consolidateDppFailure(mHistogramDppFailureCode);
394             log.dppConfiguratorSuccessCode =
395                     consolidateDppSuccess(mHistogramDppConfiguratorSuccessCode);
396             log.dppOperationTime = mHistogramDppOperationTime.toProto();
397         }
398         return log;
399     }
400 }
401