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_CONFIGURATION;
22 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_GENERIC;
23 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK;
24 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_INVALID_URI;
25 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE;
26 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED;
27 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_TIMEOUT;
28 import static android.net.wifi.EasyConnectStatusCallback.EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT;
29 
30 import android.net.wifi.EasyConnectStatusCallback;
31 import android.util.SparseIntArray;
32 
33 import com.android.internal.annotations.VisibleForTesting;
34 import com.android.server.wifi.nano.WifiMetricsProto;
35 import com.android.server.wifi.util.IntHistogram;
36 
37 import java.io.PrintWriter;
38 
39 /**
40  * Provides metrics for Wi-Fi Easy Connect (DPP). Metrics include number of initiator requests,
41  * number of successes, failures and time completion histogram.
42  */
43 public class DppMetrics {
44     private final WifiMetricsProto.WifiDppLog mWifiDppLogProto = new WifiMetricsProto.WifiDppLog();
45 
46     // Easy-Connect (DPP) Metrics
47     // Histogram for DPP operation time. Indicates the following 5 buckets (in seconds):
48     //   < 1
49     //   [1, 10)
50     //   [10, 25)
51     //   [25, 39)
52     //   >= 39  - which means timeout.
53     @VisibleForTesting
54     public static final int[] DPP_OPERATION_TIME = {1, 10, 25, 39};
55     private IntHistogram mHistogramDppOperationTime = new IntHistogram(DPP_OPERATION_TIME);
56 
57     // Failure codes
58     private SparseIntArray mHistogramDppFailureCode = new SparseIntArray();
59 
60     // Configurator success codes
61     private SparseIntArray mHistogramDppConfiguratorSuccessCode = new SparseIntArray();
62 
63     private final Object mLock = new Object();
64 
65     /**
66      * Update DPP Configurator-Initiator requests
67      */
updateDppConfiguratorInitiatorRequests()68     public void updateDppConfiguratorInitiatorRequests() {
69         synchronized (mLock) {
70             mWifiDppLogProto.numDppConfiguratorInitiatorRequests++;
71         }
72     }
73 
74     /**
75      * Update DPP Enrollee-Initiator requests
76      */
updateDppEnrolleeInitiatorRequests()77     public void updateDppEnrolleeInitiatorRequests() {
78         synchronized (mLock) {
79             mWifiDppLogProto.numDppEnrolleeInitiatorRequests++;
80         }
81     }
82 
83     /**
84      * Update DPP Enrollee success counter
85      */
updateDppEnrolleeSuccess()86     public void updateDppEnrolleeSuccess() {
87         synchronized (mLock) {
88             mWifiDppLogProto.numDppEnrolleeSuccess++;
89         }
90     }
91 
92     /**
93      * Update DPP Configurator success counter
94      */
updateDppConfiguratorSuccess( @asyConnectStatusCallback.EasyConnectSuccessStatusCode int code)95     public void updateDppConfiguratorSuccess(
96             @EasyConnectStatusCallback.EasyConnectSuccessStatusCode int code) {
97         synchronized (mLock) {
98             switch (code) {
99                 case EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT:
100                     mHistogramDppConfiguratorSuccessCode.put(WifiMetricsProto.WifiDppLog
101                                     .EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT,
102                             mHistogramDppConfiguratorSuccessCode.get(WifiMetricsProto.WifiDppLog
103                                     .EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT) + 1);
104                     break;
105                 default:
106                     break;
107             }
108         }
109     }
110 
111     /**
112      * Update DPP failure counters
113      */
updateDppFailure(@asyConnectStatusCallback.EasyConnectFailureStatusCode int code)114     public void updateDppFailure(@EasyConnectStatusCallback.EasyConnectFailureStatusCode int code) {
115         synchronized (mLock) {
116             switch (code) {
117                 case EASY_CONNECT_EVENT_FAILURE_INVALID_URI:
118                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
119                                     .EASY_CONNECT_EVENT_FAILURE_INVALID_URI,
120                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
121                                     .EASY_CONNECT_EVENT_FAILURE_INVALID_URI) + 1);
122                     break;
123                 case EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION:
124                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
125                                     .EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION,
126                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
127                                     .EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION) + 1);
128                     break;
129                 case EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE:
130                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
131                                     .EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE,
132                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
133                                     .EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE) + 1);
134                     break;
135                 case EASY_CONNECT_EVENT_FAILURE_CONFIGURATION:
136                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
137                                     .EASY_CONNECT_EVENT_FAILURE_CONFIGURATION,
138                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
139                                     .EASY_CONNECT_EVENT_FAILURE_CONFIGURATION) + 1);
140                     break;
141                 case EASY_CONNECT_EVENT_FAILURE_BUSY:
142                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
143                                     .EASY_CONNECT_EVENT_FAILURE_BUSY,
144                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
145                                     .EASY_CONNECT_EVENT_FAILURE_BUSY) + 1);
146                     break;
147                 case EASY_CONNECT_EVENT_FAILURE_TIMEOUT:
148                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
149                                     .EASY_CONNECT_EVENT_FAILURE_TIMEOUT,
150                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
151                                     .EASY_CONNECT_EVENT_FAILURE_TIMEOUT) + 1);
152                     break;
153                 case EASY_CONNECT_EVENT_FAILURE_GENERIC:
154                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
155                                     .EASY_CONNECT_EVENT_FAILURE_GENERIC,
156                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
157                                     .EASY_CONNECT_EVENT_FAILURE_GENERIC) + 1);
158                     break;
159                 case EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED:
160                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
161                                     .EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED,
162                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
163                                     .EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED) + 1);
164                     break;
165                 case EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK:
166                     mHistogramDppFailureCode.put(WifiMetricsProto.WifiDppLog
167                                     .EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK,
168                             mHistogramDppFailureCode.get(WifiMetricsProto.WifiDppLog
169                                     .EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK) + 1);
170                     break;
171                 default:
172                     break;
173             }
174         }
175     }
176 
177     /**
178      * Update DPP operation time
179      *
180      * @param timeMs Time it took to complete the operation, in milliseconds
181      */
updateDppOperationTime(int timeMs)182     public void updateDppOperationTime(int timeMs) {
183         synchronized (mLock) {
184             mHistogramDppOperationTime.increment(timeMs / 1000);
185         }
186     }
187 
188     /**
189      * Dump all DPP metrics
190      *
191      * @param pw PrintWriter handle
192      */
dump(PrintWriter pw)193     public void dump(PrintWriter pw) {
194         synchronized (mLock) {
195             pw.println("---Easy Connect/DPP metrics---");
196             pw.println("mWifiDppLogProto.numDppConfiguratorInitiatorRequests="
197                     + mWifiDppLogProto.numDppConfiguratorInitiatorRequests);
198             pw.println("mWifiDppLogProto.numDppEnrolleeInitiatorRequests="
199                     + mWifiDppLogProto.numDppEnrolleeInitiatorRequests);
200             pw.println("mWifiDppLogProto.numDppEnrolleeSuccess="
201                     + mWifiDppLogProto.numDppEnrolleeSuccess);
202 
203             if (mHistogramDppFailureCode.size() > 0) {
204                 pw.println("mHistogramDppFailureCode=");
205                 pw.println(mHistogramDppFailureCode);
206             }
207 
208             if (mHistogramDppConfiguratorSuccessCode.size() > 0) {
209                 pw.println("mHistogramDppConfiguratorSuccessCode=");
210                 pw.println(mHistogramDppConfiguratorSuccessCode);
211             }
212 
213             if (mHistogramDppOperationTime.numNonEmptyBuckets() > 0) {
214                 pw.println("mHistogramDppOperationTime=");
215                 pw.println(mHistogramDppOperationTime);
216             }
217             pw.println("---End of Easy Connect/DPP metrics---");
218         }
219     }
220 
221     /**
222      * Clear all DPP metrics
223      */
clear()224     public void clear() {
225         synchronized (mLock) {
226             mWifiDppLogProto.numDppConfiguratorInitiatorRequests = 0;
227             mWifiDppLogProto.numDppEnrolleeInitiatorRequests = 0;
228             mWifiDppLogProto.numDppEnrolleeSuccess = 0;
229             mHistogramDppFailureCode.clear();
230             mHistogramDppOperationTime.clear();
231             mHistogramDppConfiguratorSuccessCode.clear();
232         }
233     }
234 
consolidateDppFailure( SparseIntArray data)235     private WifiMetricsProto.WifiDppLog.DppFailureStatusHistogramBucket[] consolidateDppFailure(
236             SparseIntArray data) {
237         WifiMetricsProto.WifiDppLog.DppFailureStatusHistogramBucket[]
238                 dppFailureStatusHistogramBuckets =
239                 new WifiMetricsProto.WifiDppLog.DppFailureStatusHistogramBucket[data.size()];
240 
241         for (int i = 0; i < data.size(); i++) {
242             dppFailureStatusHistogramBuckets[i] =
243                     new WifiMetricsProto.WifiDppLog.DppFailureStatusHistogramBucket();
244             dppFailureStatusHistogramBuckets[i].dppStatusType = data.keyAt(i);
245             dppFailureStatusHistogramBuckets[i].count = data.valueAt(i);
246         }
247 
248         return dppFailureStatusHistogramBuckets;
249     }
250 
251     private WifiMetricsProto.WifiDppLog.DppConfiguratorSuccessStatusHistogramBucket[]
consolidateDppSuccess( SparseIntArray data)252             consolidateDppSuccess(
253             SparseIntArray data) {
254         WifiMetricsProto.WifiDppLog.DppConfiguratorSuccessStatusHistogramBucket[]
255                 dppConfiguratorSuccessStatusHistogramBuckets =
256                 new WifiMetricsProto.WifiDppLog
257                         .DppConfiguratorSuccessStatusHistogramBucket[data.size()];
258 
259         for (int i = 0; i < data.size(); i++) {
260             dppConfiguratorSuccessStatusHistogramBuckets[i] =
261                     new WifiMetricsProto.WifiDppLog.DppConfiguratorSuccessStatusHistogramBucket();
262             dppConfiguratorSuccessStatusHistogramBuckets[i].dppStatusType = data.keyAt(i);
263             dppConfiguratorSuccessStatusHistogramBuckets[i].count = data.valueAt(i);
264         }
265 
266         return dppConfiguratorSuccessStatusHistogramBuckets;
267     }
268 
269     /**
270      * Consolidate all metrics into the proto.
271      */
consolidateProto()272     public WifiMetricsProto.WifiDppLog consolidateProto() {
273         WifiMetricsProto.WifiDppLog log = new WifiMetricsProto.WifiDppLog();
274         synchronized (mLock) {
275             log.numDppConfiguratorInitiatorRequests =
276                     mWifiDppLogProto.numDppConfiguratorInitiatorRequests;
277             log.numDppEnrolleeInitiatorRequests = mWifiDppLogProto.numDppEnrolleeInitiatorRequests;
278             log.numDppEnrolleeSuccess = mWifiDppLogProto.numDppEnrolleeSuccess;
279             log.dppFailureCode = consolidateDppFailure(mHistogramDppFailureCode);
280             log.dppConfiguratorSuccessCode =
281                     consolidateDppSuccess(mHistogramDppConfiguratorSuccessCode);
282             log.dppOperationTime = mHistogramDppOperationTime.toProto();
283         }
284         return log;
285     }
286 }
287