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.wifi;
18 
19 import static java.lang.StrictMath.toIntExact;
20 
21 import android.content.Context;
22 import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback;
23 import android.net.NetworkAgent;
24 import android.net.wifi.EAPConstants;
25 import android.net.wifi.IOnWifiUsabilityStatsListener;
26 import android.net.wifi.ScanResult;
27 import android.net.wifi.SupplicantState;
28 import android.net.wifi.WifiConfiguration;
29 import android.net.wifi.WifiInfo;
30 import android.net.wifi.WifiManager;
31 import android.net.wifi.WifiManager.DeviceMobilityState;
32 import android.net.wifi.WifiUsabilityStatsEntry.ProbeStatus;
33 import android.net.wifi.hotspot2.PasspointConfiguration;
34 import android.net.wifi.hotspot2.ProvisioningCallback;
35 import android.os.Handler;
36 import android.os.IBinder;
37 import android.os.Looper;
38 import android.os.Message;
39 import android.os.RemoteException;
40 import android.os.SystemProperties;
41 import android.provider.Settings;
42 import android.telephony.TelephonyManager;
43 import android.util.ArrayMap;
44 import android.util.Base64;
45 import android.util.Log;
46 import android.util.Pair;
47 import android.util.SparseArray;
48 import android.util.SparseIntArray;
49 
50 import com.android.internal.annotations.VisibleForTesting;
51 import com.android.server.wifi.aware.WifiAwareMetrics;
52 import com.android.server.wifi.hotspot2.ANQPNetworkKey;
53 import com.android.server.wifi.hotspot2.NetworkDetail;
54 import com.android.server.wifi.hotspot2.PasspointManager;
55 import com.android.server.wifi.hotspot2.PasspointMatch;
56 import com.android.server.wifi.hotspot2.PasspointProvider;
57 import com.android.server.wifi.hotspot2.Utils;
58 import com.android.server.wifi.nano.WifiMetricsProto;
59 import com.android.server.wifi.nano.WifiMetricsProto.ConnectToNetworkNotificationAndActionCount;
60 import com.android.server.wifi.nano.WifiMetricsProto.DeviceMobilityStatePnoScanStats;
61 import com.android.server.wifi.nano.WifiMetricsProto.ExperimentValues;
62 import com.android.server.wifi.nano.WifiMetricsProto.LinkProbeStats;
63 import com.android.server.wifi.nano.WifiMetricsProto.LinkProbeStats.ExperimentProbeCounts;
64 import com.android.server.wifi.nano.WifiMetricsProto.LinkProbeStats.LinkProbeFailureReasonCount;
65 import com.android.server.wifi.nano.WifiMetricsProto.LinkSpeedCount;
66 import com.android.server.wifi.nano.WifiMetricsProto.NetworkSelectionExperimentDecisions;
67 import com.android.server.wifi.nano.WifiMetricsProto.PasspointProfileTypeCount;
68 import com.android.server.wifi.nano.WifiMetricsProto.PasspointProvisionStats;
69 import com.android.server.wifi.nano.WifiMetricsProto.PasspointProvisionStats.ProvisionFailureCount;
70 import com.android.server.wifi.nano.WifiMetricsProto.PnoScanMetrics;
71 import com.android.server.wifi.nano.WifiMetricsProto.SoftApConnectedClientsEvent;
72 import com.android.server.wifi.nano.WifiMetricsProto.StaEvent;
73 import com.android.server.wifi.nano.WifiMetricsProto.StaEvent.ConfigInfo;
74 import com.android.server.wifi.nano.WifiMetricsProto.WifiIsUnusableEvent;
75 import com.android.server.wifi.nano.WifiMetricsProto.WifiLinkLayerUsageStats;
76 import com.android.server.wifi.nano.WifiMetricsProto.WifiLockStats;
77 import com.android.server.wifi.nano.WifiMetricsProto.WifiNetworkRequestApiLog;
78 import com.android.server.wifi.nano.WifiMetricsProto.WifiNetworkSuggestionApiLog;
79 import com.android.server.wifi.nano.WifiMetricsProto.WifiToggleStats;
80 import com.android.server.wifi.nano.WifiMetricsProto.WifiUsabilityStats;
81 import com.android.server.wifi.nano.WifiMetricsProto.WifiUsabilityStatsEntry;
82 import com.android.server.wifi.nano.WifiMetricsProto.WpsMetrics;
83 import com.android.server.wifi.p2p.WifiP2pMetrics;
84 import com.android.server.wifi.rtt.RttMetrics;
85 import com.android.server.wifi.util.ExternalCallbackTracker;
86 import com.android.server.wifi.util.InformationElementUtil;
87 import com.android.server.wifi.util.IntCounter;
88 import com.android.server.wifi.util.IntHistogram;
89 import com.android.server.wifi.util.MetricsUtils;
90 import com.android.server.wifi.util.ObjectCounter;
91 import com.android.server.wifi.util.ScanResultUtil;
92 
93 import org.json.JSONArray;
94 import org.json.JSONException;
95 import org.json.JSONObject;
96 
97 import java.io.FileDescriptor;
98 import java.io.PrintWriter;
99 import java.util.ArrayList;
100 import java.util.BitSet;
101 import java.util.Calendar;
102 import java.util.HashMap;
103 import java.util.HashSet;
104 import java.util.LinkedList;
105 import java.util.List;
106 import java.util.Map;
107 import java.util.Random;
108 import java.util.Set;
109 
110 /**
111  * Provides storage for wireless connectivity metrics, as they are generated.
112  * Metrics logged by this class include:
113  *   Aggregated connection stats (num of connections, num of failures, ...)
114  *   Discrete connection event stats (time, duration, failure codes, ...)
115  *   Router details (technology type, authentication type, ...)
116  *   Scan stats
117  */
118 public class WifiMetrics {
119     private static final String TAG = "WifiMetrics";
120     private static final boolean DBG = false;
121     /**
122      * Clamp the RSSI poll counts to values between [MIN,MAX]_RSSI_POLL
123      */
124     private static final int MAX_RSSI_POLL = 0;
125     private static final int MIN_RSSI_POLL = -127;
126     public static final int MAX_RSSI_DELTA = 127;
127     public static final int MIN_RSSI_DELTA = -127;
128     /** Minimum link speed (Mbps) to count for link_speed_counts */
129     public static final int MIN_LINK_SPEED_MBPS = 0;
130     /** Maximum time period between ScanResult and RSSI poll to generate rssi delta datapoint */
131     public static final long TIMEOUT_RSSI_DELTA_MILLIS =  3000;
132     private static final int MIN_WIFI_SCORE = 0;
133     private static final int MAX_WIFI_SCORE = NetworkAgent.WIFI_BASE_SCORE;
134     private static final int MIN_WIFI_USABILITY_SCORE = 0; // inclusive
135     private static final int MAX_WIFI_USABILITY_SCORE = 100; // inclusive
136     @VisibleForTesting
137     static final int LOW_WIFI_SCORE = 50; // Mobile data score
138     @VisibleForTesting
139     static final int LOW_WIFI_USABILITY_SCORE = 50; // Mobile data score
140     private final Object mLock = new Object();
141     private static final int MAX_CONNECTION_EVENTS = 256;
142     // Largest bucket in the NumConnectableNetworkCount histogram,
143     // anything large will be stored in this bucket
144     public static final int MAX_CONNECTABLE_SSID_NETWORK_BUCKET = 20;
145     public static final int MAX_CONNECTABLE_BSSID_NETWORK_BUCKET = 50;
146     public static final int MAX_TOTAL_SCAN_RESULT_SSIDS_BUCKET = 100;
147     public static final int MAX_TOTAL_SCAN_RESULTS_BUCKET = 250;
148     public static final int MAX_TOTAL_PASSPOINT_APS_BUCKET = 50;
149     public static final int MAX_TOTAL_PASSPOINT_UNIQUE_ESS_BUCKET = 20;
150     public static final int MAX_PASSPOINT_APS_PER_UNIQUE_ESS_BUCKET = 50;
151     public static final int MAX_TOTAL_80211MC_APS_BUCKET = 20;
152     private static final int CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER = 1000;
153     // Max limit for number of soft AP related events, extra events will be dropped.
154     private static final int MAX_NUM_SOFT_AP_EVENTS = 256;
155     // Maximum number of WifiIsUnusableEvent
156     public static final int MAX_UNUSABLE_EVENTS = 20;
157     // Minimum time wait before generating next WifiIsUnusableEvent from data stall
158     public static final int MIN_DATA_STALL_WAIT_MS = 120 * 1000; // 2 minutes
159     private static final int WIFI_IS_UNUSABLE_EVENT_METRICS_ENABLED_DEFAULT = 1; // 1 = true
160     private static final int WIFI_LINK_SPEED_METRICS_ENABLED_DEFAULT = 1; // 1 = true
161     // Max number of WifiUsabilityStatsEntry elements to store in the ringbuffer.
162     public static final int MAX_WIFI_USABILITY_STATS_ENTRIES_LIST_SIZE = 40;
163     // Max number of WifiUsabilityStats elements to store for each type.
164     public static final int MAX_WIFI_USABILITY_STATS_LIST_SIZE_PER_TYPE = 10;
165     // Max number of WifiUsabilityStats per labeled type to upload to server
166     public static final int MAX_WIFI_USABILITY_STATS_PER_TYPE_TO_UPLOAD = 2;
167     public static final int NUM_WIFI_USABILITY_STATS_ENTRIES_PER_WIFI_GOOD = 100;
168     public static final int MIN_WIFI_GOOD_USABILITY_STATS_PERIOD_MS = 1000 * 3600; // 1 hour
169     // Histogram for WifiConfigStore IO duration times. Indicates the following 5 buckets (in ms):
170     //   < 50
171     //   [50, 100)
172     //   [100, 150)
173     //   [150, 200)
174     //   [200, 300)
175     //   >= 300
176     private static final int[] WIFI_CONFIG_STORE_IO_DURATION_BUCKET_RANGES_MS =
177             {50, 100, 150, 200, 300};
178     // Minimum time wait before generating a LABEL_GOOD stats after score breaching low.
179     public static final int MIN_SCORE_BREACH_TO_GOOD_STATS_WAIT_TIME_MS = 60 * 1000; // 1 minute
180     // Maximum time that a score breaching low event stays valid.
181     public static final int VALIDITY_PERIOD_OF_SCORE_BREACH_LOW_MS = 90 * 1000; // 1.5 minutes
182 
183     private Clock mClock;
184     private boolean mScreenOn;
185     private int mWifiState;
186     private WifiAwareMetrics mWifiAwareMetrics;
187     private RttMetrics mRttMetrics;
188     private final PnoScanMetrics mPnoScanMetrics = new PnoScanMetrics();
189     private final WifiLinkLayerUsageStats mWifiLinkLayerUsageStats = new WifiLinkLayerUsageStats();
190     private final WpsMetrics mWpsMetrics = new WpsMetrics();
191     private final ExperimentValues mExperimentValues = new ExperimentValues();
192     private Handler mHandler;
193     private ScoringParams mScoringParams;
194     private WifiConfigManager mWifiConfigManager;
195     private WifiNetworkSelector mWifiNetworkSelector;
196     private PasspointManager mPasspointManager;
197     private Context mContext;
198     private FrameworkFacade mFacade;
199     private WifiDataStall mWifiDataStall;
200     private WifiLinkLayerStats mLastLinkLayerStats;
201     private String mLastBssid;
202     private int mLastFrequency = -1;
203     private int mSeqNumInsideFramework = 0;
204     private int mLastWifiUsabilityScore = -1;
205     private int mLastWifiUsabilityScoreNoReset = -1;
206     private int mLastPredictionHorizonSec = -1;
207     private int mLastPredictionHorizonSecNoReset = -1;
208     private int mSeqNumToFramework = -1;
209     @ProbeStatus private int mProbeStatusSinceLastUpdate =
210             android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE;
211     private int mProbeElapsedTimeSinceLastUpdateMs = -1;
212     private int mProbeMcsRateSinceLastUpdate = -1;
213     private long mScoreBreachLowTimeMillis = -1;
214 
215     public static final int MAX_STA_EVENTS = 768;
216     private LinkedList<StaEventWithTime> mStaEventList = new LinkedList<>();
217     private int mLastPollRssi = -127;
218     private int mLastPollLinkSpeed = -1;
219     private int mLastPollFreq = -1;
220     private int mLastScore = -1;
221 
222     /** Tracks if we should be logging WifiIsUnusableEvent */
223     private boolean mUnusableEventLogging = false;
224     /** Tracks if we should be logging LinkSpeedCounts */
225     private boolean mLinkSpeedCountsLogging = true;
226 
227     /**
228      * Metrics are stored within an instance of the WifiLog proto during runtime,
229      * The ConnectionEvent, SystemStateEntries & ScanReturnEntries metrics are stored during
230      * runtime in member lists of this WifiMetrics class, with the final WifiLog proto being pieced
231      * together at dump-time
232      */
233     private final WifiMetricsProto.WifiLog mWifiLogProto = new WifiMetricsProto.WifiLog();
234     /**
235      * Session information that gets logged for every Wifi connection attempt.
236      */
237     private final List<ConnectionEvent> mConnectionEventList = new ArrayList<>();
238     /**
239      * The latest started (but un-ended) connection attempt
240      */
241     private ConnectionEvent mCurrentConnectionEvent;
242     /**
243      * Count of number of times each scan return code, indexed by WifiLog.ScanReturnCode
244      */
245     private final SparseIntArray mScanReturnEntries = new SparseIntArray();
246     /**
247      * Mapping of system state to the counts of scans requested in that wifi state * screenOn
248      * combination. Indexed by WifiLog.WifiState * (1 + screenOn)
249      */
250     private final SparseIntArray mWifiSystemStateEntries = new SparseIntArray();
251     /** Mapping of channel frequency to its RSSI distribution histogram **/
252     private final Map<Integer, SparseIntArray> mRssiPollCountsMap = new HashMap<>();
253     /** Mapping of RSSI scan-poll delta values to counts. */
254     private final SparseIntArray mRssiDeltaCounts = new SparseIntArray();
255     /** Mapping of link speed values to LinkSpeedCount objects. */
256     private final SparseArray<LinkSpeedCount> mLinkSpeedCounts = new SparseArray<>();
257     /** RSSI of the scan result for the last connection event*/
258     private int mScanResultRssi = 0;
259     /** Boot-relative timestamp when the last candidate scanresult was received, used to calculate
260         RSSI deltas. -1 designates no candidate scanResult being tracked */
261     private long mScanResultRssiTimestampMillis = -1;
262     /** Mapping of alert reason to the respective alert count. */
263     private final SparseIntArray mWifiAlertReasonCounts = new SparseIntArray();
264     /**
265      * Records the getElapsedSinceBootMillis (in seconds) that represents the beginning of data
266      * capture for for this WifiMetricsProto
267      */
268     private long mRecordStartTimeSec;
269     /** Mapping of Wifi Scores to counts */
270     private final SparseIntArray mWifiScoreCounts = new SparseIntArray();
271     /** Mapping of Wifi Usability Scores to counts */
272     private final SparseIntArray mWifiUsabilityScoreCounts = new SparseIntArray();
273     /** Mapping of SoftApManager start SoftAp return codes to counts */
274     private final SparseIntArray mSoftApManagerReturnCodeCounts = new SparseIntArray();
275 
276     private final SparseIntArray mTotalSsidsInScanHistogram = new SparseIntArray();
277     private final SparseIntArray mTotalBssidsInScanHistogram = new SparseIntArray();
278     private final SparseIntArray mAvailableOpenSsidsInScanHistogram = new SparseIntArray();
279     private final SparseIntArray mAvailableOpenBssidsInScanHistogram = new SparseIntArray();
280     private final SparseIntArray mAvailableSavedSsidsInScanHistogram = new SparseIntArray();
281     private final SparseIntArray mAvailableSavedBssidsInScanHistogram = new SparseIntArray();
282     private final SparseIntArray mAvailableOpenOrSavedSsidsInScanHistogram = new SparseIntArray();
283     private final SparseIntArray mAvailableOpenOrSavedBssidsInScanHistogram = new SparseIntArray();
284     private final SparseIntArray mAvailableSavedPasspointProviderProfilesInScanHistogram =
285             new SparseIntArray();
286     private final SparseIntArray mAvailableSavedPasspointProviderBssidsInScanHistogram =
287             new SparseIntArray();
288 
289     private final IntCounter mInstalledPasspointProfileTypeForR1 = new IntCounter();
290     private final IntCounter mInstalledPasspointProfileTypeForR2 = new IntCounter();
291 
292     /** Mapping of "Connect to Network" notifications to counts. */
293     private final SparseIntArray mConnectToNetworkNotificationCount = new SparseIntArray();
294     /** Mapping of "Connect to Network" notification user actions to counts. */
295     private final SparseIntArray mConnectToNetworkNotificationActionCount = new SparseIntArray();
296     private int mOpenNetworkRecommenderBlacklistSize = 0;
297     private boolean mIsWifiNetworksAvailableNotificationOn = false;
298     private int mNumOpenNetworkConnectMessageFailedToSend = 0;
299     private int mNumOpenNetworkRecommendationUpdates = 0;
300     /** List of soft AP events related to number of connected clients in tethered mode */
301     private final List<SoftApConnectedClientsEvent> mSoftApEventListTethered = new ArrayList<>();
302     /** List of soft AP events related to number of connected clients in local only mode */
303     private final List<SoftApConnectedClientsEvent> mSoftApEventListLocalOnly = new ArrayList<>();
304 
305     private final SparseIntArray mObservedHotspotR1ApInScanHistogram = new SparseIntArray();
306     private final SparseIntArray mObservedHotspotR2ApInScanHistogram = new SparseIntArray();
307     private final SparseIntArray mObservedHotspotR1EssInScanHistogram = new SparseIntArray();
308     private final SparseIntArray mObservedHotspotR2EssInScanHistogram = new SparseIntArray();
309     private final SparseIntArray mObservedHotspotR1ApsPerEssInScanHistogram = new SparseIntArray();
310     private final SparseIntArray mObservedHotspotR2ApsPerEssInScanHistogram = new SparseIntArray();
311 
312     private final SparseIntArray mObserved80211mcApInScanHistogram = new SparseIntArray();
313 
314     // link probing stats
315     private final IntCounter mLinkProbeSuccessRssiCounts = new IntCounter(-85, -65);
316     private final IntCounter mLinkProbeFailureRssiCounts = new IntCounter(-85, -65);
317     private final IntCounter mLinkProbeSuccessLinkSpeedCounts = new IntCounter();
318     private final IntCounter mLinkProbeFailureLinkSpeedCounts = new IntCounter();
319 
320     private static final int[] LINK_PROBE_TIME_SINCE_LAST_TX_SUCCESS_SECONDS_HISTOGRAM_BUCKETS =
321             {5, 15, 45, 135};
322     private final IntHistogram mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram =
323             new IntHistogram(LINK_PROBE_TIME_SINCE_LAST_TX_SUCCESS_SECONDS_HISTOGRAM_BUCKETS);
324     private final IntHistogram mLinkProbeFailureSecondsSinceLastTxSuccessHistogram =
325             new IntHistogram(LINK_PROBE_TIME_SINCE_LAST_TX_SUCCESS_SECONDS_HISTOGRAM_BUCKETS);
326 
327     private static final int[] LINK_PROBE_ELAPSED_TIME_MS_HISTOGRAM_BUCKETS =
328             {5, 10, 15, 20, 25, 50, 100, 200, 400, 800};
329     private final IntHistogram mLinkProbeSuccessElapsedTimeMsHistogram = new IntHistogram(
330             LINK_PROBE_ELAPSED_TIME_MS_HISTOGRAM_BUCKETS);
331     private final IntCounter mLinkProbeFailureReasonCounts = new IntCounter();
332 
333     /**
334      * Maps a String link probe experiment ID to the number of link probes that were sent for this
335      * experiment.
336      */
337     private final ObjectCounter<String> mLinkProbeExperimentProbeCounts = new ObjectCounter<>();
338     private int mLinkProbeStaEventCount = 0;
339     @VisibleForTesting static final int MAX_LINK_PROBE_STA_EVENTS = MAX_STA_EVENTS / 4;
340 
341     private final LinkedList<WifiUsabilityStatsEntry> mWifiUsabilityStatsEntriesList =
342             new LinkedList<>();
343     private final LinkedList<WifiUsabilityStats> mWifiUsabilityStatsListBad = new LinkedList<>();
344     private final LinkedList<WifiUsabilityStats> mWifiUsabilityStatsListGood = new LinkedList<>();
345     private int mWifiUsabilityStatsCounter = 0;
346     private final Random mRand = new Random();
347     private final ExternalCallbackTracker<IOnWifiUsabilityStatsListener> mOnWifiUsabilityListeners;
348 
349     private final SparseArray<DeviceMobilityStatePnoScanStats> mMobilityStatePnoStatsMap =
350             new SparseArray<>();
351     private int mCurrentDeviceMobilityState;
352     /**
353      * The timestamp of the start of the current device mobility state.
354      */
355     private long mCurrentDeviceMobilityStateStartMs;
356     /**
357      * The timestamp of when the PNO scan started in the current device mobility state.
358      */
359     private long mCurrentDeviceMobilityStatePnoScanStartMs;
360 
361     /** Wifi power metrics*/
362     private WifiPowerMetrics mWifiPowerMetrics;
363 
364     /** Wifi Wake metrics */
365     private final WifiWakeMetrics mWifiWakeMetrics = new WifiWakeMetrics();
366 
367     /** Wifi P2p metrics */
368     private final WifiP2pMetrics mWifiP2pMetrics;
369 
370     private boolean mIsMacRandomizationOn = false;
371 
372     /** DPP */
373     private final DppMetrics mDppMetrics;
374 
375     /** WifiConfigStore read duration histogram. */
376     private SparseIntArray mWifiConfigStoreReadDurationHistogram = new SparseIntArray();
377 
378     /** WifiConfigStore write duration histogram. */
379     private SparseIntArray mWifiConfigStoreWriteDurationHistogram = new SparseIntArray();
380 
381     /** New  API surface metrics */
382     private final WifiNetworkRequestApiLog mWifiNetworkRequestApiLog =
383             new WifiNetworkRequestApiLog();
384     private static final int[] NETWORK_REQUEST_API_MATCH_SIZE_HISTOGRAM_BUCKETS =
385             {0, 1, 5, 10};
386     private final IntHistogram mWifiNetworkRequestApiMatchSizeHistogram =
387             new IntHistogram(NETWORK_REQUEST_API_MATCH_SIZE_HISTOGRAM_BUCKETS);
388 
389     private final WifiNetworkSuggestionApiLog mWifiNetworkSuggestionApiLog =
390             new WifiNetworkSuggestionApiLog();
391     private static final int[] NETWORK_SUGGESTION_API_LIST_SIZE_HISTOGRAM_BUCKETS =
392             {5, 20, 50, 100, 500};
393     private final IntHistogram mWifiNetworkSuggestionApiListSizeHistogram =
394             new IntHistogram(NETWORK_SUGGESTION_API_LIST_SIZE_HISTOGRAM_BUCKETS);
395     private final WifiLockStats mWifiLockStats = new WifiLockStats();
396     private static final int[] WIFI_LOCK_SESSION_DURATION_HISTOGRAM_BUCKETS =
397             {1, 10, 60, 600, 3600};
398     private final WifiToggleStats mWifiToggleStats = new WifiToggleStats();
399 
400     private final IntHistogram mWifiLockHighPerfAcqDurationSecHistogram =
401             new IntHistogram(WIFI_LOCK_SESSION_DURATION_HISTOGRAM_BUCKETS);
402     private final IntHistogram mWifiLockLowLatencyAcqDurationSecHistogram =
403             new IntHistogram(WIFI_LOCK_SESSION_DURATION_HISTOGRAM_BUCKETS);
404 
405     private final IntHistogram mWifiLockHighPerfActiveSessionDurationSecHistogram =
406             new IntHistogram(WIFI_LOCK_SESSION_DURATION_HISTOGRAM_BUCKETS);
407     private final IntHistogram mWifiLockLowLatencyActiveSessionDurationSecHistogram =
408             new IntHistogram(WIFI_LOCK_SESSION_DURATION_HISTOGRAM_BUCKETS);
409 
410     /**
411      * (experiment1Id, experiment2Id) =>
412      *     (sameSelectionNumChoicesCounter, differentSelectionNumChoicesCounter)
413      */
414     private Map<Pair<Integer, Integer>, NetworkSelectionExperimentResults>
415             mNetworkSelectionExperimentPairNumChoicesCounts = new ArrayMap<>();
416 
417     private int mNetworkSelectorExperimentId;
418 
419     private final CellularLinkLayerStatsCollector mCellularLinkLayerStatsCollector;
420 
421     /**
422      * Tracks the nominator for each network (i.e. which entity made the suggestion to connect).
423      * This object should not be cleared.
424      */
425     private final SparseIntArray mNetworkIdToNominatorId = new SparseIntArray();
426 
427     /** passpoint provision success count */
428     private int mNumProvisionSuccess = 0;
429 
430     /** Mapping of failure code to the respective passpoint provision failure count. */
431     private final IntCounter mPasspointProvisionFailureCounts = new IntCounter();
432 
433     @VisibleForTesting
434     static class NetworkSelectionExperimentResults {
435         public static final int MAX_CHOICES = 10;
436 
437         public IntCounter sameSelectionNumChoicesCounter = new IntCounter(0, MAX_CHOICES);
438         public IntCounter differentSelectionNumChoicesCounter = new IntCounter(0, MAX_CHOICES);
439 
440         @Override
toString()441         public String toString() {
442             return "NetworkSelectionExperimentResults{"
443                     + "sameSelectionNumChoicesCounter="
444                     + sameSelectionNumChoicesCounter
445                     + ", differentSelectionNumChoicesCounter="
446                     + differentSelectionNumChoicesCounter
447                     + '}';
448         }
449     }
450 
451     class RouterFingerPrint {
452         private WifiMetricsProto.RouterFingerPrint mRouterFingerPrintProto;
RouterFingerPrint()453         RouterFingerPrint() {
454             mRouterFingerPrintProto = new WifiMetricsProto.RouterFingerPrint();
455         }
456 
toString()457         public String toString() {
458             StringBuilder sb = new StringBuilder();
459             synchronized (mLock) {
460                 sb.append("mConnectionEvent.roamType=" + mRouterFingerPrintProto.roamType);
461                 sb.append(", mChannelInfo=" + mRouterFingerPrintProto.channelInfo);
462                 sb.append(", mDtim=" + mRouterFingerPrintProto.dtim);
463                 sb.append(", mAuthentication=" + mRouterFingerPrintProto.authentication);
464                 sb.append(", mHidden=" + mRouterFingerPrintProto.hidden);
465                 sb.append(", mRouterTechnology=" + mRouterFingerPrintProto.routerTechnology);
466                 sb.append(", mSupportsIpv6=" + mRouterFingerPrintProto.supportsIpv6);
467             }
468             return sb.toString();
469         }
updateFromWifiConfiguration(WifiConfiguration config)470         public void updateFromWifiConfiguration(WifiConfiguration config) {
471             synchronized (mLock) {
472                 if (config != null) {
473                     // Is this a hidden network
474                     mRouterFingerPrintProto.hidden = config.hiddenSSID;
475                     // Config may not have a valid dtimInterval set yet, in which case dtim will be zero
476                     // (These are only populated from beacon frame scan results, which are returned as
477                     // scan results from the chip far less frequently than Probe-responses)
478                     if (config.dtimInterval > 0) {
479                         mRouterFingerPrintProto.dtim = config.dtimInterval;
480                     }
481                     mCurrentConnectionEvent.mConfigSsid = config.SSID;
482                     // Get AuthType information from config (We do this again from ScanResult after
483                     // associating with BSSID)
484                     if (config.allowedKeyManagement != null
485                             && config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) {
486                         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
487                                 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_OPEN;
488                     } else if (config.isEnterprise()) {
489                         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
490                                 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE;
491                     } else {
492                         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
493                                 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL;
494                     }
495                     mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
496                             .passpoint = config.isPasspoint();
497                     // If there's a ScanResult candidate associated with this config already, get it and
498                     // log (more accurate) metrics from it
499                     ScanResult candidate = config.getNetworkSelectionStatus().getCandidate();
500                     if (candidate != null) {
501                         updateMetricsFromScanResult(candidate);
502                     }
503                 }
504             }
505         }
506     }
507 
508     /**
509      * Log event, tracking the start time, end time and result of a wireless connection attempt.
510      */
511     class ConnectionEvent {
512         WifiMetricsProto.ConnectionEvent mConnectionEvent;
513         //<TODO> Move these constants into a wifi.proto Enum, and create a new Failure Type field
514         //covering more than just l2 failures. see b/27652362
515         /**
516          * Failure codes, used for the 'level_2_failure_code' Connection event field (covers a lot
517          * more failures than just l2 though, since the proto does not have a place to log
518          * framework failures)
519          */
520         // Failure is unknown
521         public static final int FAILURE_UNKNOWN = 0;
522         // NONE
523         public static final int FAILURE_NONE = 1;
524         // ASSOCIATION_REJECTION_EVENT
525         public static final int FAILURE_ASSOCIATION_REJECTION = 2;
526         // AUTHENTICATION_FAILURE_EVENT
527         public static final int FAILURE_AUTHENTICATION_FAILURE = 3;
528         // SSID_TEMP_DISABLED (Also Auth failure)
529         public static final int FAILURE_SSID_TEMP_DISABLED = 4;
530         // reconnect() or reassociate() call to WifiNative failed
531         public static final int FAILURE_CONNECT_NETWORK_FAILED = 5;
532         // NETWORK_DISCONNECTION_EVENT
533         public static final int FAILURE_NETWORK_DISCONNECTION = 6;
534         // NEW_CONNECTION_ATTEMPT before previous finished
535         public static final int FAILURE_NEW_CONNECTION_ATTEMPT = 7;
536         // New connection attempt to the same network & bssid
537         public static final int FAILURE_REDUNDANT_CONNECTION_ATTEMPT = 8;
538         // Roam Watchdog timer triggered (Roaming timed out)
539         public static final int FAILURE_ROAM_TIMEOUT = 9;
540         // DHCP failure
541         public static final int FAILURE_DHCP = 10;
542         // ASSOCIATION_TIMED_OUT
543         public static final int FAILURE_ASSOCIATION_TIMED_OUT = 11;
544 
545         RouterFingerPrint mRouterFingerPrint;
546         private long mRealStartTime;
547         private long mRealEndTime;
548         private String mConfigSsid;
549         private String mConfigBssid;
550         private int mWifiState;
551         private boolean mScreenOn;
552 
ConnectionEvent()553         private ConnectionEvent() {
554             mConnectionEvent = new WifiMetricsProto.ConnectionEvent();
555             mRealEndTime = 0;
556             mRealStartTime = 0;
557             mRouterFingerPrint = new RouterFingerPrint();
558             mConnectionEvent.routerFingerprint = mRouterFingerPrint.mRouterFingerPrintProto;
559             mConfigSsid = "<NULL>";
560             mConfigBssid = "<NULL>";
561             mWifiState = WifiMetricsProto.WifiLog.WIFI_UNKNOWN;
562             mScreenOn = false;
563         }
564 
toString()565         public String toString() {
566             StringBuilder sb = new StringBuilder();
567             sb.append("startTime=");
568             Calendar c = Calendar.getInstance();
569             synchronized (mLock) {
570                 c.setTimeInMillis(mConnectionEvent.startTimeMillis);
571                 sb.append(mConnectionEvent.startTimeMillis == 0 ? "            <null>" :
572                         String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
573                 sb.append(", SSID=");
574                 sb.append(mConfigSsid);
575                 sb.append(", BSSID=");
576                 sb.append(mConfigBssid);
577                 sb.append(", durationMillis=");
578                 sb.append(mConnectionEvent.durationTakenToConnectMillis);
579                 sb.append(", roamType=");
580                 switch(mConnectionEvent.roamType) {
581                     case 1:
582                         sb.append("ROAM_NONE");
583                         break;
584                     case 2:
585                         sb.append("ROAM_DBDC");
586                         break;
587                     case 3:
588                         sb.append("ROAM_ENTERPRISE");
589                         break;
590                     case 4:
591                         sb.append("ROAM_USER_SELECTED");
592                         break;
593                     case 5:
594                         sb.append("ROAM_UNRELATED");
595                         break;
596                     default:
597                         sb.append("ROAM_UNKNOWN");
598                 }
599                 sb.append(", connectionResult=");
600                 sb.append(mConnectionEvent.connectionResult);
601                 sb.append(", level2FailureCode=");
602                 switch(mConnectionEvent.level2FailureCode) {
603                     case FAILURE_NONE:
604                         sb.append("NONE");
605                         break;
606                     case FAILURE_ASSOCIATION_REJECTION:
607                         sb.append("ASSOCIATION_REJECTION");
608                         break;
609                     case FAILURE_AUTHENTICATION_FAILURE:
610                         sb.append("AUTHENTICATION_FAILURE");
611                         break;
612                     case FAILURE_SSID_TEMP_DISABLED:
613                         sb.append("SSID_TEMP_DISABLED");
614                         break;
615                     case FAILURE_CONNECT_NETWORK_FAILED:
616                         sb.append("CONNECT_NETWORK_FAILED");
617                         break;
618                     case FAILURE_NETWORK_DISCONNECTION:
619                         sb.append("NETWORK_DISCONNECTION");
620                         break;
621                     case FAILURE_NEW_CONNECTION_ATTEMPT:
622                         sb.append("NEW_CONNECTION_ATTEMPT");
623                         break;
624                     case FAILURE_REDUNDANT_CONNECTION_ATTEMPT:
625                         sb.append("REDUNDANT_CONNECTION_ATTEMPT");
626                         break;
627                     case FAILURE_ROAM_TIMEOUT:
628                         sb.append("ROAM_TIMEOUT");
629                         break;
630                     case FAILURE_DHCP:
631                         sb.append("DHCP");
632                         break;
633                     case FAILURE_ASSOCIATION_TIMED_OUT:
634                         sb.append("ASSOCIATION_TIMED_OUT");
635                         break;
636                     default:
637                         sb.append("UNKNOWN");
638                         break;
639                 }
640                 sb.append(", connectivityLevelFailureCode=");
641                 switch(mConnectionEvent.connectivityLevelFailureCode) {
642                     case WifiMetricsProto.ConnectionEvent.HLF_NONE:
643                         sb.append("NONE");
644                         break;
645                     case WifiMetricsProto.ConnectionEvent.HLF_DHCP:
646                         sb.append("DHCP");
647                         break;
648                     case WifiMetricsProto.ConnectionEvent.HLF_NO_INTERNET:
649                         sb.append("NO_INTERNET");
650                         break;
651                     case WifiMetricsProto.ConnectionEvent.HLF_UNWANTED:
652                         sb.append("UNWANTED");
653                         break;
654                     default:
655                         sb.append("UNKNOWN");
656                         break;
657                 }
658                 sb.append(", signalStrength=");
659                 sb.append(mConnectionEvent.signalStrength);
660                 sb.append(", wifiState=");
661                 switch(mWifiState) {
662                     case WifiMetricsProto.WifiLog.WIFI_DISABLED:
663                         sb.append("WIFI_DISABLED");
664                         break;
665                     case WifiMetricsProto.WifiLog.WIFI_DISCONNECTED:
666                         sb.append("WIFI_DISCONNECTED");
667                         break;
668                     case WifiMetricsProto.WifiLog.WIFI_ASSOCIATED:
669                         sb.append("WIFI_ASSOCIATED");
670                         break;
671                     default:
672                         sb.append("WIFI_UNKNOWN");
673                         break;
674                 }
675                 sb.append(", screenOn=");
676                 sb.append(mScreenOn);
677                 sb.append(", mRouterFingerprint=");
678                 sb.append(mRouterFingerPrint.toString());
679                 sb.append(", useRandomizedMac=");
680                 sb.append(mConnectionEvent.useRandomizedMac);
681                 sb.append(", connectionNominator=");
682                 switch (mConnectionEvent.connectionNominator) {
683                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_UNKNOWN:
684                         sb.append("NOMINATOR_UNKNOWN");
685                         break;
686                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_MANUAL:
687                         sb.append("NOMINATOR_MANUAL");
688                         break;
689                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_SAVED:
690                         sb.append("NOMINATOR_SAVED");
691                         break;
692                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_SUGGESTION:
693                         sb.append("NOMINATOR_SUGGESTION");
694                         break;
695                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_PASSPOINT:
696                         sb.append("NOMINATOR_PASSPOINT");
697                         break;
698                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_CARRIER:
699                         sb.append("NOMINATOR_CARRIER");
700                         break;
701                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_EXTERNAL_SCORED:
702                         sb.append("NOMINATOR_EXTERNAL_SCORED");
703                         break;
704                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_SPECIFIER:
705                         sb.append("NOMINATOR_SPECIFIER");
706                         break;
707                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_SAVED_USER_CONNECT_CHOICE:
708                         sb.append("NOMINATOR_SAVED_USER_CONNECT_CHOICE");
709                         break;
710                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_OPEN_NETWORK_AVAILABLE:
711                         sb.append("NOMINATOR_OPEN_NETWORK_AVAILABLE");
712                         break;
713                     default:
714                         sb.append(String.format("UnrecognizedNominator(%d)",
715                                 mConnectionEvent.connectionNominator));
716                 }
717                 sb.append(", networkSelectorExperimentId=");
718                 sb.append(mConnectionEvent.networkSelectorExperimentId);
719                 sb.append(", level2FailureReason=");
720                 switch(mConnectionEvent.level2FailureReason) {
721                     case WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_NONE:
722                         sb.append("AUTH_FAILURE_NONE");
723                         break;
724                     case WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_TIMEOUT:
725                         sb.append("AUTH_FAILURE_TIMEOUT");
726                         break;
727                     case WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_WRONG_PSWD:
728                         sb.append("AUTH_FAILURE_WRONG_PSWD");
729                         break;
730                     case WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_EAP_FAILURE:
731                         sb.append("AUTH_FAILURE_EAP_FAILURE");
732                         break;
733                     default:
734                         sb.append("FAILURE_REASON_UNKNOWN");
735                         break;
736                 }
737             }
738             return sb.toString();
739         }
740     }
741 
WifiMetrics(Context context, FrameworkFacade facade, Clock clock, Looper looper, WifiAwareMetrics awareMetrics, RttMetrics rttMetrics, WifiPowerMetrics wifiPowerMetrics, WifiP2pMetrics wifiP2pMetrics, DppMetrics dppMetrics, CellularLinkLayerStatsCollector cellularLinkLayerStatsCollector)742     public WifiMetrics(Context context, FrameworkFacade facade, Clock clock, Looper looper,
743             WifiAwareMetrics awareMetrics, RttMetrics rttMetrics,
744             WifiPowerMetrics wifiPowerMetrics, WifiP2pMetrics wifiP2pMetrics,
745             DppMetrics dppMetrics,
746             CellularLinkLayerStatsCollector cellularLinkLayerStatsCollector) {
747         mContext = context;
748         mFacade = facade;
749         mClock = clock;
750         mCurrentConnectionEvent = null;
751         mScreenOn = true;
752         mWifiState = WifiMetricsProto.WifiLog.WIFI_DISABLED;
753         mRecordStartTimeSec = mClock.getElapsedSinceBootMillis() / 1000;
754         mWifiAwareMetrics = awareMetrics;
755         mRttMetrics = rttMetrics;
756         mWifiPowerMetrics = wifiPowerMetrics;
757         mWifiP2pMetrics = wifiP2pMetrics;
758         mDppMetrics = dppMetrics;
759         mCellularLinkLayerStatsCollector = cellularLinkLayerStatsCollector;
760         loadSettings();
761         mHandler = new Handler(looper) {
762             public void handleMessage(Message msg) {
763                 synchronized (mLock) {
764                     processMessage(msg);
765                 }
766             }
767         };
768 
769         mCurrentDeviceMobilityState = WifiManager.DEVICE_MOBILITY_STATE_UNKNOWN;
770         DeviceMobilityStatePnoScanStats unknownStateStats =
771                 getOrCreateDeviceMobilityStatePnoScanStats(mCurrentDeviceMobilityState);
772         unknownStateStats.numTimesEnteredState++;
773         mCurrentDeviceMobilityStateStartMs = mClock.getElapsedSinceBootMillis();
774         mCurrentDeviceMobilityStatePnoScanStartMs = -1;
775         mOnWifiUsabilityListeners =
776                 new ExternalCallbackTracker<IOnWifiUsabilityStatsListener>(mHandler);
777     }
778 
779     /**
780      * Load setting values related to metrics logging.
781      */
782     @VisibleForTesting
loadSettings()783     public void loadSettings() {
784         int unusableEventFlag = mFacade.getIntegerSetting(
785                 mContext, Settings.Global.WIFI_IS_UNUSABLE_EVENT_METRICS_ENABLED,
786                 WIFI_IS_UNUSABLE_EVENT_METRICS_ENABLED_DEFAULT);
787         mUnusableEventLogging = (unusableEventFlag == 1);
788         setWifiIsUnusableLoggingEnabled(mUnusableEventLogging);
789         int linkSpeedCountsFlag = mFacade.getIntegerSetting(
790                 mContext, Settings.Global.WIFI_LINK_SPEED_METRICS_ENABLED,
791                 WIFI_LINK_SPEED_METRICS_ENABLED_DEFAULT);
792         mLinkSpeedCountsLogging = (linkSpeedCountsFlag == 1);
793         setLinkSpeedCountsLoggingEnabled(mLinkSpeedCountsLogging);
794         if (mWifiDataStall != null) {
795             mWifiDataStall.loadSettings();
796         }
797     }
798 
799     /** Sets internal ScoringParams member */
setScoringParams(ScoringParams scoringParams)800     public void setScoringParams(ScoringParams scoringParams) {
801         mScoringParams = scoringParams;
802     }
803 
804     /** Sets internal WifiConfigManager member */
setWifiConfigManager(WifiConfigManager wifiConfigManager)805     public void setWifiConfigManager(WifiConfigManager wifiConfigManager) {
806         mWifiConfigManager = wifiConfigManager;
807     }
808 
809     /** Sets internal WifiNetworkSelector member */
setWifiNetworkSelector(WifiNetworkSelector wifiNetworkSelector)810     public void setWifiNetworkSelector(WifiNetworkSelector wifiNetworkSelector) {
811         mWifiNetworkSelector = wifiNetworkSelector;
812     }
813 
814     /** Sets internal PasspointManager member */
setPasspointManager(PasspointManager passpointManager)815     public void setPasspointManager(PasspointManager passpointManager) {
816         mPasspointManager = passpointManager;
817     }
818 
819     /** Sets internal WifiDataStall member */
setWifiDataStall(WifiDataStall wifiDataStall)820     public void setWifiDataStall(WifiDataStall wifiDataStall) {
821         mWifiDataStall = wifiDataStall;
822     }
823 
824     /**
825      * Increment cumulative counters for link layer stats.
826      * @param newStats
827      */
incrementWifiLinkLayerUsageStats(WifiLinkLayerStats newStats)828     public void incrementWifiLinkLayerUsageStats(WifiLinkLayerStats newStats) {
829         if (newStats == null) {
830             return;
831         }
832         if (mLastLinkLayerStats == null) {
833             mLastLinkLayerStats = newStats;
834             return;
835         }
836         if (!newLinkLayerStatsIsValid(mLastLinkLayerStats, newStats)) {
837             // This could mean the radio chip is reset or the data is incorrectly reported.
838             // Don't increment any counts and discard the possibly corrupt |newStats| completely.
839             mLastLinkLayerStats = null;
840             return;
841         }
842         mWifiLinkLayerUsageStats.loggingDurationMs +=
843                 (newStats.timeStampInMs - mLastLinkLayerStats.timeStampInMs);
844         mWifiLinkLayerUsageStats.radioOnTimeMs += (newStats.on_time - mLastLinkLayerStats.on_time);
845         mWifiLinkLayerUsageStats.radioTxTimeMs += (newStats.tx_time - mLastLinkLayerStats.tx_time);
846         mWifiLinkLayerUsageStats.radioRxTimeMs += (newStats.rx_time - mLastLinkLayerStats.rx_time);
847         mWifiLinkLayerUsageStats.radioScanTimeMs +=
848                 (newStats.on_time_scan - mLastLinkLayerStats.on_time_scan);
849         mWifiLinkLayerUsageStats.radioNanScanTimeMs +=
850                 (newStats.on_time_nan_scan - mLastLinkLayerStats.on_time_nan_scan);
851         mWifiLinkLayerUsageStats.radioBackgroundScanTimeMs +=
852                 (newStats.on_time_background_scan - mLastLinkLayerStats.on_time_background_scan);
853         mWifiLinkLayerUsageStats.radioRoamScanTimeMs +=
854                 (newStats.on_time_roam_scan - mLastLinkLayerStats.on_time_roam_scan);
855         mWifiLinkLayerUsageStats.radioPnoScanTimeMs +=
856                 (newStats.on_time_pno_scan - mLastLinkLayerStats.on_time_pno_scan);
857         mWifiLinkLayerUsageStats.radioHs20ScanTimeMs +=
858                 (newStats.on_time_hs20_scan - mLastLinkLayerStats.on_time_hs20_scan);
859         mLastLinkLayerStats = newStats;
860     }
861 
newLinkLayerStatsIsValid(WifiLinkLayerStats oldStats, WifiLinkLayerStats newStats)862     private boolean newLinkLayerStatsIsValid(WifiLinkLayerStats oldStats,
863             WifiLinkLayerStats newStats) {
864         if (newStats.on_time < oldStats.on_time
865                 || newStats.tx_time < oldStats.tx_time
866                 || newStats.rx_time < oldStats.rx_time
867                 || newStats.on_time_scan < oldStats.on_time_scan) {
868             return false;
869         }
870         return true;
871     }
872 
873     /**
874      * Increment total number of attempts to start a pno scan
875      */
incrementPnoScanStartAttempCount()876     public void incrementPnoScanStartAttempCount() {
877         synchronized (mLock) {
878             mPnoScanMetrics.numPnoScanAttempts++;
879         }
880     }
881 
882     /**
883      * Increment total number of attempts with pno scan failed
884      */
incrementPnoScanFailedCount()885     public void incrementPnoScanFailedCount() {
886         synchronized (mLock) {
887             mPnoScanMetrics.numPnoScanFailed++;
888         }
889     }
890 
891     /**
892      * Increment number of pno scans started successfully over offload
893      */
incrementPnoScanStartedOverOffloadCount()894     public void incrementPnoScanStartedOverOffloadCount() {
895         synchronized (mLock) {
896             mPnoScanMetrics.numPnoScanStartedOverOffload++;
897         }
898     }
899 
900     /**
901      * Increment number of pno scans failed over offload
902      */
incrementPnoScanFailedOverOffloadCount()903     public void incrementPnoScanFailedOverOffloadCount() {
904         synchronized (mLock) {
905             mPnoScanMetrics.numPnoScanFailedOverOffload++;
906         }
907     }
908 
909     /**
910      * Increment number of times pno scan found a result
911      */
incrementPnoFoundNetworkEventCount()912     public void incrementPnoFoundNetworkEventCount() {
913         synchronized (mLock) {
914             mPnoScanMetrics.numPnoFoundNetworkEvents++;
915         }
916     }
917 
918     /**
919      * Increment total number of wps connection attempts
920      */
incrementWpsAttemptCount()921     public void incrementWpsAttemptCount() {
922         synchronized (mLock) {
923             mWpsMetrics.numWpsAttempts++;
924         }
925     }
926 
927     /**
928      * Increment total number of wps connection success
929      */
incrementWpsSuccessCount()930     public void incrementWpsSuccessCount() {
931         synchronized (mLock) {
932             mWpsMetrics.numWpsSuccess++;
933         }
934     }
935 
936     /**
937      * Increment total number of wps failure on start
938      */
incrementWpsStartFailureCount()939     public void incrementWpsStartFailureCount() {
940         synchronized (mLock) {
941             mWpsMetrics.numWpsStartFailure++;
942         }
943     }
944 
945     /**
946      * Increment total number of wps overlap failure
947      */
incrementWpsOverlapFailureCount()948     public void incrementWpsOverlapFailureCount() {
949         synchronized (mLock) {
950             mWpsMetrics.numWpsOverlapFailure++;
951         }
952     }
953 
954     /**
955      * Increment total number of wps timeout failure
956      */
incrementWpsTimeoutFailureCount()957     public void incrementWpsTimeoutFailureCount() {
958         synchronized (mLock) {
959             mWpsMetrics.numWpsTimeoutFailure++;
960         }
961     }
962 
963     /**
964      * Increment total number of other wps failure during connection
965      */
incrementWpsOtherConnectionFailureCount()966     public void incrementWpsOtherConnectionFailureCount() {
967         synchronized (mLock) {
968             mWpsMetrics.numWpsOtherConnectionFailure++;
969         }
970     }
971 
972     /**
973      * Increment total number of supplicant failure after wps
974      */
incrementWpsSupplicantFailureCount()975     public void incrementWpsSupplicantFailureCount() {
976         synchronized (mLock) {
977             mWpsMetrics.numWpsSupplicantFailure++;
978         }
979     }
980 
981     /**
982      * Increment total number of wps cancellation
983      */
incrementWpsCancellationCount()984     public void incrementWpsCancellationCount() {
985         synchronized (mLock) {
986             mWpsMetrics.numWpsCancellation++;
987         }
988     }
989 
990     // Values used for indexing SystemStateEntries
991     private static final int SCREEN_ON = 1;
992     private static final int SCREEN_OFF = 0;
993 
994     /**
995      * Create a new connection event. Call when wifi attempts to make a new network connection
996      * If there is a current 'un-ended' connection event, it will be ended with UNKNOWN connectivity
997      * failure code.
998      * Gathers and sets the RouterFingerPrint data as well
999      *
1000      * @param config WifiConfiguration of the config used for the current connection attempt
1001      * @param roamType Roam type that caused connection attempt, see WifiMetricsProto.WifiLog.ROAM_X
1002      */
startConnectionEvent(WifiConfiguration config, String targetBSSID, int roamType)1003     public void startConnectionEvent(WifiConfiguration config, String targetBSSID, int roamType) {
1004         synchronized (mLock) {
1005             // Check if this is overlapping another current connection event
1006             if (mCurrentConnectionEvent != null) {
1007                 //Is this new Connection Event the same as the current one
1008                 if (mCurrentConnectionEvent.mConfigSsid != null
1009                         && mCurrentConnectionEvent.mConfigBssid != null
1010                         && config != null
1011                         && mCurrentConnectionEvent.mConfigSsid.equals(config.SSID)
1012                         && (mCurrentConnectionEvent.mConfigBssid.equals("any")
1013                         || mCurrentConnectionEvent.mConfigBssid.equals(targetBSSID))) {
1014                     mCurrentConnectionEvent.mConfigBssid = targetBSSID;
1015                     // End Connection Event due to new connection attempt to the same network
1016                     endConnectionEvent(ConnectionEvent.FAILURE_REDUNDANT_CONNECTION_ATTEMPT,
1017                             WifiMetricsProto.ConnectionEvent.HLF_NONE,
1018                             WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN);
1019                 } else {
1020                     // End Connection Event due to new connection attempt to different network
1021                     endConnectionEvent(ConnectionEvent.FAILURE_NEW_CONNECTION_ATTEMPT,
1022                             WifiMetricsProto.ConnectionEvent.HLF_NONE,
1023                             WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN);
1024                 }
1025             }
1026             //If past maximum connection events, start removing the oldest
1027             while(mConnectionEventList.size() >= MAX_CONNECTION_EVENTS) {
1028                 mConnectionEventList.remove(0);
1029             }
1030             mCurrentConnectionEvent = new ConnectionEvent();
1031             mCurrentConnectionEvent.mConnectionEvent.startTimeMillis =
1032                     mClock.getWallClockMillis();
1033             mCurrentConnectionEvent.mConfigBssid = targetBSSID;
1034             mCurrentConnectionEvent.mConnectionEvent.roamType = roamType;
1035             mCurrentConnectionEvent.mConnectionEvent.networkSelectorExperimentId =
1036                     mNetworkSelectorExperimentId;
1037             mCurrentConnectionEvent.mRouterFingerPrint.updateFromWifiConfiguration(config);
1038             mCurrentConnectionEvent.mConfigBssid = "any";
1039             mCurrentConnectionEvent.mRealStartTime = mClock.getElapsedSinceBootMillis();
1040             mCurrentConnectionEvent.mWifiState = mWifiState;
1041             mCurrentConnectionEvent.mScreenOn = mScreenOn;
1042             mConnectionEventList.add(mCurrentConnectionEvent);
1043             mScanResultRssiTimestampMillis = -1;
1044             if (config != null) {
1045                 mCurrentConnectionEvent.mConnectionEvent.useRandomizedMac =
1046                         config.macRandomizationSetting
1047                         == WifiConfiguration.RANDOMIZATION_PERSISTENT;
1048                 mCurrentConnectionEvent.mConnectionEvent.connectionNominator =
1049                         mNetworkIdToNominatorId.get(config.networkId,
1050                                 WifiMetricsProto.ConnectionEvent.NOMINATOR_UNKNOWN);
1051                 ScanResult candidate = config.getNetworkSelectionStatus().getCandidate();
1052                 if (candidate != null) {
1053                     // Cache the RSSI of the candidate, as the connection event level is updated
1054                     // from other sources (polls, bssid_associations) and delta requires the
1055                     // scanResult rssi
1056                     mScanResultRssi = candidate.level;
1057                     mScanResultRssiTimestampMillis = mClock.getElapsedSinceBootMillis();
1058                 }
1059             }
1060         }
1061     }
1062 
1063     /**
1064      * set the RoamType of the current ConnectionEvent (if any)
1065      */
setConnectionEventRoamType(int roamType)1066     public void setConnectionEventRoamType(int roamType) {
1067         synchronized (mLock) {
1068             if (mCurrentConnectionEvent != null) {
1069                 mCurrentConnectionEvent.mConnectionEvent.roamType = roamType;
1070             }
1071         }
1072     }
1073 
1074     /**
1075      * Set AP related metrics from ScanDetail
1076      */
setConnectionScanDetail(ScanDetail scanDetail)1077     public void setConnectionScanDetail(ScanDetail scanDetail) {
1078         synchronized (mLock) {
1079             if (mCurrentConnectionEvent != null && scanDetail != null) {
1080                 NetworkDetail networkDetail = scanDetail.getNetworkDetail();
1081                 ScanResult scanResult = scanDetail.getScanResult();
1082                 //Ensure that we have a networkDetail, and that it corresponds to the currently
1083                 //tracked connection attempt
1084                 if (networkDetail != null && scanResult != null
1085                         && mCurrentConnectionEvent.mConfigSsid != null
1086                         && mCurrentConnectionEvent.mConfigSsid
1087                         .equals("\"" + networkDetail.getSSID() + "\"")) {
1088                     updateMetricsFromNetworkDetail(networkDetail);
1089                     updateMetricsFromScanResult(scanResult);
1090                 }
1091             }
1092         }
1093     }
1094 
1095     /**
1096      * End a Connection event record. Call when wifi connection attempt succeeds or fails.
1097      * If a Connection event has not been started and is active when .end is called, a new one is
1098      * created with zero duration.
1099      *
1100      * @param level2FailureCode Level 2 failure code returned by supplicant
1101      * @param connectivityFailureCode WifiMetricsProto.ConnectionEvent.HLF_X
1102      * @param level2FailureReason Breakdown of level2FailureCode with more detailed reason
1103      */
endConnectionEvent(int level2FailureCode, int connectivityFailureCode, int level2FailureReason)1104     public void endConnectionEvent(int level2FailureCode, int connectivityFailureCode,
1105             int level2FailureReason) {
1106         synchronized (mLock) {
1107             if (mCurrentConnectionEvent != null) {
1108                 boolean result = (level2FailureCode == 1)
1109                         && (connectivityFailureCode == WifiMetricsProto.ConnectionEvent.HLF_NONE);
1110                 mCurrentConnectionEvent.mConnectionEvent.connectionResult = result ? 1 : 0;
1111                 mCurrentConnectionEvent.mRealEndTime = mClock.getElapsedSinceBootMillis();
1112                 mCurrentConnectionEvent.mConnectionEvent.durationTakenToConnectMillis = (int)
1113                         (mCurrentConnectionEvent.mRealEndTime
1114                         - mCurrentConnectionEvent.mRealStartTime);
1115                 mCurrentConnectionEvent.mConnectionEvent.level2FailureCode = level2FailureCode;
1116                 mCurrentConnectionEvent.mConnectionEvent.connectivityLevelFailureCode =
1117                         connectivityFailureCode;
1118                 mCurrentConnectionEvent.mConnectionEvent.level2FailureReason = level2FailureReason;
1119                 // ConnectionEvent already added to ConnectionEvents List. Safe to null current here
1120                 mCurrentConnectionEvent = null;
1121                 if (!result) {
1122                     mScanResultRssiTimestampMillis = -1;
1123                 }
1124             }
1125         }
1126     }
1127 
1128     /**
1129      * Set ConnectionEvent DTIM Interval (if set), and 802.11 Connection mode, from NetworkDetail
1130      */
updateMetricsFromNetworkDetail(NetworkDetail networkDetail)1131     private void updateMetricsFromNetworkDetail(NetworkDetail networkDetail) {
1132         int dtimInterval = networkDetail.getDtimInterval();
1133         if (dtimInterval > 0) {
1134             mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.dtim =
1135                     dtimInterval;
1136         }
1137         int connectionWifiMode;
1138         switch (networkDetail.getWifiMode()) {
1139             case InformationElementUtil.WifiMode.MODE_UNDEFINED:
1140                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_UNKNOWN;
1141                 break;
1142             case InformationElementUtil.WifiMode.MODE_11A:
1143                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_A;
1144                 break;
1145             case InformationElementUtil.WifiMode.MODE_11B:
1146                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_B;
1147                 break;
1148             case InformationElementUtil.WifiMode.MODE_11G:
1149                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_G;
1150                 break;
1151             case InformationElementUtil.WifiMode.MODE_11N:
1152                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_N;
1153                 break;
1154             case InformationElementUtil.WifiMode.MODE_11AC  :
1155                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_AC;
1156                 break;
1157             default:
1158                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_OTHER;
1159                 break;
1160         }
1161         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
1162                 .routerTechnology = connectionWifiMode;
1163     }
1164 
1165     /**
1166      * Set ConnectionEvent RSSI and authentication type from ScanResult
1167      */
updateMetricsFromScanResult(ScanResult scanResult)1168     private void updateMetricsFromScanResult(ScanResult scanResult) {
1169         mCurrentConnectionEvent.mConnectionEvent.signalStrength = scanResult.level;
1170         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
1171                 WifiMetricsProto.RouterFingerPrint.AUTH_OPEN;
1172         mCurrentConnectionEvent.mConfigBssid = scanResult.BSSID;
1173         if (scanResult.capabilities != null) {
1174             if (ScanResultUtil.isScanResultForWepNetwork(scanResult)) {
1175                 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
1176                         WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL;
1177             } else if (ScanResultUtil.isScanResultForPskNetwork(scanResult)
1178                     || ScanResultUtil.isScanResultForSaeNetwork(scanResult)) {
1179                 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
1180                         WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL;
1181             } else if (ScanResultUtil.isScanResultForEapNetwork(scanResult)
1182                     || ScanResultUtil.isScanResultForEapSuiteBNetwork(scanResult)) {
1183                 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
1184                         WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE;
1185             }
1186         }
1187         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.channelInfo =
1188                 scanResult.frequency;
1189     }
1190 
setIsLocationEnabled(boolean enabled)1191     void setIsLocationEnabled(boolean enabled) {
1192         synchronized (mLock) {
1193             mWifiLogProto.isLocationEnabled = enabled;
1194         }
1195     }
1196 
setIsScanningAlwaysEnabled(boolean enabled)1197     void setIsScanningAlwaysEnabled(boolean enabled) {
1198         synchronized (mLock) {
1199             mWifiLogProto.isScanningAlwaysEnabled = enabled;
1200         }
1201     }
1202 
1203     /**
1204      * Increment Non Empty Scan Results count
1205      */
incrementNonEmptyScanResultCount()1206     public void incrementNonEmptyScanResultCount() {
1207         if (DBG) Log.v(TAG, "incrementNonEmptyScanResultCount");
1208         synchronized (mLock) {
1209             mWifiLogProto.numNonEmptyScanResults++;
1210         }
1211     }
1212 
1213     /**
1214      * Increment Empty Scan Results count
1215      */
incrementEmptyScanResultCount()1216     public void incrementEmptyScanResultCount() {
1217         if (DBG) Log.v(TAG, "incrementEmptyScanResultCount");
1218         synchronized (mLock) {
1219             mWifiLogProto.numEmptyScanResults++;
1220         }
1221     }
1222 
1223     /**
1224      * Increment background scan count
1225      */
incrementBackgroundScanCount()1226     public void incrementBackgroundScanCount() {
1227         if (DBG) Log.v(TAG, "incrementBackgroundScanCount");
1228         synchronized (mLock) {
1229             mWifiLogProto.numBackgroundScans++;
1230         }
1231     }
1232 
1233     /**
1234      * Get Background scan count
1235      */
getBackgroundScanCount()1236     public int getBackgroundScanCount() {
1237         synchronized (mLock) {
1238             return mWifiLogProto.numBackgroundScans;
1239         }
1240     }
1241 
1242     /**
1243      * Increment oneshot scan count, and the associated WifiSystemScanStateCount entry
1244      */
incrementOneshotScanCount()1245     public void incrementOneshotScanCount() {
1246         synchronized (mLock) {
1247             mWifiLogProto.numOneshotScans++;
1248         }
1249         incrementWifiSystemScanStateCount(mWifiState, mScreenOn);
1250     }
1251 
1252     /**
1253      * Increment the count of oneshot scans that include DFS channels.
1254      */
incrementOneshotScanWithDfsCount()1255     public void incrementOneshotScanWithDfsCount() {
1256         synchronized (mLock) {
1257             mWifiLogProto.numOneshotHasDfsChannelScans++;
1258         }
1259     }
1260 
1261     /**
1262      * Increment connectivity oneshot scan count.
1263      */
incrementConnectivityOneshotScanCount()1264     public void incrementConnectivityOneshotScanCount() {
1265         synchronized (mLock) {
1266             mWifiLogProto.numConnectivityOneshotScans++;
1267         }
1268     }
1269 
1270     /**
1271      * Get oneshot scan count
1272      */
getOneshotScanCount()1273     public int getOneshotScanCount() {
1274         synchronized (mLock) {
1275             return mWifiLogProto.numOneshotScans;
1276         }
1277     }
1278 
1279     /**
1280      * Get connectivity oneshot scan count
1281      */
getConnectivityOneshotScanCount()1282     public int getConnectivityOneshotScanCount() {
1283         synchronized (mLock) {
1284             return mWifiLogProto.numConnectivityOneshotScans;
1285         }
1286     }
1287 
1288     /**
1289      * Get the count of oneshot scan requests that included DFS channels.
1290      */
getOneshotScanWithDfsCount()1291     public int getOneshotScanWithDfsCount() {
1292         synchronized (mLock) {
1293             return mWifiLogProto.numOneshotHasDfsChannelScans;
1294         }
1295     }
1296 
1297     /**
1298      * Increment oneshot scan count for external apps.
1299      */
incrementExternalAppOneshotScanRequestsCount()1300     public void incrementExternalAppOneshotScanRequestsCount() {
1301         synchronized (mLock) {
1302             mWifiLogProto.numExternalAppOneshotScanRequests++;
1303         }
1304     }
1305     /**
1306      * Increment oneshot scan throttle count for external foreground apps.
1307      */
incrementExternalForegroundAppOneshotScanRequestsThrottledCount()1308     public void incrementExternalForegroundAppOneshotScanRequestsThrottledCount() {
1309         synchronized (mLock) {
1310             mWifiLogProto.numExternalForegroundAppOneshotScanRequestsThrottled++;
1311         }
1312     }
1313 
1314     /**
1315      * Increment oneshot scan throttle count for external background apps.
1316      */
incrementExternalBackgroundAppOneshotScanRequestsThrottledCount()1317     public void incrementExternalBackgroundAppOneshotScanRequestsThrottledCount() {
1318         synchronized (mLock) {
1319             mWifiLogProto.numExternalBackgroundAppOneshotScanRequestsThrottled++;
1320         }
1321     }
1322 
returnCodeToString(int scanReturnCode)1323     private String returnCodeToString(int scanReturnCode) {
1324         switch(scanReturnCode){
1325             case WifiMetricsProto.WifiLog.SCAN_UNKNOWN:
1326                 return "SCAN_UNKNOWN";
1327             case WifiMetricsProto.WifiLog.SCAN_SUCCESS:
1328                 return "SCAN_SUCCESS";
1329             case WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED:
1330                 return "SCAN_FAILURE_INTERRUPTED";
1331             case WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION:
1332                 return "SCAN_FAILURE_INVALID_CONFIGURATION";
1333             case WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED:
1334                 return "FAILURE_WIFI_DISABLED";
1335             default:
1336                 return "<UNKNOWN>";
1337         }
1338     }
1339 
1340     /**
1341      * Increment count of scan return code occurrence
1342      *
1343      * @param scanReturnCode Return code from scan attempt WifiMetricsProto.WifiLog.SCAN_X
1344      */
incrementScanReturnEntry(int scanReturnCode, int countToAdd)1345     public void incrementScanReturnEntry(int scanReturnCode, int countToAdd) {
1346         synchronized (mLock) {
1347             if (DBG) Log.v(TAG, "incrementScanReturnEntry " + returnCodeToString(scanReturnCode));
1348             int entry = mScanReturnEntries.get(scanReturnCode);
1349             entry += countToAdd;
1350             mScanReturnEntries.put(scanReturnCode, entry);
1351         }
1352     }
1353     /**
1354      * Get the count of this scanReturnCode
1355      * @param scanReturnCode that we are getting the count for
1356      */
getScanReturnEntry(int scanReturnCode)1357     public int getScanReturnEntry(int scanReturnCode) {
1358         synchronized (mLock) {
1359             return mScanReturnEntries.get(scanReturnCode);
1360         }
1361     }
1362 
wifiSystemStateToString(int state)1363     private String wifiSystemStateToString(int state) {
1364         switch(state){
1365             case WifiMetricsProto.WifiLog.WIFI_UNKNOWN:
1366                 return "WIFI_UNKNOWN";
1367             case WifiMetricsProto.WifiLog.WIFI_DISABLED:
1368                 return "WIFI_DISABLED";
1369             case WifiMetricsProto.WifiLog.WIFI_DISCONNECTED:
1370                 return "WIFI_DISCONNECTED";
1371             case WifiMetricsProto.WifiLog.WIFI_ASSOCIATED:
1372                 return "WIFI_ASSOCIATED";
1373             default:
1374                 return "default";
1375         }
1376     }
1377 
1378     /**
1379      * Increments the count of scans initiated by each wifi state, accounts for screenOn/Off
1380      *
1381      * @param state State of the system when scan was initiated, see WifiMetricsProto.WifiLog.WIFI_X
1382      * @param screenOn Is the screen on
1383      */
incrementWifiSystemScanStateCount(int state, boolean screenOn)1384     public void incrementWifiSystemScanStateCount(int state, boolean screenOn) {
1385         synchronized (mLock) {
1386             if (DBG) {
1387                 Log.v(TAG, "incrementWifiSystemScanStateCount " + wifiSystemStateToString(state)
1388                         + " " + screenOn);
1389             }
1390             int index = (state * 2) + (screenOn ? SCREEN_ON : SCREEN_OFF);
1391             int entry = mWifiSystemStateEntries.get(index);
1392             entry++;
1393             mWifiSystemStateEntries.put(index, entry);
1394         }
1395     }
1396 
1397     /**
1398      * Get the count of this system State Entry
1399      */
getSystemStateCount(int state, boolean screenOn)1400     public int getSystemStateCount(int state, boolean screenOn) {
1401         synchronized (mLock) {
1402             int index = state * 2 + (screenOn ? SCREEN_ON : SCREEN_OFF);
1403             return mWifiSystemStateEntries.get(index);
1404         }
1405     }
1406 
1407     /**
1408      * Increment number of times the Watchdog of Last Resort triggered, resetting the wifi stack
1409      */
incrementNumLastResortWatchdogTriggers()1410     public void incrementNumLastResortWatchdogTriggers() {
1411         synchronized (mLock) {
1412             mWifiLogProto.numLastResortWatchdogTriggers++;
1413         }
1414     }
1415     /**
1416      * @param count number of networks over bad association threshold when watchdog triggered
1417      */
addCountToNumLastResortWatchdogBadAssociationNetworksTotal(int count)1418     public void addCountToNumLastResortWatchdogBadAssociationNetworksTotal(int count) {
1419         synchronized (mLock) {
1420             mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal += count;
1421         }
1422     }
1423     /**
1424      * @param count number of networks over bad authentication threshold when watchdog triggered
1425      */
addCountToNumLastResortWatchdogBadAuthenticationNetworksTotal(int count)1426     public void addCountToNumLastResortWatchdogBadAuthenticationNetworksTotal(int count) {
1427         synchronized (mLock) {
1428             mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal += count;
1429         }
1430     }
1431     /**
1432      * @param count number of networks over bad dhcp threshold when watchdog triggered
1433      */
addCountToNumLastResortWatchdogBadDhcpNetworksTotal(int count)1434     public void addCountToNumLastResortWatchdogBadDhcpNetworksTotal(int count) {
1435         synchronized (mLock) {
1436             mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal += count;
1437         }
1438     }
1439     /**
1440      * @param count number of networks over bad other threshold when watchdog triggered
1441      */
addCountToNumLastResortWatchdogBadOtherNetworksTotal(int count)1442     public void addCountToNumLastResortWatchdogBadOtherNetworksTotal(int count) {
1443         synchronized (mLock) {
1444             mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal += count;
1445         }
1446     }
1447     /**
1448      * @param count number of networks seen when watchdog triggered
1449      */
addCountToNumLastResortWatchdogAvailableNetworksTotal(int count)1450     public void addCountToNumLastResortWatchdogAvailableNetworksTotal(int count) {
1451         synchronized (mLock) {
1452             mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal += count;
1453         }
1454     }
1455     /**
1456      * Increment count of triggers with atleast one bad association network
1457      */
incrementNumLastResortWatchdogTriggersWithBadAssociation()1458     public void incrementNumLastResortWatchdogTriggersWithBadAssociation() {
1459         synchronized (mLock) {
1460             mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation++;
1461         }
1462     }
1463     /**
1464      * Increment count of triggers with atleast one bad authentication network
1465      */
incrementNumLastResortWatchdogTriggersWithBadAuthentication()1466     public void incrementNumLastResortWatchdogTriggersWithBadAuthentication() {
1467         synchronized (mLock) {
1468             mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication++;
1469         }
1470     }
1471     /**
1472      * Increment count of triggers with atleast one bad dhcp network
1473      */
incrementNumLastResortWatchdogTriggersWithBadDhcp()1474     public void incrementNumLastResortWatchdogTriggersWithBadDhcp() {
1475         synchronized (mLock) {
1476             mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp++;
1477         }
1478     }
1479     /**
1480      * Increment count of triggers with atleast one bad other network
1481      */
incrementNumLastResortWatchdogTriggersWithBadOther()1482     public void incrementNumLastResortWatchdogTriggersWithBadOther() {
1483         synchronized (mLock) {
1484             mWifiLogProto.numLastResortWatchdogTriggersWithBadOther++;
1485         }
1486     }
1487 
1488     /**
1489      * Increment number of times connectivity watchdog confirmed pno is working
1490      */
incrementNumConnectivityWatchdogPnoGood()1491     public void incrementNumConnectivityWatchdogPnoGood() {
1492         synchronized (mLock) {
1493             mWifiLogProto.numConnectivityWatchdogPnoGood++;
1494         }
1495     }
1496     /**
1497      * Increment number of times connectivity watchdog found pno not working
1498      */
incrementNumConnectivityWatchdogPnoBad()1499     public void incrementNumConnectivityWatchdogPnoBad() {
1500         synchronized (mLock) {
1501             mWifiLogProto.numConnectivityWatchdogPnoBad++;
1502         }
1503     }
1504     /**
1505      * Increment number of times connectivity watchdog confirmed background scan is working
1506      */
incrementNumConnectivityWatchdogBackgroundGood()1507     public void incrementNumConnectivityWatchdogBackgroundGood() {
1508         synchronized (mLock) {
1509             mWifiLogProto.numConnectivityWatchdogBackgroundGood++;
1510         }
1511     }
1512     /**
1513      * Increment number of times connectivity watchdog found background scan not working
1514      */
incrementNumConnectivityWatchdogBackgroundBad()1515     public void incrementNumConnectivityWatchdogBackgroundBad() {
1516         synchronized (mLock) {
1517             mWifiLogProto.numConnectivityWatchdogBackgroundBad++;
1518         }
1519     }
1520 
1521     /**
1522      * Increment various poll related metrics, and cache performance data for StaEvent logging
1523      */
handlePollResult(WifiInfo wifiInfo)1524     public void handlePollResult(WifiInfo wifiInfo) {
1525         mLastPollRssi = wifiInfo.getRssi();
1526         mLastPollLinkSpeed = wifiInfo.getLinkSpeed();
1527         mLastPollFreq = wifiInfo.getFrequency();
1528         incrementRssiPollRssiCount(mLastPollFreq, mLastPollRssi);
1529         incrementLinkSpeedCount(mLastPollLinkSpeed, mLastPollRssi);
1530     }
1531 
1532     /**
1533      * Increment occurence count of RSSI level from RSSI poll for the given frequency.
1534      * @param frequency (MHz)
1535      * @param rssi
1536      */
1537     @VisibleForTesting
incrementRssiPollRssiCount(int frequency, int rssi)1538     public void incrementRssiPollRssiCount(int frequency, int rssi) {
1539         if (!(rssi >= MIN_RSSI_POLL && rssi <= MAX_RSSI_POLL)) {
1540             return;
1541         }
1542         synchronized (mLock) {
1543             if (!mRssiPollCountsMap.containsKey(frequency)) {
1544                 mRssiPollCountsMap.put(frequency, new SparseIntArray());
1545             }
1546             SparseIntArray sparseIntArray = mRssiPollCountsMap.get(frequency);
1547             int count = sparseIntArray.get(rssi);
1548             sparseIntArray.put(rssi, count + 1);
1549             maybeIncrementRssiDeltaCount(rssi - mScanResultRssi);
1550         }
1551     }
1552 
1553     /**
1554      * Increment occurence count of difference between scan result RSSI and the first RSSI poll.
1555      * Ignores rssi values outside the bounds of [MIN_RSSI_DELTA, MAX_RSSI_DELTA]
1556      * mLock must be held when calling this method.
1557      */
maybeIncrementRssiDeltaCount(int rssi)1558     private void maybeIncrementRssiDeltaCount(int rssi) {
1559         // Check if this RSSI poll is close enough to a scan result RSSI to log a delta value
1560         if (mScanResultRssiTimestampMillis >= 0) {
1561             long timeDelta = mClock.getElapsedSinceBootMillis() - mScanResultRssiTimestampMillis;
1562             if (timeDelta <= TIMEOUT_RSSI_DELTA_MILLIS) {
1563                 if (rssi >= MIN_RSSI_DELTA && rssi <= MAX_RSSI_DELTA) {
1564                     int count = mRssiDeltaCounts.get(rssi);
1565                     mRssiDeltaCounts.put(rssi, count + 1);
1566                 }
1567             }
1568             mScanResultRssiTimestampMillis = -1;
1569         }
1570     }
1571 
1572     /**
1573      * Increment occurrence count of link speed.
1574      * Ignores link speed values that are lower than MIN_LINK_SPEED_MBPS
1575      * and rssi values outside the bounds of [MIN_RSSI_POLL, MAX_RSSI_POLL]
1576      */
1577     @VisibleForTesting
incrementLinkSpeedCount(int linkSpeed, int rssi)1578     public void incrementLinkSpeedCount(int linkSpeed, int rssi) {
1579         if (!(mLinkSpeedCountsLogging
1580                 && linkSpeed >= MIN_LINK_SPEED_MBPS
1581                 && rssi >= MIN_RSSI_POLL
1582                 && rssi <= MAX_RSSI_POLL)) {
1583             return;
1584         }
1585         synchronized (mLock) {
1586             LinkSpeedCount linkSpeedCount = mLinkSpeedCounts.get(linkSpeed);
1587             if (linkSpeedCount == null) {
1588                 linkSpeedCount = new LinkSpeedCount();
1589                 linkSpeedCount.linkSpeedMbps = linkSpeed;
1590                 mLinkSpeedCounts.put(linkSpeed, linkSpeedCount);
1591             }
1592             linkSpeedCount.count++;
1593             linkSpeedCount.rssiSumDbm += Math.abs(rssi);
1594             linkSpeedCount.rssiSumOfSquaresDbmSq += rssi * rssi;
1595         }
1596     }
1597 
1598     /**
1599      * Increment count of Watchdog successes.
1600      */
incrementNumLastResortWatchdogSuccesses()1601     public void incrementNumLastResortWatchdogSuccesses() {
1602         synchronized (mLock) {
1603             mWifiLogProto.numLastResortWatchdogSuccesses++;
1604         }
1605     }
1606 
1607     /**
1608      * Increment the count of network connection failures that happened after watchdog has been
1609      * triggered.
1610      */
incrementWatchdogTotalConnectionFailureCountAfterTrigger()1611     public void incrementWatchdogTotalConnectionFailureCountAfterTrigger() {
1612         synchronized (mLock) {
1613             mWifiLogProto.watchdogTotalConnectionFailureCountAfterTrigger++;
1614         }
1615     }
1616 
1617     /**
1618      * Sets the time taken for wifi to connect after a watchdog triggers a restart.
1619      * @param milliseconds
1620      */
setWatchdogSuccessTimeDurationMs(long ms)1621     public void setWatchdogSuccessTimeDurationMs(long ms) {
1622         synchronized (mLock) {
1623             mWifiLogProto.watchdogTriggerToConnectionSuccessDurationMs = ms;
1624         }
1625     }
1626 
1627     /**
1628      * Increments the count of alerts by alert reason.
1629      *
1630      * @param reason The cause of the alert. The reason values are driver-specific.
1631      */
incrementAlertReasonCount(int reason)1632     private void incrementAlertReasonCount(int reason) {
1633         if (reason > WifiLoggerHal.WIFI_ALERT_REASON_MAX
1634                 || reason < WifiLoggerHal.WIFI_ALERT_REASON_MIN) {
1635             reason = WifiLoggerHal.WIFI_ALERT_REASON_RESERVED;
1636         }
1637         synchronized (mLock) {
1638             int alertCount = mWifiAlertReasonCounts.get(reason);
1639             mWifiAlertReasonCounts.put(reason, alertCount + 1);
1640         }
1641     }
1642 
1643     /**
1644      * Counts all the different types of networks seen in a set of scan results
1645      */
countScanResults(List<ScanDetail> scanDetails)1646     public void countScanResults(List<ScanDetail> scanDetails) {
1647         if (scanDetails == null) {
1648             return;
1649         }
1650         int totalResults = 0;
1651         int openNetworks = 0;
1652         int personalNetworks = 0;
1653         int enterpriseNetworks = 0;
1654         int hiddenNetworks = 0;
1655         int hotspot2r1Networks = 0;
1656         int hotspot2r2Networks = 0;
1657         int enhacedOpenNetworks = 0;
1658         int wpa3PersonalNetworks = 0;
1659         int wpa3EnterpriseNetworks = 0;
1660 
1661         for (ScanDetail scanDetail : scanDetails) {
1662             NetworkDetail networkDetail = scanDetail.getNetworkDetail();
1663             ScanResult scanResult = scanDetail.getScanResult();
1664             totalResults++;
1665             if (networkDetail != null) {
1666                 if (networkDetail.isHiddenBeaconFrame()) {
1667                     hiddenNetworks++;
1668                 }
1669                 if (networkDetail.getHSRelease() != null) {
1670                     if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) {
1671                         hotspot2r1Networks++;
1672                     } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) {
1673                         hotspot2r2Networks++;
1674                     }
1675                 }
1676             }
1677             if (scanResult != null && scanResult.capabilities != null) {
1678                 if (ScanResultUtil.isScanResultForEapSuiteBNetwork(scanResult)) {
1679                     wpa3EnterpriseNetworks++;
1680                 } else if (ScanResultUtil.isScanResultForEapNetwork(scanResult)) {
1681                     enterpriseNetworks++;
1682                 } else if (ScanResultUtil.isScanResultForSaeNetwork(scanResult)) {
1683                     wpa3PersonalNetworks++;
1684                 } else if (ScanResultUtil.isScanResultForPskNetwork(scanResult)
1685                         || ScanResultUtil.isScanResultForWepNetwork(scanResult)) {
1686                     personalNetworks++;
1687                 } else if (ScanResultUtil.isScanResultForOweNetwork(scanResult)) {
1688                     enhacedOpenNetworks++;
1689                 } else {
1690                     openNetworks++;
1691                 }
1692             }
1693         }
1694         synchronized (mLock) {
1695             mWifiLogProto.numTotalScanResults += totalResults;
1696             mWifiLogProto.numOpenNetworkScanResults += openNetworks;
1697             mWifiLogProto.numLegacyPersonalNetworkScanResults += personalNetworks;
1698             mWifiLogProto.numLegacyEnterpriseNetworkScanResults += enterpriseNetworks;
1699             mWifiLogProto.numEnhancedOpenNetworkScanResults += enhacedOpenNetworks;
1700             mWifiLogProto.numWpa3PersonalNetworkScanResults += wpa3PersonalNetworks;
1701             mWifiLogProto.numWpa3EnterpriseNetworkScanResults += wpa3EnterpriseNetworks;
1702             mWifiLogProto.numHiddenNetworkScanResults += hiddenNetworks;
1703             mWifiLogProto.numHotspot2R1NetworkScanResults += hotspot2r1Networks;
1704             mWifiLogProto.numHotspot2R2NetworkScanResults += hotspot2r2Networks;
1705             mWifiLogProto.numScans++;
1706         }
1707     }
1708 
1709     private boolean mWifiWins = false; // Based on scores, use wifi instead of mobile data?
1710     // Based on Wifi usability scores. use wifi instead of mobile data?
1711     private boolean mWifiWinsUsabilityScore = false;
1712 
1713     /**
1714      * Increments occurence of a particular wifi score calculated
1715      * in WifiScoreReport by current connected network. Scores are bounded
1716      * within  [MIN_WIFI_SCORE, MAX_WIFI_SCORE] to limit size of SparseArray.
1717      *
1718      * Also records events when the current score breaches significant thresholds.
1719      */
incrementWifiScoreCount(int score)1720     public void incrementWifiScoreCount(int score) {
1721         if (score < MIN_WIFI_SCORE || score > MAX_WIFI_SCORE) {
1722             return;
1723         }
1724         synchronized (mLock) {
1725             int count = mWifiScoreCounts.get(score);
1726             mWifiScoreCounts.put(score, count + 1);
1727 
1728             boolean wifiWins = mWifiWins;
1729             if (mWifiWins && score < LOW_WIFI_SCORE) {
1730                 wifiWins = false;
1731             } else if (!mWifiWins && score > LOW_WIFI_SCORE) {
1732                 wifiWins = true;
1733             }
1734             mLastScore = score;
1735             mLastScoreNoReset = score;
1736             if (wifiWins != mWifiWins) {
1737                 mWifiWins = wifiWins;
1738                 StaEvent event = new StaEvent();
1739                 event.type = StaEvent.TYPE_SCORE_BREACH;
1740                 addStaEvent(event);
1741                 // Only record the first score breach by checking whether mScoreBreachLowTimeMillis
1742                 // has been set to -1
1743                 if (!wifiWins && mScoreBreachLowTimeMillis == -1) {
1744                     mScoreBreachLowTimeMillis = mClock.getElapsedSinceBootMillis();
1745                 }
1746             }
1747         }
1748     }
1749 
1750     /**
1751      * Increments occurence of the results from attempting to start SoftAp.
1752      * Maps the |result| and WifiManager |failureCode| constant to proto defined SoftApStartResult
1753      * codes.
1754      */
incrementSoftApStartResult(boolean result, int failureCode)1755     public void incrementSoftApStartResult(boolean result, int failureCode) {
1756         synchronized (mLock) {
1757             if (result) {
1758                 int count = mSoftApManagerReturnCodeCounts.get(
1759                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY);
1760                 mSoftApManagerReturnCodeCounts.put(
1761                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY,
1762                         count + 1);
1763                 return;
1764             }
1765 
1766             // now increment failure modes - if not explicitly handled, dump into the general
1767             // error bucket.
1768             if (failureCode == WifiManager.SAP_START_FAILURE_NO_CHANNEL) {
1769                 int count = mSoftApManagerReturnCodeCounts.get(
1770                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL);
1771                 mSoftApManagerReturnCodeCounts.put(
1772                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL,
1773                         count + 1);
1774             } else {
1775                 // failure mode not tracked at this time...  count as a general error for now.
1776                 int count = mSoftApManagerReturnCodeCounts.get(
1777                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR);
1778                 mSoftApManagerReturnCodeCounts.put(
1779                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR,
1780                         count + 1);
1781             }
1782         }
1783     }
1784 
1785     /**
1786      * Adds a record indicating the current up state of soft AP
1787      */
addSoftApUpChangedEvent(boolean isUp, int mode)1788     public void addSoftApUpChangedEvent(boolean isUp, int mode) {
1789         SoftApConnectedClientsEvent event = new SoftApConnectedClientsEvent();
1790         event.eventType = isUp ? SoftApConnectedClientsEvent.SOFT_AP_UP :
1791                 SoftApConnectedClientsEvent.SOFT_AP_DOWN;
1792         event.numConnectedClients = 0;
1793         addSoftApConnectedClientsEvent(event, mode);
1794     }
1795 
1796     /**
1797      * Adds a record for current number of associated stations to soft AP
1798      */
addSoftApNumAssociatedStationsChangedEvent(int numStations, int mode)1799     public void addSoftApNumAssociatedStationsChangedEvent(int numStations, int mode) {
1800         SoftApConnectedClientsEvent event = new SoftApConnectedClientsEvent();
1801         event.eventType = SoftApConnectedClientsEvent.NUM_CLIENTS_CHANGED;
1802         event.numConnectedClients = numStations;
1803         addSoftApConnectedClientsEvent(event, mode);
1804     }
1805 
1806     /**
1807      * Adds a record to the corresponding event list based on mode param
1808      */
addSoftApConnectedClientsEvent(SoftApConnectedClientsEvent event, int mode)1809     private void addSoftApConnectedClientsEvent(SoftApConnectedClientsEvent event, int mode) {
1810         synchronized (mLock) {
1811             List<SoftApConnectedClientsEvent> softApEventList;
1812             switch (mode) {
1813                 case WifiManager.IFACE_IP_MODE_TETHERED:
1814                     softApEventList = mSoftApEventListTethered;
1815                     break;
1816                 case WifiManager.IFACE_IP_MODE_LOCAL_ONLY:
1817                     softApEventList = mSoftApEventListLocalOnly;
1818                     break;
1819                 default:
1820                     return;
1821             }
1822 
1823             if (softApEventList.size() > MAX_NUM_SOFT_AP_EVENTS) {
1824                 return;
1825             }
1826 
1827             event.timeStampMillis = mClock.getElapsedSinceBootMillis();
1828             softApEventList.add(event);
1829         }
1830     }
1831 
1832     /**
1833      * Updates current soft AP events with channel info
1834      */
addSoftApChannelSwitchedEvent(int frequency, int bandwidth, int mode)1835     public void addSoftApChannelSwitchedEvent(int frequency, int bandwidth, int mode) {
1836         synchronized (mLock) {
1837             List<SoftApConnectedClientsEvent> softApEventList;
1838             switch (mode) {
1839                 case WifiManager.IFACE_IP_MODE_TETHERED:
1840                     softApEventList = mSoftApEventListTethered;
1841                     break;
1842                 case WifiManager.IFACE_IP_MODE_LOCAL_ONLY:
1843                     softApEventList = mSoftApEventListLocalOnly;
1844                     break;
1845                 default:
1846                     return;
1847             }
1848 
1849             for (int index = softApEventList.size() - 1; index >= 0; index--) {
1850                 SoftApConnectedClientsEvent event = softApEventList.get(index);
1851 
1852                 if (event != null && event.eventType == SoftApConnectedClientsEvent.SOFT_AP_UP) {
1853                     event.channelFrequency = frequency;
1854                     event.channelBandwidth = bandwidth;
1855                     break;
1856                 }
1857             }
1858         }
1859     }
1860 
1861     /**
1862      * Increment number of times the HAL crashed.
1863      */
incrementNumHalCrashes()1864     public void incrementNumHalCrashes() {
1865         synchronized (mLock) {
1866             mWifiLogProto.numHalCrashes++;
1867         }
1868     }
1869 
1870     /**
1871      * Increment number of times the Wificond crashed.
1872      */
incrementNumWificondCrashes()1873     public void incrementNumWificondCrashes() {
1874         synchronized (mLock) {
1875             mWifiLogProto.numWificondCrashes++;
1876         }
1877     }
1878 
1879     /**
1880      * Increment number of times the supplicant crashed.
1881      */
incrementNumSupplicantCrashes()1882     public void incrementNumSupplicantCrashes() {
1883         synchronized (mLock) {
1884             mWifiLogProto.numSupplicantCrashes++;
1885         }
1886     }
1887 
1888     /**
1889      * Increment number of times the hostapd crashed.
1890      */
incrementNumHostapdCrashes()1891     public void incrementNumHostapdCrashes() {
1892         synchronized (mLock) {
1893             mWifiLogProto.numHostapdCrashes++;
1894         }
1895     }
1896 
1897     /**
1898      * Increment number of times the wifi on failed due to an error in HAL.
1899      */
incrementNumSetupClientInterfaceFailureDueToHal()1900     public void incrementNumSetupClientInterfaceFailureDueToHal() {
1901         synchronized (mLock) {
1902             mWifiLogProto.numSetupClientInterfaceFailureDueToHal++;
1903         }
1904     }
1905 
1906     /**
1907      * Increment number of times the wifi on failed due to an error in wificond.
1908      */
incrementNumSetupClientInterfaceFailureDueToWificond()1909     public void incrementNumSetupClientInterfaceFailureDueToWificond() {
1910         synchronized (mLock) {
1911             mWifiLogProto.numSetupClientInterfaceFailureDueToWificond++;
1912         }
1913     }
1914 
1915     /**
1916      * Increment number of times the wifi on failed due to an error in supplicant.
1917      */
incrementNumSetupClientInterfaceFailureDueToSupplicant()1918     public void incrementNumSetupClientInterfaceFailureDueToSupplicant() {
1919         synchronized (mLock) {
1920             mWifiLogProto.numSetupClientInterfaceFailureDueToSupplicant++;
1921         }
1922     }
1923 
1924     /**
1925      * Increment number of times the SoftAp on failed due to an error in HAL.
1926      */
incrementNumSetupSoftApInterfaceFailureDueToHal()1927     public void incrementNumSetupSoftApInterfaceFailureDueToHal() {
1928         synchronized (mLock) {
1929             mWifiLogProto.numSetupSoftApInterfaceFailureDueToHal++;
1930         }
1931     }
1932 
1933     /**
1934      * Increment number of times the SoftAp on failed due to an error in wificond.
1935      */
incrementNumSetupSoftApInterfaceFailureDueToWificond()1936     public void incrementNumSetupSoftApInterfaceFailureDueToWificond() {
1937         synchronized (mLock) {
1938             mWifiLogProto.numSetupSoftApInterfaceFailureDueToWificond++;
1939         }
1940     }
1941 
1942     /**
1943      * Increment number of times the SoftAp on failed due to an error in hostapd.
1944      */
incrementNumSetupSoftApInterfaceFailureDueToHostapd()1945     public void incrementNumSetupSoftApInterfaceFailureDueToHostapd() {
1946         synchronized (mLock) {
1947             mWifiLogProto.numSetupSoftApInterfaceFailureDueToHostapd++;
1948         }
1949     }
1950 
1951     /**
1952      * Increment number of times we got client interface down.
1953      */
incrementNumClientInterfaceDown()1954     public void incrementNumClientInterfaceDown() {
1955         synchronized (mLock) {
1956             mWifiLogProto.numClientInterfaceDown++;
1957         }
1958     }
1959 
1960     /**
1961      * Increment number of times we got client interface down.
1962      */
incrementNumSoftApInterfaceDown()1963     public void incrementNumSoftApInterfaceDown() {
1964         synchronized (mLock) {
1965             mWifiLogProto.numSoftApInterfaceDown++;
1966         }
1967     }
1968 
1969     /**
1970      * Increment number of times Passpoint provider being installed.
1971      */
incrementNumPasspointProviderInstallation()1972     public void incrementNumPasspointProviderInstallation() {
1973         synchronized (mLock) {
1974             mWifiLogProto.numPasspointProviderInstallation++;
1975         }
1976     }
1977 
1978     /**
1979      * Increment number of times Passpoint provider is installed successfully.
1980      */
incrementNumPasspointProviderInstallSuccess()1981     public void incrementNumPasspointProviderInstallSuccess() {
1982         synchronized (mLock) {
1983             mWifiLogProto.numPasspointProviderInstallSuccess++;
1984         }
1985     }
1986 
1987     /**
1988      * Increment number of times Passpoint provider being uninstalled.
1989      */
incrementNumPasspointProviderUninstallation()1990     public void incrementNumPasspointProviderUninstallation() {
1991         synchronized (mLock) {
1992             mWifiLogProto.numPasspointProviderUninstallation++;
1993         }
1994     }
1995 
1996     /**
1997      * Increment number of times Passpoint provider is uninstalled successfully.
1998      */
incrementNumPasspointProviderUninstallSuccess()1999     public void incrementNumPasspointProviderUninstallSuccess() {
2000         synchronized (mLock) {
2001             mWifiLogProto.numPasspointProviderUninstallSuccess++;
2002         }
2003     }
2004 
2005     /**
2006      * Increment number of times we detected a radio mode change to MCC.
2007      */
incrementNumRadioModeChangeToMcc()2008     public void incrementNumRadioModeChangeToMcc() {
2009         synchronized (mLock) {
2010             mWifiLogProto.numRadioModeChangeToMcc++;
2011         }
2012     }
2013 
2014     /**
2015      * Increment number of times we detected a radio mode change to SCC.
2016      */
incrementNumRadioModeChangeToScc()2017     public void incrementNumRadioModeChangeToScc() {
2018         synchronized (mLock) {
2019             mWifiLogProto.numRadioModeChangeToScc++;
2020         }
2021     }
2022 
2023     /**
2024      * Increment number of times we detected a radio mode change to SBS.
2025      */
incrementNumRadioModeChangeToSbs()2026     public void incrementNumRadioModeChangeToSbs() {
2027         synchronized (mLock) {
2028             mWifiLogProto.numRadioModeChangeToSbs++;
2029         }
2030     }
2031 
2032     /**
2033      * Increment number of times we detected a radio mode change to DBS.
2034      */
incrementNumRadioModeChangeToDbs()2035     public void incrementNumRadioModeChangeToDbs() {
2036         synchronized (mLock) {
2037             mWifiLogProto.numRadioModeChangeToDbs++;
2038         }
2039     }
2040 
2041     /**
2042      * Increment number of times we detected a channel did not satisfy user band preference.
2043      */
incrementNumSoftApUserBandPreferenceUnsatisfied()2044     public void incrementNumSoftApUserBandPreferenceUnsatisfied() {
2045         synchronized (mLock) {
2046             mWifiLogProto.numSoftApUserBandPreferenceUnsatisfied++;
2047         }
2048     }
2049 
2050     /** Increment the failure count of SAR sensor listener registration */
incrementNumSarSensorRegistrationFailures()2051     public void incrementNumSarSensorRegistrationFailures() {
2052         synchronized (mLock) {
2053             mWifiLogProto.numSarSensorRegistrationFailures++;
2054         }
2055     }
2056 
2057     /**
2058      * Increment N-Way network selection decision histograms:
2059      * Counts the size of various sets of scanDetails within a scan, and increment the occurrence
2060      * of that size for the associated histogram. There are ten histograms generated for each
2061      * combination of: {SSID, BSSID} *{Total, Saved, Open, Saved_or_Open, Passpoint}
2062      * Only performs this count if isFullBand is true, otherwise, increments the partial scan count
2063      */
incrementAvailableNetworksHistograms(List<ScanDetail> scanDetails, boolean isFullBand)2064     public void incrementAvailableNetworksHistograms(List<ScanDetail> scanDetails,
2065             boolean isFullBand) {
2066         synchronized (mLock) {
2067             if (mWifiConfigManager == null || mWifiNetworkSelector == null
2068                     || mPasspointManager == null) {
2069                 return;
2070             }
2071             if (!isFullBand) {
2072                 mWifiLogProto.partialAllSingleScanListenerResults++;
2073                 return;
2074             }
2075             Set<ScanResultMatchInfo> ssids = new HashSet<ScanResultMatchInfo>();
2076             int bssids = 0;
2077             Set<ScanResultMatchInfo> openSsids = new HashSet<ScanResultMatchInfo>();
2078             int openBssids = 0;
2079             Set<ScanResultMatchInfo> savedSsids = new HashSet<ScanResultMatchInfo>();
2080             int savedBssids = 0;
2081             // openOrSavedSsids calculated from union of savedSsids & openSsids
2082             int openOrSavedBssids = 0;
2083             Set<PasspointProvider> savedPasspointProviderProfiles =
2084                     new HashSet<PasspointProvider>();
2085             int savedPasspointProviderBssids = 0;
2086             int passpointR1Aps = 0;
2087             int passpointR2Aps = 0;
2088             Map<ANQPNetworkKey, Integer> passpointR1UniqueEss = new HashMap<>();
2089             Map<ANQPNetworkKey, Integer> passpointR2UniqueEss = new HashMap<>();
2090             int supporting80211mcAps = 0;
2091             for (ScanDetail scanDetail : scanDetails) {
2092                 NetworkDetail networkDetail = scanDetail.getNetworkDetail();
2093                 ScanResult scanResult = scanDetail.getScanResult();
2094 
2095                 // statistics to be collected for ALL APs (irrespective of signal power)
2096                 if (networkDetail.is80211McResponderSupport()) {
2097                     supporting80211mcAps++;
2098                 }
2099 
2100                 ScanResultMatchInfo matchInfo = ScanResultMatchInfo.fromScanResult(scanResult);
2101                 Pair<PasspointProvider, PasspointMatch> providerMatch = null;
2102                 PasspointProvider passpointProvider = null;
2103                 if (networkDetail.isInterworking()) {
2104                     providerMatch =
2105                             mPasspointManager.matchProvider(scanResult);
2106                     passpointProvider = providerMatch != null ? providerMatch.first : null;
2107 
2108                     if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) {
2109                         passpointR1Aps++;
2110                     } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) {
2111                         passpointR2Aps++;
2112                     }
2113 
2114                     long bssid = 0;
2115                     boolean validBssid = false;
2116                     try {
2117                         bssid = Utils.parseMac(scanResult.BSSID);
2118                         validBssid = true;
2119                     } catch (IllegalArgumentException e) {
2120                         Log.e(TAG,
2121                                 "Invalid BSSID provided in the scan result: " + scanResult.BSSID);
2122                     }
2123                     if (validBssid) {
2124                         ANQPNetworkKey uniqueEss = ANQPNetworkKey.buildKey(scanResult.SSID, bssid,
2125                                 scanResult.hessid, networkDetail.getAnqpDomainID());
2126                         if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) {
2127                             Integer countObj = passpointR1UniqueEss.get(uniqueEss);
2128                             int count = countObj == null ? 0 : countObj;
2129                             passpointR1UniqueEss.put(uniqueEss, count + 1);
2130                         } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) {
2131                             Integer countObj = passpointR2UniqueEss.get(uniqueEss);
2132                             int count = countObj == null ? 0 : countObj;
2133                             passpointR2UniqueEss.put(uniqueEss, count + 1);
2134                         }
2135                     }
2136 
2137                 }
2138 
2139                 if (mWifiNetworkSelector.isSignalTooWeak(scanResult)) {
2140                     continue;
2141                 }
2142 
2143                 // statistics to be collected ONLY for those APs with sufficient signal power
2144 
2145                 ssids.add(matchInfo);
2146                 bssids++;
2147                 boolean isOpen = matchInfo.networkType == WifiConfiguration.SECURITY_TYPE_OPEN;
2148                 WifiConfiguration config =
2149                         mWifiConfigManager.getConfiguredNetworkForScanDetail(scanDetail);
2150                 boolean isSaved = (config != null) && !config.isEphemeral()
2151                         && !config.isPasspoint();
2152                 boolean isSavedPasspoint = passpointProvider != null;
2153                 if (isOpen) {
2154                     openSsids.add(matchInfo);
2155                     openBssids++;
2156                 }
2157                 if (isSaved) {
2158                     savedSsids.add(matchInfo);
2159                     savedBssids++;
2160                 }
2161                 if (isOpen || isSaved) {
2162                     openOrSavedBssids++;
2163                     // Calculate openOrSavedSsids union later
2164                 }
2165                 if (isSavedPasspoint) {
2166                     savedPasspointProviderProfiles.add(passpointProvider);
2167                     savedPasspointProviderBssids++;
2168                 }
2169             }
2170             mWifiLogProto.fullBandAllSingleScanListenerResults++;
2171             incrementTotalScanSsids(mTotalSsidsInScanHistogram, ssids.size());
2172             incrementTotalScanResults(mTotalBssidsInScanHistogram, bssids);
2173             incrementSsid(mAvailableOpenSsidsInScanHistogram, openSsids.size());
2174             incrementBssid(mAvailableOpenBssidsInScanHistogram, openBssids);
2175             incrementSsid(mAvailableSavedSsidsInScanHistogram, savedSsids.size());
2176             incrementBssid(mAvailableSavedBssidsInScanHistogram, savedBssids);
2177             openSsids.addAll(savedSsids); // openSsids = Union(openSsids, savedSsids)
2178             incrementSsid(mAvailableOpenOrSavedSsidsInScanHistogram, openSsids.size());
2179             incrementBssid(mAvailableOpenOrSavedBssidsInScanHistogram, openOrSavedBssids);
2180             incrementSsid(mAvailableSavedPasspointProviderProfilesInScanHistogram,
2181                     savedPasspointProviderProfiles.size());
2182             incrementBssid(mAvailableSavedPasspointProviderBssidsInScanHistogram,
2183                     savedPasspointProviderBssids);
2184             incrementTotalPasspointAps(mObservedHotspotR1ApInScanHistogram, passpointR1Aps);
2185             incrementTotalPasspointAps(mObservedHotspotR2ApInScanHistogram, passpointR2Aps);
2186             incrementTotalUniquePasspointEss(mObservedHotspotR1EssInScanHistogram,
2187                     passpointR1UniqueEss.size());
2188             incrementTotalUniquePasspointEss(mObservedHotspotR2EssInScanHistogram,
2189                     passpointR2UniqueEss.size());
2190             for (Integer count : passpointR1UniqueEss.values()) {
2191                 incrementPasspointPerUniqueEss(mObservedHotspotR1ApsPerEssInScanHistogram, count);
2192             }
2193             for (Integer count : passpointR2UniqueEss.values()) {
2194                 incrementPasspointPerUniqueEss(mObservedHotspotR2ApsPerEssInScanHistogram, count);
2195             }
2196             increment80211mcAps(mObserved80211mcApInScanHistogram, supporting80211mcAps);
2197         }
2198     }
2199 
2200     /**
2201      * TODO: (b/72443859) Use notifierTag param to separate metrics for OpenNetworkNotifier and
2202      * CarrierNetworkNotifier, for this method and all other related metrics.
2203      */
2204     /** Increments the occurence of a "Connect to Network" notification. */
incrementConnectToNetworkNotification(String notifierTag, int notificationType)2205     public void incrementConnectToNetworkNotification(String notifierTag, int notificationType) {
2206         synchronized (mLock) {
2207             int count = mConnectToNetworkNotificationCount.get(notificationType);
2208             mConnectToNetworkNotificationCount.put(notificationType, count + 1);
2209         }
2210     }
2211 
2212     /** Increments the occurence of an "Connect to Network" notification user action. */
incrementConnectToNetworkNotificationAction(String notifierTag, int notificationType, int actionType)2213     public void incrementConnectToNetworkNotificationAction(String notifierTag,
2214             int notificationType, int actionType) {
2215         synchronized (mLock) {
2216             int key = notificationType * CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER
2217                     + actionType;
2218             int count = mConnectToNetworkNotificationActionCount.get(key);
2219             mConnectToNetworkNotificationActionCount.put(key, count + 1);
2220         }
2221     }
2222 
2223     /**
2224      * Sets the number of SSIDs blacklisted from recommendation by the open network notification
2225      * recommender.
2226      */
setNetworkRecommenderBlacklistSize(String notifierTag, int size)2227     public void setNetworkRecommenderBlacklistSize(String notifierTag, int size) {
2228         synchronized (mLock) {
2229             mOpenNetworkRecommenderBlacklistSize = size;
2230         }
2231     }
2232 
2233     /** Sets if the available network notification feature is enabled. */
setIsWifiNetworksAvailableNotificationEnabled(String notifierTag, boolean enabled)2234     public void setIsWifiNetworksAvailableNotificationEnabled(String notifierTag, boolean enabled) {
2235         synchronized (mLock) {
2236             mIsWifiNetworksAvailableNotificationOn = enabled;
2237         }
2238     }
2239 
2240     /** Increments the occurence of connection attempts that were initiated unsuccessfully */
incrementNumNetworkRecommendationUpdates(String notifierTag)2241     public void incrementNumNetworkRecommendationUpdates(String notifierTag) {
2242         synchronized (mLock) {
2243             mNumOpenNetworkRecommendationUpdates++;
2244         }
2245     }
2246 
2247     /** Increments the occurence of connection attempts that were initiated unsuccessfully */
incrementNumNetworkConnectMessageFailedToSend(String notifierTag)2248     public void incrementNumNetworkConnectMessageFailedToSend(String notifierTag) {
2249         synchronized (mLock) {
2250             mNumOpenNetworkConnectMessageFailedToSend++;
2251         }
2252     }
2253 
2254     /** Sets if Connected MAC Randomization feature is enabled */
setIsMacRandomizationOn(boolean enabled)2255     public void setIsMacRandomizationOn(boolean enabled) {
2256         synchronized (mLock) {
2257             mIsMacRandomizationOn = enabled;
2258         }
2259     }
2260 
2261     /** Log firmware alert related metrics */
logFirmwareAlert(int errorCode)2262     public void logFirmwareAlert(int errorCode) {
2263         incrementAlertReasonCount(errorCode);
2264         logWifiIsUnusableEvent(WifiIsUnusableEvent.TYPE_FIRMWARE_ALERT, errorCode);
2265         addToWifiUsabilityStatsList(WifiUsabilityStats.LABEL_BAD,
2266                 WifiUsabilityStats.TYPE_FIRMWARE_ALERT, errorCode);
2267     }
2268 
2269     public static final String PROTO_DUMP_ARG = "wifiMetricsProto";
2270     public static final String CLEAN_DUMP_ARG = "clean";
2271 
2272     /**
2273      * Dump all WifiMetrics. Collects some metrics from ConfigStore, Settings and WifiManager
2274      * at this time.
2275      *
2276      * @param fd unused
2277      * @param pw PrintWriter for writing dump to
2278      * @param args [wifiMetricsProto [clean]]
2279      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)2280     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2281         synchronized (mLock) {
2282             consolidateScoringParams();
2283             if (args != null && args.length > 0 && PROTO_DUMP_ARG.equals(args[0])) {
2284                 // Dump serialized WifiLog proto
2285                 consolidateProto();
2286 
2287                 byte[] wifiMetricsProto = WifiMetricsProto.WifiLog.toByteArray(mWifiLogProto);
2288                 String metricsProtoDump = Base64.encodeToString(wifiMetricsProto, Base64.DEFAULT);
2289                 if (args.length > 1 && CLEAN_DUMP_ARG.equals(args[1])) {
2290                     // Output metrics proto bytes (base64) and nothing else
2291                     pw.print(metricsProtoDump);
2292                 } else {
2293                     // Tag the start and end of the metrics proto bytes
2294                     pw.println("WifiMetrics:");
2295                     pw.println(metricsProtoDump);
2296                     pw.println("EndWifiMetrics");
2297                 }
2298                 clear();
2299             } else {
2300                 pw.println("WifiMetrics:");
2301                 pw.println("mConnectionEvents:");
2302                 for (ConnectionEvent event : mConnectionEventList) {
2303                     String eventLine = event.toString();
2304                     if (event == mCurrentConnectionEvent) {
2305                         eventLine += "CURRENTLY OPEN EVENT";
2306                     }
2307                     pw.println(eventLine);
2308                 }
2309                 pw.println("mWifiLogProto.numSavedNetworks=" + mWifiLogProto.numSavedNetworks);
2310                 pw.println("mWifiLogProto.numSavedNetworksWithMacRandomization="
2311                         + mWifiLogProto.numSavedNetworksWithMacRandomization);
2312                 pw.println("mWifiLogProto.numOpenNetworks=" + mWifiLogProto.numOpenNetworks);
2313                 pw.println("mWifiLogProto.numLegacyPersonalNetworks="
2314                         + mWifiLogProto.numLegacyPersonalNetworks);
2315                 pw.println("mWifiLogProto.numLegacyEnterpriseNetworks="
2316                         + mWifiLogProto.numLegacyEnterpriseNetworks);
2317                 pw.println("mWifiLogProto.numEnhancedOpenNetworks="
2318                         + mWifiLogProto.numEnhancedOpenNetworks);
2319                 pw.println("mWifiLogProto.numWpa3PersonalNetworks="
2320                         + mWifiLogProto.numWpa3PersonalNetworks);
2321                 pw.println("mWifiLogProto.numWpa3EnterpriseNetworks="
2322                         + mWifiLogProto.numWpa3EnterpriseNetworks);
2323                 pw.println("mWifiLogProto.numHiddenNetworks=" + mWifiLogProto.numHiddenNetworks);
2324                 pw.println("mWifiLogProto.numPasspointNetworks="
2325                         + mWifiLogProto.numPasspointNetworks);
2326                 pw.println("mWifiLogProto.isLocationEnabled=" + mWifiLogProto.isLocationEnabled);
2327                 pw.println("mWifiLogProto.isScanningAlwaysEnabled="
2328                         + mWifiLogProto.isScanningAlwaysEnabled);
2329                 pw.println("mWifiLogProto.numNetworksAddedByUser="
2330                         + mWifiLogProto.numNetworksAddedByUser);
2331                 pw.println("mWifiLogProto.numNetworksAddedByApps="
2332                         + mWifiLogProto.numNetworksAddedByApps);
2333                 pw.println("mWifiLogProto.numNonEmptyScanResults="
2334                         + mWifiLogProto.numNonEmptyScanResults);
2335                 pw.println("mWifiLogProto.numEmptyScanResults="
2336                         + mWifiLogProto.numEmptyScanResults);
2337                 pw.println("mWifiLogProto.numConnecitvityOneshotScans="
2338                         + mWifiLogProto.numConnectivityOneshotScans);
2339                 pw.println("mWifiLogProto.numOneshotScans="
2340                         + mWifiLogProto.numOneshotScans);
2341                 pw.println("mWifiLogProto.numOneshotHasDfsChannelScans="
2342                         + mWifiLogProto.numOneshotHasDfsChannelScans);
2343                 pw.println("mWifiLogProto.numBackgroundScans="
2344                         + mWifiLogProto.numBackgroundScans);
2345                 pw.println("mWifiLogProto.numExternalAppOneshotScanRequests="
2346                         + mWifiLogProto.numExternalAppOneshotScanRequests);
2347                 pw.println("mWifiLogProto.numExternalForegroundAppOneshotScanRequestsThrottled="
2348                         + mWifiLogProto.numExternalForegroundAppOneshotScanRequestsThrottled);
2349                 pw.println("mWifiLogProto.numExternalBackgroundAppOneshotScanRequestsThrottled="
2350                         + mWifiLogProto.numExternalBackgroundAppOneshotScanRequestsThrottled);
2351 
2352                 pw.println("mScanReturnEntries:");
2353                 pw.println("  SCAN_UNKNOWN: " + getScanReturnEntry(
2354                         WifiMetricsProto.WifiLog.SCAN_UNKNOWN));
2355                 pw.println("  SCAN_SUCCESS: " + getScanReturnEntry(
2356                         WifiMetricsProto.WifiLog.SCAN_SUCCESS));
2357                 pw.println("  SCAN_FAILURE_INTERRUPTED: " + getScanReturnEntry(
2358                         WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED));
2359                 pw.println("  SCAN_FAILURE_INVALID_CONFIGURATION: " + getScanReturnEntry(
2360                         WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION));
2361                 pw.println("  FAILURE_WIFI_DISABLED: " + getScanReturnEntry(
2362                         WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED));
2363 
2364                 pw.println("mSystemStateEntries: <state><screenOn> : <scansInitiated>");
2365                 pw.println("  WIFI_UNKNOWN       ON: "
2366                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, true));
2367                 pw.println("  WIFI_DISABLED      ON: "
2368                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, true));
2369                 pw.println("  WIFI_DISCONNECTED  ON: "
2370                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, true));
2371                 pw.println("  WIFI_ASSOCIATED    ON: "
2372                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, true));
2373                 pw.println("  WIFI_UNKNOWN      OFF: "
2374                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, false));
2375                 pw.println("  WIFI_DISABLED     OFF: "
2376                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, false));
2377                 pw.println("  WIFI_DISCONNECTED OFF: "
2378                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, false));
2379                 pw.println("  WIFI_ASSOCIATED   OFF: "
2380                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, false));
2381                 pw.println("mWifiLogProto.numConnectivityWatchdogPnoGood="
2382                         + mWifiLogProto.numConnectivityWatchdogPnoGood);
2383                 pw.println("mWifiLogProto.numConnectivityWatchdogPnoBad="
2384                         + mWifiLogProto.numConnectivityWatchdogPnoBad);
2385                 pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundGood="
2386                         + mWifiLogProto.numConnectivityWatchdogBackgroundGood);
2387                 pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundBad="
2388                         + mWifiLogProto.numConnectivityWatchdogBackgroundBad);
2389                 pw.println("mWifiLogProto.numLastResortWatchdogTriggers="
2390                         + mWifiLogProto.numLastResortWatchdogTriggers);
2391                 pw.println("mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal="
2392                         + mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal);
2393                 pw.println("mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal="
2394                         + mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal);
2395                 pw.println("mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal="
2396                         + mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal);
2397                 pw.println("mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal="
2398                         + mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal);
2399                 pw.println("mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal="
2400                         + mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal);
2401                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation="
2402                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation);
2403                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication="
2404                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication);
2405                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp="
2406                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp);
2407                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadOther="
2408                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadOther);
2409                 pw.println("mWifiLogProto.numLastResortWatchdogSuccesses="
2410                         + mWifiLogProto.numLastResortWatchdogSuccesses);
2411                 pw.println("mWifiLogProto.watchdogTotalConnectionFailureCountAfterTrigger="
2412                         + mWifiLogProto.watchdogTotalConnectionFailureCountAfterTrigger);
2413                 pw.println("mWifiLogProto.watchdogTriggerToConnectionSuccessDurationMs="
2414                         + mWifiLogProto.watchdogTriggerToConnectionSuccessDurationMs);
2415                 pw.println("mWifiLogProto.recordDurationSec="
2416                         + ((mClock.getElapsedSinceBootMillis() / 1000) - mRecordStartTimeSec));
2417 
2418                 try {
2419                     JSONObject rssiMap = new JSONObject();
2420                     for (Map.Entry<Integer, SparseIntArray> entry : mRssiPollCountsMap.entrySet()) {
2421                         int frequency = entry.getKey();
2422                         final SparseIntArray histogram = entry.getValue();
2423                         JSONArray histogramElements = new JSONArray();
2424                         for (int i = MIN_RSSI_POLL; i <= MAX_RSSI_POLL; i++) {
2425                             int count = histogram.get(i);
2426                             if (count == 0) {
2427                                 continue;
2428                             }
2429                             JSONObject histogramElement = new JSONObject();
2430                             histogramElement.put(Integer.toString(i), count);
2431                             histogramElements.put(histogramElement);
2432                         }
2433                         rssiMap.put(Integer.toString(frequency), histogramElements);
2434                     }
2435                     pw.println("mWifiLogProto.rssiPollCount: " + rssiMap.toString());
2436                 } catch (JSONException e) {
2437                     pw.println("JSONException occurred: " + e.getMessage());
2438                 }
2439 
2440                 pw.println("mWifiLogProto.rssiPollDeltaCount: Printing counts for ["
2441                         + MIN_RSSI_DELTA + ", " + MAX_RSSI_DELTA + "]");
2442                 StringBuilder sb = new StringBuilder();
2443                 for (int i = MIN_RSSI_DELTA; i <= MAX_RSSI_DELTA; i++) {
2444                     sb.append(mRssiDeltaCounts.get(i) + " ");
2445                 }
2446                 pw.println("  " + sb.toString());
2447                 pw.println("mWifiLogProto.linkSpeedCounts: ");
2448                 sb.setLength(0);
2449                 for (int i = 0; i < mLinkSpeedCounts.size(); i++) {
2450                     LinkSpeedCount linkSpeedCount = mLinkSpeedCounts.valueAt(i);
2451                     sb.append(linkSpeedCount.linkSpeedMbps).append(":{")
2452                             .append(linkSpeedCount.count).append(", ")
2453                             .append(linkSpeedCount.rssiSumDbm).append(", ")
2454                             .append(linkSpeedCount.rssiSumOfSquaresDbmSq).append("} ");
2455                 }
2456                 if (sb.length() > 0) {
2457                     pw.println(sb.toString());
2458                 }
2459                 pw.print("mWifiLogProto.alertReasonCounts=");
2460                 sb.setLength(0);
2461                 for (int i = WifiLoggerHal.WIFI_ALERT_REASON_MIN;
2462                         i <= WifiLoggerHal.WIFI_ALERT_REASON_MAX; i++) {
2463                     int count = mWifiAlertReasonCounts.get(i);
2464                     if (count > 0) {
2465                         sb.append("(" + i + "," + count + "),");
2466                     }
2467                 }
2468                 if (sb.length() > 1) {
2469                     sb.setLength(sb.length() - 1);  // strip trailing comma
2470                     pw.println(sb.toString());
2471                 } else {
2472                     pw.println("()");
2473                 }
2474                 pw.println("mWifiLogProto.numTotalScanResults="
2475                         + mWifiLogProto.numTotalScanResults);
2476                 pw.println("mWifiLogProto.numOpenNetworkScanResults="
2477                         + mWifiLogProto.numOpenNetworkScanResults);
2478                 pw.println("mWifiLogProto.numLegacyPersonalNetworkScanResults="
2479                         + mWifiLogProto.numLegacyPersonalNetworkScanResults);
2480                 pw.println("mWifiLogProto.numLegacyEnterpriseNetworkScanResults="
2481                         + mWifiLogProto.numLegacyEnterpriseNetworkScanResults);
2482                 pw.println("mWifiLogProto.numEnhancedOpenNetworkScanResults="
2483                         + mWifiLogProto.numEnhancedOpenNetworkScanResults);
2484                 pw.println("mWifiLogProto.numWpa3PersonalNetworkScanResults="
2485                         + mWifiLogProto.numWpa3PersonalNetworkScanResults);
2486                 pw.println("mWifiLogProto.numWpa3EnterpriseNetworkScanResults="
2487                         + mWifiLogProto.numWpa3EnterpriseNetworkScanResults);
2488                 pw.println("mWifiLogProto.numHiddenNetworkScanResults="
2489                         + mWifiLogProto.numHiddenNetworkScanResults);
2490                 pw.println("mWifiLogProto.numHotspot2R1NetworkScanResults="
2491                         + mWifiLogProto.numHotspot2R1NetworkScanResults);
2492                 pw.println("mWifiLogProto.numHotspot2R2NetworkScanResults="
2493                         + mWifiLogProto.numHotspot2R2NetworkScanResults);
2494                 pw.println("mWifiLogProto.numScans=" + mWifiLogProto.numScans);
2495                 pw.println("mWifiLogProto.WifiScoreCount: [" + MIN_WIFI_SCORE + ", "
2496                         + MAX_WIFI_SCORE + "]");
2497                 for (int i = 0; i <= MAX_WIFI_SCORE; i++) {
2498                     pw.print(mWifiScoreCounts.get(i) + " ");
2499                 }
2500                 pw.println(); // add a line after wifi scores
2501                 pw.println("mWifiLogProto.WifiUsabilityScoreCount: [" + MIN_WIFI_USABILITY_SCORE
2502                         + ", " + MAX_WIFI_USABILITY_SCORE + "]");
2503                 for (int i = MIN_WIFI_USABILITY_SCORE; i <= MAX_WIFI_USABILITY_SCORE; i++) {
2504                     pw.print(mWifiUsabilityScoreCounts.get(i) + " ");
2505                 }
2506                 pw.println(); // add a line after wifi usability scores
2507                 pw.println("mWifiLogProto.SoftApManagerReturnCodeCounts:");
2508                 pw.println("  SUCCESS: " + mSoftApManagerReturnCodeCounts.get(
2509                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY));
2510                 pw.println("  FAILED_GENERAL_ERROR: " + mSoftApManagerReturnCodeCounts.get(
2511                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR));
2512                 pw.println("  FAILED_NO_CHANNEL: " + mSoftApManagerReturnCodeCounts.get(
2513                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL));
2514                 pw.print("\n");
2515                 pw.println("mWifiLogProto.numHalCrashes="
2516                         + mWifiLogProto.numHalCrashes);
2517                 pw.println("mWifiLogProto.numWificondCrashes="
2518                         + mWifiLogProto.numWificondCrashes);
2519                 pw.println("mWifiLogProto.numSupplicantCrashes="
2520                         + mWifiLogProto.numSupplicantCrashes);
2521                 pw.println("mWifiLogProto.numHostapdCrashes="
2522                         + mWifiLogProto.numHostapdCrashes);
2523                 pw.println("mWifiLogProto.numSetupClientInterfaceFailureDueToHal="
2524                         + mWifiLogProto.numSetupClientInterfaceFailureDueToHal);
2525                 pw.println("mWifiLogProto.numSetupClientInterfaceFailureDueToWificond="
2526                         + mWifiLogProto.numSetupClientInterfaceFailureDueToWificond);
2527                 pw.println("mWifiLogProto.numSetupClientInterfaceFailureDueToSupplicant="
2528                         + mWifiLogProto.numSetupClientInterfaceFailureDueToSupplicant);
2529                 pw.println("mWifiLogProto.numSetupSoftApInterfaceFailureDueToHal="
2530                         + mWifiLogProto.numSetupSoftApInterfaceFailureDueToHal);
2531                 pw.println("mWifiLogProto.numSetupSoftApInterfaceFailureDueToWificond="
2532                         + mWifiLogProto.numSetupSoftApInterfaceFailureDueToWificond);
2533                 pw.println("mWifiLogProto.numSetupSoftApInterfaceFailureDueToHostapd="
2534                         + mWifiLogProto.numSetupSoftApInterfaceFailureDueToHostapd);
2535                 pw.println("mWifiLogProto.numSarSensorRegistrationFailures="
2536                         + mWifiLogProto.numSarSensorRegistrationFailures);
2537                 pw.println("StaEventList:");
2538                 for (StaEventWithTime event : mStaEventList) {
2539                     pw.println(event);
2540                 }
2541 
2542                 pw.println("mWifiLogProto.numPasspointProviders="
2543                         + mWifiLogProto.numPasspointProviders);
2544                 pw.println("mWifiLogProto.numPasspointProviderInstallation="
2545                         + mWifiLogProto.numPasspointProviderInstallation);
2546                 pw.println("mWifiLogProto.numPasspointProviderInstallSuccess="
2547                         + mWifiLogProto.numPasspointProviderInstallSuccess);
2548                 pw.println("mWifiLogProto.numPasspointProviderUninstallation="
2549                         + mWifiLogProto.numPasspointProviderUninstallation);
2550                 pw.println("mWifiLogProto.numPasspointProviderUninstallSuccess="
2551                         + mWifiLogProto.numPasspointProviderUninstallSuccess);
2552                 pw.println("mWifiLogProto.numPasspointProvidersSuccessfullyConnected="
2553                         + mWifiLogProto.numPasspointProvidersSuccessfullyConnected);
2554 
2555                 pw.println("mWifiLogProto.installedPasspointProfileTypeForR1:"
2556                         + mInstalledPasspointProfileTypeForR1);
2557                 pw.println("mWifiLogProto.installedPasspointProfileTypeForR2:"
2558                         + mInstalledPasspointProfileTypeForR2);
2559 
2560                 pw.println("mWifiLogProto.passpointProvisionStats.numProvisionSuccess="
2561                             + mNumProvisionSuccess);
2562                 pw.println("mWifiLogProto.passpointProvisionStats.provisionFailureCount:"
2563                             + mPasspointProvisionFailureCounts);
2564 
2565                 pw.println("mWifiLogProto.numRadioModeChangeToMcc="
2566                         + mWifiLogProto.numRadioModeChangeToMcc);
2567                 pw.println("mWifiLogProto.numRadioModeChangeToScc="
2568                         + mWifiLogProto.numRadioModeChangeToScc);
2569                 pw.println("mWifiLogProto.numRadioModeChangeToSbs="
2570                         + mWifiLogProto.numRadioModeChangeToSbs);
2571                 pw.println("mWifiLogProto.numRadioModeChangeToDbs="
2572                         + mWifiLogProto.numRadioModeChangeToDbs);
2573                 pw.println("mWifiLogProto.numSoftApUserBandPreferenceUnsatisfied="
2574                         + mWifiLogProto.numSoftApUserBandPreferenceUnsatisfied);
2575                 pw.println("mTotalSsidsInScanHistogram:"
2576                         + mTotalSsidsInScanHistogram.toString());
2577                 pw.println("mTotalBssidsInScanHistogram:"
2578                         + mTotalBssidsInScanHistogram.toString());
2579                 pw.println("mAvailableOpenSsidsInScanHistogram:"
2580                         + mAvailableOpenSsidsInScanHistogram.toString());
2581                 pw.println("mAvailableOpenBssidsInScanHistogram:"
2582                         + mAvailableOpenBssidsInScanHistogram.toString());
2583                 pw.println("mAvailableSavedSsidsInScanHistogram:"
2584                         + mAvailableSavedSsidsInScanHistogram.toString());
2585                 pw.println("mAvailableSavedBssidsInScanHistogram:"
2586                         + mAvailableSavedBssidsInScanHistogram.toString());
2587                 pw.println("mAvailableOpenOrSavedSsidsInScanHistogram:"
2588                         + mAvailableOpenOrSavedSsidsInScanHistogram.toString());
2589                 pw.println("mAvailableOpenOrSavedBssidsInScanHistogram:"
2590                         + mAvailableOpenOrSavedBssidsInScanHistogram.toString());
2591                 pw.println("mAvailableSavedPasspointProviderProfilesInScanHistogram:"
2592                         + mAvailableSavedPasspointProviderProfilesInScanHistogram.toString());
2593                 pw.println("mAvailableSavedPasspointProviderBssidsInScanHistogram:"
2594                         + mAvailableSavedPasspointProviderBssidsInScanHistogram.toString());
2595                 pw.println("mWifiLogProto.partialAllSingleScanListenerResults="
2596                         + mWifiLogProto.partialAllSingleScanListenerResults);
2597                 pw.println("mWifiLogProto.fullBandAllSingleScanListenerResults="
2598                         + mWifiLogProto.fullBandAllSingleScanListenerResults);
2599                 pw.println("mWifiAwareMetrics:");
2600                 mWifiAwareMetrics.dump(fd, pw, args);
2601                 pw.println("mRttMetrics:");
2602                 mRttMetrics.dump(fd, pw, args);
2603 
2604                 pw.println("mPnoScanMetrics.numPnoScanAttempts="
2605                         + mPnoScanMetrics.numPnoScanAttempts);
2606                 pw.println("mPnoScanMetrics.numPnoScanFailed="
2607                         + mPnoScanMetrics.numPnoScanFailed);
2608                 pw.println("mPnoScanMetrics.numPnoScanStartedOverOffload="
2609                         + mPnoScanMetrics.numPnoScanStartedOverOffload);
2610                 pw.println("mPnoScanMetrics.numPnoScanFailedOverOffload="
2611                         + mPnoScanMetrics.numPnoScanFailedOverOffload);
2612                 pw.println("mPnoScanMetrics.numPnoFoundNetworkEvents="
2613                         + mPnoScanMetrics.numPnoFoundNetworkEvents);
2614 
2615                 pw.println("mWifiLinkLayerUsageStats.loggingDurationMs="
2616                         + mWifiLinkLayerUsageStats.loggingDurationMs);
2617                 pw.println("mWifiLinkLayerUsageStats.radioOnTimeMs="
2618                         + mWifiLinkLayerUsageStats.radioOnTimeMs);
2619                 pw.println("mWifiLinkLayerUsageStats.radioTxTimeMs="
2620                         + mWifiLinkLayerUsageStats.radioTxTimeMs);
2621                 pw.println("mWifiLinkLayerUsageStats.radioRxTimeMs="
2622                         + mWifiLinkLayerUsageStats.radioRxTimeMs);
2623                 pw.println("mWifiLinkLayerUsageStats.radioScanTimeMs="
2624                         + mWifiLinkLayerUsageStats.radioScanTimeMs);
2625                 pw.println("mWifiLinkLayerUsageStats.radioNanScanTimeMs="
2626                         + mWifiLinkLayerUsageStats.radioNanScanTimeMs);
2627                 pw.println("mWifiLinkLayerUsageStats.radioBackgroundScanTimeMs="
2628                         + mWifiLinkLayerUsageStats.radioBackgroundScanTimeMs);
2629                 pw.println("mWifiLinkLayerUsageStats.radioRoamScanTimeMs="
2630                         + mWifiLinkLayerUsageStats.radioRoamScanTimeMs);
2631                 pw.println("mWifiLinkLayerUsageStats.radioPnoScanTimeMs="
2632                         + mWifiLinkLayerUsageStats.radioPnoScanTimeMs);
2633                 pw.println("mWifiLinkLayerUsageStats.radioHs20ScanTimeMs="
2634                         + mWifiLinkLayerUsageStats.radioHs20ScanTimeMs);
2635 
2636                 pw.println("mWifiLogProto.connectToNetworkNotificationCount="
2637                         + mConnectToNetworkNotificationCount.toString());
2638                 pw.println("mWifiLogProto.connectToNetworkNotificationActionCount="
2639                         + mConnectToNetworkNotificationActionCount.toString());
2640                 pw.println("mWifiLogProto.openNetworkRecommenderBlacklistSize="
2641                         + mOpenNetworkRecommenderBlacklistSize);
2642                 pw.println("mWifiLogProto.isWifiNetworksAvailableNotificationOn="
2643                         + mIsWifiNetworksAvailableNotificationOn);
2644                 pw.println("mWifiLogProto.numOpenNetworkRecommendationUpdates="
2645                         + mNumOpenNetworkRecommendationUpdates);
2646                 pw.println("mWifiLogProto.numOpenNetworkConnectMessageFailedToSend="
2647                         + mNumOpenNetworkConnectMessageFailedToSend);
2648 
2649                 pw.println("mWifiLogProto.observedHotspotR1ApInScanHistogram="
2650                         + mObservedHotspotR1ApInScanHistogram);
2651                 pw.println("mWifiLogProto.observedHotspotR2ApInScanHistogram="
2652                         + mObservedHotspotR2ApInScanHistogram);
2653                 pw.println("mWifiLogProto.observedHotspotR1EssInScanHistogram="
2654                         + mObservedHotspotR1EssInScanHistogram);
2655                 pw.println("mWifiLogProto.observedHotspotR2EssInScanHistogram="
2656                         + mObservedHotspotR2EssInScanHistogram);
2657                 pw.println("mWifiLogProto.observedHotspotR1ApsPerEssInScanHistogram="
2658                         + mObservedHotspotR1ApsPerEssInScanHistogram);
2659                 pw.println("mWifiLogProto.observedHotspotR2ApsPerEssInScanHistogram="
2660                         + mObservedHotspotR2ApsPerEssInScanHistogram);
2661 
2662                 pw.println("mWifiLogProto.observed80211mcSupportingApsInScanHistogram"
2663                         + mObserved80211mcApInScanHistogram);
2664 
2665                 pw.println("mSoftApTetheredEvents:");
2666                 for (SoftApConnectedClientsEvent event : mSoftApEventListTethered) {
2667                     StringBuilder eventLine = new StringBuilder();
2668                     eventLine.append("event_type=" + event.eventType);
2669                     eventLine.append(",time_stamp_millis=" + event.timeStampMillis);
2670                     eventLine.append(",num_connected_clients=" + event.numConnectedClients);
2671                     eventLine.append(",channel_frequency=" + event.channelFrequency);
2672                     eventLine.append(",channel_bandwidth=" + event.channelBandwidth);
2673                     pw.println(eventLine.toString());
2674                 }
2675                 pw.println("mSoftApLocalOnlyEvents:");
2676                 for (SoftApConnectedClientsEvent event : mSoftApEventListLocalOnly) {
2677                     StringBuilder eventLine = new StringBuilder();
2678                     eventLine.append("event_type=" + event.eventType);
2679                     eventLine.append(",time_stamp_millis=" + event.timeStampMillis);
2680                     eventLine.append(",num_connected_clients=" + event.numConnectedClients);
2681                     eventLine.append(",channel_frequency=" + event.channelFrequency);
2682                     eventLine.append(",channel_bandwidth=" + event.channelBandwidth);
2683                     pw.println(eventLine.toString());
2684                 }
2685 
2686                 pw.println("mWpsMetrics.numWpsAttempts="
2687                         + mWpsMetrics.numWpsAttempts);
2688                 pw.println("mWpsMetrics.numWpsSuccess="
2689                         + mWpsMetrics.numWpsSuccess);
2690                 pw.println("mWpsMetrics.numWpsStartFailure="
2691                         + mWpsMetrics.numWpsStartFailure);
2692                 pw.println("mWpsMetrics.numWpsOverlapFailure="
2693                         + mWpsMetrics.numWpsOverlapFailure);
2694                 pw.println("mWpsMetrics.numWpsTimeoutFailure="
2695                         + mWpsMetrics.numWpsTimeoutFailure);
2696                 pw.println("mWpsMetrics.numWpsOtherConnectionFailure="
2697                         + mWpsMetrics.numWpsOtherConnectionFailure);
2698                 pw.println("mWpsMetrics.numWpsSupplicantFailure="
2699                         + mWpsMetrics.numWpsSupplicantFailure);
2700                 pw.println("mWpsMetrics.numWpsCancellation="
2701                         + mWpsMetrics.numWpsCancellation);
2702 
2703                 mWifiPowerMetrics.dump(pw);
2704                 mWifiWakeMetrics.dump(pw);
2705 
2706                 pw.println("mWifiLogProto.isMacRandomizationOn=" + mIsMacRandomizationOn);
2707                 pw.println("mWifiLogProto.scoreExperimentId=" + mWifiLogProto.scoreExperimentId);
2708                 pw.println("mExperimentValues.wifiIsUnusableLoggingEnabled="
2709                         + mExperimentValues.wifiIsUnusableLoggingEnabled);
2710                 pw.println("mExperimentValues.wifiDataStallMinTxBad="
2711                         + mExperimentValues.wifiDataStallMinTxBad);
2712                 pw.println("mExperimentValues.wifiDataStallMinTxSuccessWithoutRx="
2713                         + mExperimentValues.wifiDataStallMinTxSuccessWithoutRx);
2714                 pw.println("mExperimentValues.linkSpeedCountsLoggingEnabled="
2715                         + mExperimentValues.linkSpeedCountsLoggingEnabled);
2716                 pw.println("WifiIsUnusableEventList: ");
2717                 for (WifiIsUnusableWithTime event : mWifiIsUnusableList) {
2718                     pw.println(event);
2719                 }
2720                 pw.println("Hardware Version: " + SystemProperties.get("ro.boot.revision", ""));
2721 
2722                 pw.println("mWifiUsabilityStatsEntriesList:");
2723                 for (WifiUsabilityStatsEntry stats : mWifiUsabilityStatsEntriesList) {
2724                     printWifiUsabilityStatsEntry(pw, stats);
2725                 }
2726                 pw.println("mWifiUsabilityStatsList:");
2727                 for (WifiUsabilityStats stats : mWifiUsabilityStatsListGood) {
2728                     pw.println("\nlabel=" + stats.label);
2729                     pw.println("\ntrigger_type=" + stats.triggerType);
2730                     pw.println("\ntime_stamp_ms=" + stats.timeStampMs);
2731                     for (WifiUsabilityStatsEntry entry : stats.stats) {
2732                         printWifiUsabilityStatsEntry(pw, entry);
2733                     }
2734                 }
2735                 for (WifiUsabilityStats stats : mWifiUsabilityStatsListBad) {
2736                     pw.println("\nlabel=" + stats.label);
2737                     pw.println("\ntrigger_type=" + stats.triggerType);
2738                     pw.println("\ntime_stamp_ms=" + stats.timeStampMs);
2739                     for (WifiUsabilityStatsEntry entry : stats.stats) {
2740                         printWifiUsabilityStatsEntry(pw, entry);
2741                     }
2742                 }
2743 
2744                 pw.println("mMobilityStatePnoStatsMap:");
2745                 for (int i = 0; i < mMobilityStatePnoStatsMap.size(); i++) {
2746                     printDeviceMobilityStatePnoScanStats(pw, mMobilityStatePnoStatsMap.valueAt(i));
2747                 }
2748 
2749                 mWifiP2pMetrics.dump(pw);
2750                 pw.println("mDppMetrics:");
2751                 mDppMetrics.dump(pw);
2752 
2753                 pw.println("mWifiConfigStoreReadDurationHistogram:"
2754                         + mWifiConfigStoreReadDurationHistogram.toString());
2755                 pw.println("mWifiConfigStoreWriteDurationHistogram:"
2756                         + mWifiConfigStoreWriteDurationHistogram.toString());
2757 
2758                 pw.println("mLinkProbeSuccessRssiCounts:" + mLinkProbeSuccessRssiCounts);
2759                 pw.println("mLinkProbeFailureRssiCounts:" + mLinkProbeFailureRssiCounts);
2760                 pw.println("mLinkProbeSuccessLinkSpeedCounts:" + mLinkProbeSuccessLinkSpeedCounts);
2761                 pw.println("mLinkProbeFailureLinkSpeedCounts:" + mLinkProbeFailureLinkSpeedCounts);
2762                 pw.println("mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram:"
2763                         + mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram);
2764                 pw.println("mLinkProbeFailureSecondsSinceLastTxSuccessHistogram:"
2765                         + mLinkProbeFailureSecondsSinceLastTxSuccessHistogram);
2766                 pw.println("mLinkProbeSuccessElapsedTimeMsHistogram:"
2767                         + mLinkProbeSuccessElapsedTimeMsHistogram);
2768                 pw.println("mLinkProbeFailureReasonCounts:" + mLinkProbeFailureReasonCounts);
2769                 pw.println("mLinkProbeExperimentProbeCounts:" + mLinkProbeExperimentProbeCounts);
2770 
2771                 pw.println("mNetworkSelectionExperimentPairNumChoicesCounts:"
2772                         + mNetworkSelectionExperimentPairNumChoicesCounts);
2773                 pw.println("mLinkProbeStaEventCount:" + mLinkProbeStaEventCount);
2774 
2775                 pw.println("mWifiNetworkRequestApiLog:\n" + mWifiNetworkRequestApiLog);
2776                 pw.println("mWifiNetworkRequestApiMatchSizeHistogram:\n"
2777                         + mWifiNetworkRequestApiMatchSizeHistogram);
2778                 pw.println("mWifiNetworkSuggestionApiLog:\n" + mWifiNetworkSuggestionApiLog);
2779                 pw.println("mWifiNetworkSuggestionApiMatchSizeHistogram:\n"
2780                         + mWifiNetworkRequestApiMatchSizeHistogram);
2781                 pw.println("mNetworkIdToNominatorId:\n" + mNetworkIdToNominatorId);
2782                 pw.println("mWifiLockStats:\n" + mWifiLockStats);
2783                 pw.println("mWifiLockHighPerfAcqDurationSecHistogram:\n"
2784                         + mWifiLockHighPerfAcqDurationSecHistogram);
2785                 pw.println("mWifiLockLowLatencyAcqDurationSecHistogram:\n"
2786                         + mWifiLockLowLatencyAcqDurationSecHistogram);
2787                 pw.println("mWifiLockHighPerfActiveSessionDurationSecHistogram:\n"
2788                         + mWifiLockHighPerfActiveSessionDurationSecHistogram);
2789                 pw.println("mWifiLockLowLatencyActiveSessionDurationSecHistogram:\n"
2790                         + mWifiLockLowLatencyActiveSessionDurationSecHistogram);
2791                 pw.println("mWifiToggleStats:\n" + mWifiToggleStats);
2792                 pw.println("mWifiLogProto.numAddOrUpdateNetworkCalls="
2793                         + mWifiLogProto.numAddOrUpdateNetworkCalls);
2794                 pw.println("mWifiLogProto.numEnableNetworkCalls="
2795                         + mWifiLogProto.numEnableNetworkCalls);
2796             }
2797         }
2798     }
2799 
printWifiUsabilityStatsEntry(PrintWriter pw, WifiUsabilityStatsEntry entry)2800     private void printWifiUsabilityStatsEntry(PrintWriter pw, WifiUsabilityStatsEntry entry) {
2801         StringBuilder line = new StringBuilder();
2802         line.append("timestamp_ms=" + entry.timeStampMs);
2803         line.append(",rssi=" + entry.rssi);
2804         line.append(",link_speed_mbps=" + entry.linkSpeedMbps);
2805         line.append(",total_tx_success=" + entry.totalTxSuccess);
2806         line.append(",total_tx_retries=" + entry.totalTxRetries);
2807         line.append(",total_tx_bad=" + entry.totalTxBad);
2808         line.append(",total_rx_success=" + entry.totalRxSuccess);
2809         line.append(",total_radio_on_time_ms=" + entry.totalRadioOnTimeMs);
2810         line.append(",total_radio_tx_time_ms=" + entry.totalRadioTxTimeMs);
2811         line.append(",total_radio_rx_time_ms=" + entry.totalRadioRxTimeMs);
2812         line.append(",total_scan_time_ms=" + entry.totalScanTimeMs);
2813         line.append(",total_nan_scan_time_ms=" + entry.totalNanScanTimeMs);
2814         line.append(",total_background_scan_time_ms=" + entry.totalBackgroundScanTimeMs);
2815         line.append(",total_roam_scan_time_ms=" + entry.totalRoamScanTimeMs);
2816         line.append(",total_pno_scan_time_ms=" + entry.totalPnoScanTimeMs);
2817         line.append(",total_hotspot_2_scan_time_ms=" + entry.totalHotspot2ScanTimeMs);
2818         line.append(",wifi_score=" + entry.wifiScore);
2819         line.append(",wifi_usability_score=" + entry.wifiUsabilityScore);
2820         line.append(",seq_num_to_framework=" + entry.seqNumToFramework);
2821         line.append(",prediction_horizon_sec=" + entry.predictionHorizonSec);
2822         line.append(",total_cca_busy_freq_time_ms=" + entry.totalCcaBusyFreqTimeMs);
2823         line.append(",total_radio_on_freq_time_ms=" + entry.totalRadioOnFreqTimeMs);
2824         line.append(",total_beacon_rx=" + entry.totalBeaconRx);
2825         line.append(",probe_status_since_last_update=" + entry.probeStatusSinceLastUpdate);
2826         line.append(",probe_elapsed_time_ms_since_last_update="
2827                 + entry.probeElapsedTimeSinceLastUpdateMs);
2828         line.append(",probe_mcs_rate_since_last_update=" + entry.probeMcsRateSinceLastUpdate);
2829         line.append(",rx_link_speed_mbps=" + entry.rxLinkSpeedMbps);
2830         line.append(",seq_num_inside_framework=" + entry.seqNumInsideFramework);
2831         line.append(",is_same_bssid_and_freq=" + entry.isSameBssidAndFreq);
2832         line.append(",cellular_data_network_type=" + entry.cellularDataNetworkType);
2833         line.append(",cellular_signal_strength_dbm=" + entry.cellularSignalStrengthDbm);
2834         line.append(",cellular_signal_strength_db=" + entry.cellularSignalStrengthDb);
2835         line.append(",is_same_registered_cell=" + entry.isSameRegisteredCell);
2836         line.append(",device_mobility_state=" + entry.deviceMobilityState);
2837         pw.println(line.toString());
2838     }
2839 
printDeviceMobilityStatePnoScanStats(PrintWriter pw, DeviceMobilityStatePnoScanStats stats)2840     private void printDeviceMobilityStatePnoScanStats(PrintWriter pw,
2841             DeviceMobilityStatePnoScanStats stats) {
2842         StringBuilder line = new StringBuilder();
2843         line.append("device_mobility_state=" + stats.deviceMobilityState);
2844         line.append(",num_times_entered_state=" + stats.numTimesEnteredState);
2845         line.append(",total_duration_ms=" + stats.totalDurationMs);
2846         line.append(",pno_duration_ms=" + stats.pnoDurationMs);
2847         pw.println(line.toString());
2848     }
2849 
2850     /**
2851      * Update various counts of saved network types
2852      * @param networks List of WifiConfigurations representing all saved networks, must not be null
2853      */
updateSavedNetworks(List<WifiConfiguration> networks)2854     public void updateSavedNetworks(List<WifiConfiguration> networks) {
2855         synchronized (mLock) {
2856             mWifiLogProto.numSavedNetworks = networks.size();
2857             mWifiLogProto.numOpenNetworks = 0;
2858             mWifiLogProto.numLegacyPersonalNetworks = 0;
2859             mWifiLogProto.numLegacyEnterpriseNetworks = 0;
2860             mWifiLogProto.numEnhancedOpenNetworks = 0;
2861             mWifiLogProto.numWpa3PersonalNetworks = 0;
2862             mWifiLogProto.numWpa3EnterpriseNetworks = 0;
2863             mWifiLogProto.numNetworksAddedByUser = 0;
2864             mWifiLogProto.numNetworksAddedByApps = 0;
2865             mWifiLogProto.numHiddenNetworks = 0;
2866             mWifiLogProto.numPasspointNetworks = 0;
2867             for (WifiConfiguration config : networks) {
2868                 if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) {
2869                     mWifiLogProto.numOpenNetworks++;
2870                 } else if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE)) {
2871                     mWifiLogProto.numEnhancedOpenNetworks++;
2872                 } else if (config.isEnterprise()) {
2873                     if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SUITE_B_192)) {
2874                         mWifiLogProto.numWpa3EnterpriseNetworks++;
2875                     } else {
2876                         mWifiLogProto.numLegacyEnterpriseNetworks++;
2877                     }
2878                 } else {
2879                     if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SAE)) {
2880                         mWifiLogProto.numWpa3PersonalNetworks++;
2881                     } else {
2882                         mWifiLogProto.numLegacyPersonalNetworks++;
2883                     }
2884                 }
2885                 if (config.selfAdded) {
2886                     mWifiLogProto.numNetworksAddedByUser++;
2887                 } else {
2888                     mWifiLogProto.numNetworksAddedByApps++;
2889                 }
2890                 if (config.hiddenSSID) {
2891                     mWifiLogProto.numHiddenNetworks++;
2892                 }
2893                 if (config.isPasspoint()) {
2894                     mWifiLogProto.numPasspointNetworks++;
2895                 }
2896                 if (config.macRandomizationSetting == WifiConfiguration.RANDOMIZATION_PERSISTENT) {
2897                     mWifiLogProto.numSavedNetworksWithMacRandomization++;
2898                 }
2899             }
2900         }
2901     }
2902 
2903     /**
2904      * Update metrics for saved Passpoint profiles.
2905      *
2906      * @param numSavedProfiles The number of saved Passpoint profiles
2907      * @param numConnectedProfiles The number of saved Passpoint profiles that have ever resulted
2908      *                             in a successful network connection
2909      */
updateSavedPasspointProfiles(int numSavedProfiles, int numConnectedProfiles)2910     public void updateSavedPasspointProfiles(int numSavedProfiles, int numConnectedProfiles) {
2911         synchronized (mLock) {
2912             mWifiLogProto.numPasspointProviders = numSavedProfiles;
2913             mWifiLogProto.numPasspointProvidersSuccessfullyConnected = numConnectedProfiles;
2914         }
2915     }
2916 
2917     /**
2918      * Update number of times for type of saved Passpoint profile.
2919      *
2920      * @param providers Passpoint providers installed on the device.
2921      */
updateSavedPasspointProfilesInfo( Map<String, PasspointProvider> providers)2922     public void updateSavedPasspointProfilesInfo(
2923             Map<String, PasspointProvider> providers) {
2924         int passpointType;
2925         int eapType;
2926         PasspointConfiguration config;
2927         synchronized (mLock) {
2928             mInstalledPasspointProfileTypeForR1.clear();
2929             mInstalledPasspointProfileTypeForR2.clear();
2930             for (Map.Entry<String, PasspointProvider> entry : providers.entrySet()) {
2931                 config = entry.getValue().getConfig();
2932                 if (config.getCredential().getUserCredential() != null) {
2933                     eapType = EAPConstants.EAP_TTLS;
2934                 } else if (config.getCredential().getCertCredential() != null) {
2935                     eapType = EAPConstants.EAP_TLS;
2936                 } else if (config.getCredential().getSimCredential() != null) {
2937                     eapType = config.getCredential().getSimCredential().getEapType();
2938                 } else {
2939                     eapType = -1;
2940                 }
2941                 switch (eapType) {
2942                     case EAPConstants.EAP_TLS:
2943                         passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_TLS;
2944                         break;
2945                     case EAPConstants.EAP_TTLS:
2946                         passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_TTLS;
2947                         break;
2948                     case EAPConstants.EAP_SIM:
2949                         passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_SIM;
2950                         break;
2951                     case EAPConstants.EAP_AKA:
2952                         passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_AKA;
2953                         break;
2954                     case EAPConstants.EAP_AKA_PRIME:
2955                         passpointType =
2956                                 WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_AKA_PRIME;
2957                         break;
2958                     default:
2959                         passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_UNKNOWN;
2960 
2961                 }
2962                 if (config.validateForR2()) {
2963                     mInstalledPasspointProfileTypeForR2.increment(passpointType);
2964                 } else {
2965                     mInstalledPasspointProfileTypeForR1.increment(passpointType);
2966                 }
2967             }
2968         }
2969     }
2970 
2971     /**
2972      * Put all metrics that were being tracked separately into mWifiLogProto
2973      */
consolidateProto()2974     private void consolidateProto() {
2975         List<WifiMetricsProto.RssiPollCount> rssis = new ArrayList<>();
2976         synchronized (mLock) {
2977             int connectionEventCount = mConnectionEventList.size();
2978             // Exclude the current active un-ended connection event
2979             if (mCurrentConnectionEvent != null) {
2980                 connectionEventCount--;
2981             }
2982             mWifiLogProto.connectionEvent =
2983                     new WifiMetricsProto.ConnectionEvent[connectionEventCount];
2984             for (int i = 0; i < connectionEventCount; i++) {
2985                 mWifiLogProto.connectionEvent[i] = mConnectionEventList.get(i).mConnectionEvent;
2986             }
2987 
2988             //Convert the SparseIntArray of scanReturnEntry integers into ScanReturnEntry proto list
2989             mWifiLogProto.scanReturnEntries =
2990                     new WifiMetricsProto.WifiLog.ScanReturnEntry[mScanReturnEntries.size()];
2991             for (int i = 0; i < mScanReturnEntries.size(); i++) {
2992                 mWifiLogProto.scanReturnEntries[i] = new WifiMetricsProto.WifiLog.ScanReturnEntry();
2993                 mWifiLogProto.scanReturnEntries[i].scanReturnCode = mScanReturnEntries.keyAt(i);
2994                 mWifiLogProto.scanReturnEntries[i].scanResultsCount = mScanReturnEntries.valueAt(i);
2995             }
2996 
2997             // Convert the SparseIntArray of systemStateEntry into WifiSystemStateEntry proto list
2998             // This one is slightly more complex, as the Sparse are indexed with:
2999             //     key: wifiState * 2 + isScreenOn, value: wifiStateCount
3000             mWifiLogProto.wifiSystemStateEntries =
3001                     new WifiMetricsProto.WifiLog
3002                     .WifiSystemStateEntry[mWifiSystemStateEntries.size()];
3003             for (int i = 0; i < mWifiSystemStateEntries.size(); i++) {
3004                 mWifiLogProto.wifiSystemStateEntries[i] =
3005                         new WifiMetricsProto.WifiLog.WifiSystemStateEntry();
3006                 mWifiLogProto.wifiSystemStateEntries[i].wifiState =
3007                         mWifiSystemStateEntries.keyAt(i) / 2;
3008                 mWifiLogProto.wifiSystemStateEntries[i].wifiStateCount =
3009                         mWifiSystemStateEntries.valueAt(i);
3010                 mWifiLogProto.wifiSystemStateEntries[i].isScreenOn =
3011                         (mWifiSystemStateEntries.keyAt(i) % 2) > 0;
3012             }
3013             mWifiLogProto.recordDurationSec = (int) ((mClock.getElapsedSinceBootMillis() / 1000)
3014                     - mRecordStartTimeSec);
3015 
3016             /**
3017              * Convert the SparseIntArrays of RSSI poll rssi, counts, and frequency to the
3018              * proto's repeated IntKeyVal array.
3019              */
3020             for (Map.Entry<Integer, SparseIntArray> entry : mRssiPollCountsMap.entrySet()) {
3021                 int frequency = entry.getKey();
3022                 SparseIntArray histogram = entry.getValue();
3023                 for (int i = 0; i < histogram.size(); i++) {
3024                     WifiMetricsProto.RssiPollCount keyVal = new WifiMetricsProto.RssiPollCount();
3025                     keyVal.rssi = histogram.keyAt(i);
3026                     keyVal.count = histogram.valueAt(i);
3027                     keyVal.frequency = frequency;
3028                     rssis.add(keyVal);
3029                 }
3030             }
3031             mWifiLogProto.rssiPollRssiCount = rssis.toArray(mWifiLogProto.rssiPollRssiCount);
3032 
3033             /**
3034              * Convert the SparseIntArray of RSSI delta rssi's and counts to the proto's repeated
3035              * IntKeyVal array.
3036              */
3037             mWifiLogProto.rssiPollDeltaCount =
3038                     new WifiMetricsProto.RssiPollCount[mRssiDeltaCounts.size()];
3039             for (int i = 0; i < mRssiDeltaCounts.size(); i++) {
3040                 mWifiLogProto.rssiPollDeltaCount[i] = new WifiMetricsProto.RssiPollCount();
3041                 mWifiLogProto.rssiPollDeltaCount[i].rssi = mRssiDeltaCounts.keyAt(i);
3042                 mWifiLogProto.rssiPollDeltaCount[i].count = mRssiDeltaCounts.valueAt(i);
3043             }
3044 
3045             /**
3046              * Add LinkSpeedCount objects from mLinkSpeedCounts to proto.
3047              */
3048             mWifiLogProto.linkSpeedCounts =
3049                     new WifiMetricsProto.LinkSpeedCount[mLinkSpeedCounts.size()];
3050             for (int i = 0; i < mLinkSpeedCounts.size(); i++) {
3051                 mWifiLogProto.linkSpeedCounts[i] = mLinkSpeedCounts.valueAt(i);
3052             }
3053 
3054             /**
3055              * Convert the SparseIntArray of alert reasons and counts to the proto's repeated
3056              * IntKeyVal array.
3057              */
3058             mWifiLogProto.alertReasonCount =
3059                     new WifiMetricsProto.AlertReasonCount[mWifiAlertReasonCounts.size()];
3060             for (int i = 0; i < mWifiAlertReasonCounts.size(); i++) {
3061                 mWifiLogProto.alertReasonCount[i] = new WifiMetricsProto.AlertReasonCount();
3062                 mWifiLogProto.alertReasonCount[i].reason = mWifiAlertReasonCounts.keyAt(i);
3063                 mWifiLogProto.alertReasonCount[i].count = mWifiAlertReasonCounts.valueAt(i);
3064             }
3065 
3066             /**
3067             *  Convert the SparseIntArray of Wifi Score and counts to proto's repeated
3068             * IntKeyVal array.
3069             */
3070             mWifiLogProto.wifiScoreCount =
3071                     new WifiMetricsProto.WifiScoreCount[mWifiScoreCounts.size()];
3072             for (int score = 0; score < mWifiScoreCounts.size(); score++) {
3073                 mWifiLogProto.wifiScoreCount[score] = new WifiMetricsProto.WifiScoreCount();
3074                 mWifiLogProto.wifiScoreCount[score].score = mWifiScoreCounts.keyAt(score);
3075                 mWifiLogProto.wifiScoreCount[score].count = mWifiScoreCounts.valueAt(score);
3076             }
3077 
3078             /**
3079              * Convert the SparseIntArray of Wifi Usability Score and counts to proto's repeated
3080              * IntKeyVal array.
3081              */
3082             mWifiLogProto.wifiUsabilityScoreCount =
3083                 new WifiMetricsProto.WifiUsabilityScoreCount[mWifiUsabilityScoreCounts.size()];
3084             for (int scoreIdx = 0; scoreIdx < mWifiUsabilityScoreCounts.size(); scoreIdx++) {
3085                 mWifiLogProto.wifiUsabilityScoreCount[scoreIdx] =
3086                     new WifiMetricsProto.WifiUsabilityScoreCount();
3087                 mWifiLogProto.wifiUsabilityScoreCount[scoreIdx].score =
3088                     mWifiUsabilityScoreCounts.keyAt(scoreIdx);
3089                 mWifiLogProto.wifiUsabilityScoreCount[scoreIdx].count =
3090                     mWifiUsabilityScoreCounts.valueAt(scoreIdx);
3091             }
3092 
3093             /**
3094              * Convert the SparseIntArray of SoftAp Return codes and counts to proto's repeated
3095              * IntKeyVal array.
3096              */
3097             int codeCounts = mSoftApManagerReturnCodeCounts.size();
3098             mWifiLogProto.softApReturnCode = new WifiMetricsProto.SoftApReturnCodeCount[codeCounts];
3099             for (int sapCode = 0; sapCode < codeCounts; sapCode++) {
3100                 mWifiLogProto.softApReturnCode[sapCode] =
3101                         new WifiMetricsProto.SoftApReturnCodeCount();
3102                 mWifiLogProto.softApReturnCode[sapCode].startResult =
3103                         mSoftApManagerReturnCodeCounts.keyAt(sapCode);
3104                 mWifiLogProto.softApReturnCode[sapCode].count =
3105                         mSoftApManagerReturnCodeCounts.valueAt(sapCode);
3106             }
3107 
3108             /**
3109              * Convert StaEventList to array of StaEvents
3110              */
3111             mWifiLogProto.staEventList = new StaEvent[mStaEventList.size()];
3112             for (int i = 0; i < mStaEventList.size(); i++) {
3113                 mWifiLogProto.staEventList[i] = mStaEventList.get(i).staEvent;
3114             }
3115             mWifiLogProto.totalSsidsInScanHistogram =
3116                     makeNumConnectableNetworksBucketArray(mTotalSsidsInScanHistogram);
3117             mWifiLogProto.totalBssidsInScanHistogram =
3118                     makeNumConnectableNetworksBucketArray(mTotalBssidsInScanHistogram);
3119             mWifiLogProto.availableOpenSsidsInScanHistogram =
3120                     makeNumConnectableNetworksBucketArray(mAvailableOpenSsidsInScanHistogram);
3121             mWifiLogProto.availableOpenBssidsInScanHistogram =
3122                     makeNumConnectableNetworksBucketArray(mAvailableOpenBssidsInScanHistogram);
3123             mWifiLogProto.availableSavedSsidsInScanHistogram =
3124                     makeNumConnectableNetworksBucketArray(mAvailableSavedSsidsInScanHistogram);
3125             mWifiLogProto.availableSavedBssidsInScanHistogram =
3126                     makeNumConnectableNetworksBucketArray(mAvailableSavedBssidsInScanHistogram);
3127             mWifiLogProto.availableOpenOrSavedSsidsInScanHistogram =
3128                     makeNumConnectableNetworksBucketArray(
3129                     mAvailableOpenOrSavedSsidsInScanHistogram);
3130             mWifiLogProto.availableOpenOrSavedBssidsInScanHistogram =
3131                     makeNumConnectableNetworksBucketArray(
3132                     mAvailableOpenOrSavedBssidsInScanHistogram);
3133             mWifiLogProto.availableSavedPasspointProviderProfilesInScanHistogram =
3134                     makeNumConnectableNetworksBucketArray(
3135                     mAvailableSavedPasspointProviderProfilesInScanHistogram);
3136             mWifiLogProto.availableSavedPasspointProviderBssidsInScanHistogram =
3137                     makeNumConnectableNetworksBucketArray(
3138                     mAvailableSavedPasspointProviderBssidsInScanHistogram);
3139             mWifiLogProto.wifiAwareLog = mWifiAwareMetrics.consolidateProto();
3140             mWifiLogProto.wifiRttLog = mRttMetrics.consolidateProto();
3141 
3142             mWifiLogProto.pnoScanMetrics = mPnoScanMetrics;
3143             mWifiLogProto.wifiLinkLayerUsageStats = mWifiLinkLayerUsageStats;
3144 
3145             /**
3146              * Convert the SparseIntArray of "Connect to Network" notification types and counts to
3147              * proto's repeated IntKeyVal array.
3148              */
3149             ConnectToNetworkNotificationAndActionCount[] notificationCountArray =
3150                     new ConnectToNetworkNotificationAndActionCount[
3151                             mConnectToNetworkNotificationCount.size()];
3152             for (int i = 0; i < mConnectToNetworkNotificationCount.size(); i++) {
3153                 ConnectToNetworkNotificationAndActionCount keyVal =
3154                         new ConnectToNetworkNotificationAndActionCount();
3155                 keyVal.notification = mConnectToNetworkNotificationCount.keyAt(i);
3156                 keyVal.recommender =
3157                         ConnectToNetworkNotificationAndActionCount.RECOMMENDER_OPEN;
3158                 keyVal.count = mConnectToNetworkNotificationCount.valueAt(i);
3159                 notificationCountArray[i] = keyVal;
3160             }
3161             mWifiLogProto.connectToNetworkNotificationCount = notificationCountArray;
3162 
3163             /**
3164              * Convert the SparseIntArray of "Connect to Network" notification types and counts to
3165              * proto's repeated IntKeyVal array.
3166              */
3167             ConnectToNetworkNotificationAndActionCount[] notificationActionCountArray =
3168                     new ConnectToNetworkNotificationAndActionCount[
3169                             mConnectToNetworkNotificationActionCount.size()];
3170             for (int i = 0; i < mConnectToNetworkNotificationActionCount.size(); i++) {
3171                 ConnectToNetworkNotificationAndActionCount keyVal =
3172                         new ConnectToNetworkNotificationAndActionCount();
3173                 int key = mConnectToNetworkNotificationActionCount.keyAt(i);
3174                 keyVal.notification = key / CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER;
3175                 keyVal.action = key % CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER;
3176                 keyVal.recommender =
3177                         ConnectToNetworkNotificationAndActionCount.RECOMMENDER_OPEN;
3178                 keyVal.count = mConnectToNetworkNotificationActionCount.valueAt(i);
3179                 notificationActionCountArray[i] = keyVal;
3180             }
3181 
3182             mWifiLogProto.installedPasspointProfileTypeForR1 =
3183                     convertPasspointProfilesToProto(mInstalledPasspointProfileTypeForR1);
3184             mWifiLogProto.installedPasspointProfileTypeForR2 =
3185                     convertPasspointProfilesToProto(mInstalledPasspointProfileTypeForR2);
3186 
3187             mWifiLogProto.connectToNetworkNotificationActionCount = notificationActionCountArray;
3188 
3189             mWifiLogProto.openNetworkRecommenderBlacklistSize =
3190                     mOpenNetworkRecommenderBlacklistSize;
3191             mWifiLogProto.isWifiNetworksAvailableNotificationOn =
3192                     mIsWifiNetworksAvailableNotificationOn;
3193             mWifiLogProto.numOpenNetworkRecommendationUpdates =
3194                     mNumOpenNetworkRecommendationUpdates;
3195             mWifiLogProto.numOpenNetworkConnectMessageFailedToSend =
3196                     mNumOpenNetworkConnectMessageFailedToSend;
3197 
3198             mWifiLogProto.observedHotspotR1ApsInScanHistogram =
3199                     makeNumConnectableNetworksBucketArray(mObservedHotspotR1ApInScanHistogram);
3200             mWifiLogProto.observedHotspotR2ApsInScanHistogram =
3201                     makeNumConnectableNetworksBucketArray(mObservedHotspotR2ApInScanHistogram);
3202             mWifiLogProto.observedHotspotR1EssInScanHistogram =
3203                     makeNumConnectableNetworksBucketArray(mObservedHotspotR1EssInScanHistogram);
3204             mWifiLogProto.observedHotspotR2EssInScanHistogram =
3205                     makeNumConnectableNetworksBucketArray(mObservedHotspotR2EssInScanHistogram);
3206             mWifiLogProto.observedHotspotR1ApsPerEssInScanHistogram =
3207                     makeNumConnectableNetworksBucketArray(
3208                             mObservedHotspotR1ApsPerEssInScanHistogram);
3209             mWifiLogProto.observedHotspotR2ApsPerEssInScanHistogram =
3210                     makeNumConnectableNetworksBucketArray(
3211                             mObservedHotspotR2ApsPerEssInScanHistogram);
3212 
3213             mWifiLogProto.observed80211McSupportingApsInScanHistogram =
3214                     makeNumConnectableNetworksBucketArray(mObserved80211mcApInScanHistogram);
3215 
3216             if (mSoftApEventListTethered.size() > 0) {
3217                 mWifiLogProto.softApConnectedClientsEventsTethered =
3218                         mSoftApEventListTethered.toArray(
3219                         mWifiLogProto.softApConnectedClientsEventsTethered);
3220             }
3221             if (mSoftApEventListLocalOnly.size() > 0) {
3222                 mWifiLogProto.softApConnectedClientsEventsLocalOnly =
3223                         mSoftApEventListLocalOnly.toArray(
3224                         mWifiLogProto.softApConnectedClientsEventsLocalOnly);
3225             }
3226 
3227             mWifiLogProto.wpsMetrics = mWpsMetrics;
3228             mWifiLogProto.wifiPowerStats = mWifiPowerMetrics.buildProto();
3229             mWifiLogProto.wifiRadioUsage = mWifiPowerMetrics.buildWifiRadioUsageProto();
3230             mWifiLogProto.wifiWakeStats = mWifiWakeMetrics.buildProto();
3231             mWifiLogProto.isMacRandomizationOn = mIsMacRandomizationOn;
3232             mWifiLogProto.experimentValues = mExperimentValues;
3233             mWifiLogProto.wifiIsUnusableEventList =
3234                     new WifiIsUnusableEvent[mWifiIsUnusableList.size()];
3235             for (int i = 0; i < mWifiIsUnusableList.size(); i++) {
3236                 mWifiLogProto.wifiIsUnusableEventList[i] = mWifiIsUnusableList.get(i).event;
3237             }
3238             mWifiLogProto.hardwareRevision = SystemProperties.get("ro.boot.revision", "");
3239 
3240             // Postprocessing on WifiUsabilityStats to upload an equal number of LABEL_GOOD and
3241             // LABEL_BAD WifiUsabilityStats
3242             final int numUsabilityStats = Math.min(
3243                     Math.min(mWifiUsabilityStatsListBad.size(),
3244                             mWifiUsabilityStatsListGood.size()),
3245                     MAX_WIFI_USABILITY_STATS_PER_TYPE_TO_UPLOAD);
3246             LinkedList<WifiUsabilityStats> usabilityStatsGoodCopy =
3247                     new LinkedList<>(mWifiUsabilityStatsListGood);
3248             LinkedList<WifiUsabilityStats> usabilityStatsBadCopy =
3249                     new LinkedList<>(mWifiUsabilityStatsListBad);
3250             mWifiLogProto.wifiUsabilityStatsList = new WifiUsabilityStats[numUsabilityStats * 2];
3251             for (int i = 0; i < numUsabilityStats; i++) {
3252                 mWifiLogProto.wifiUsabilityStatsList[2 * i] = usabilityStatsGoodCopy.remove(
3253                         mRand.nextInt(usabilityStatsGoodCopy.size()));
3254                 mWifiLogProto.wifiUsabilityStatsList[2 * i + 1] = usabilityStatsBadCopy.remove(
3255                         mRand.nextInt(usabilityStatsBadCopy.size()));
3256             }
3257             mWifiLogProto.mobilityStatePnoStatsList =
3258                     new DeviceMobilityStatePnoScanStats[mMobilityStatePnoStatsMap.size()];
3259             for (int i = 0; i < mMobilityStatePnoStatsMap.size(); i++) {
3260                 mWifiLogProto.mobilityStatePnoStatsList[i] = mMobilityStatePnoStatsMap.valueAt(i);
3261             }
3262             mWifiLogProto.wifiP2PStats = mWifiP2pMetrics.consolidateProto();
3263             mWifiLogProto.wifiDppLog = mDppMetrics.consolidateProto();
3264             mWifiLogProto.wifiConfigStoreIo = new WifiMetricsProto.WifiConfigStoreIO();
3265             mWifiLogProto.wifiConfigStoreIo.readDurations =
3266                     makeWifiConfigStoreIODurationBucketArray(mWifiConfigStoreReadDurationHistogram);
3267             mWifiLogProto.wifiConfigStoreIo.writeDurations =
3268                     makeWifiConfigStoreIODurationBucketArray(
3269                             mWifiConfigStoreWriteDurationHistogram);
3270 
3271             LinkProbeStats linkProbeStats = new LinkProbeStats();
3272             linkProbeStats.successRssiCounts = mLinkProbeSuccessRssiCounts.toProto();
3273             linkProbeStats.failureRssiCounts = mLinkProbeFailureRssiCounts.toProto();
3274             linkProbeStats.successLinkSpeedCounts = mLinkProbeSuccessLinkSpeedCounts.toProto();
3275             linkProbeStats.failureLinkSpeedCounts = mLinkProbeFailureLinkSpeedCounts.toProto();
3276             linkProbeStats.successSecondsSinceLastTxSuccessHistogram =
3277                     mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram.toProto();
3278             linkProbeStats.failureSecondsSinceLastTxSuccessHistogram =
3279                     mLinkProbeFailureSecondsSinceLastTxSuccessHistogram.toProto();
3280             linkProbeStats.successElapsedTimeMsHistogram =
3281                     mLinkProbeSuccessElapsedTimeMsHistogram.toProto();
3282             linkProbeStats.failureReasonCounts = mLinkProbeFailureReasonCounts.toProto(
3283                     LinkProbeFailureReasonCount.class,
3284                     (reason, count) -> {
3285                         LinkProbeFailureReasonCount c = new LinkProbeFailureReasonCount();
3286                         c.failureReason = linkProbeFailureReasonToProto(reason);
3287                         c.count = count;
3288                         return c;
3289                     });
3290             linkProbeStats.experimentProbeCounts = mLinkProbeExperimentProbeCounts.toProto(
3291                     ExperimentProbeCounts.class,
3292                     (experimentId, probeCount) -> {
3293                         ExperimentProbeCounts c = new ExperimentProbeCounts();
3294                         c.experimentId = experimentId;
3295                         c.probeCount = probeCount;
3296                         return c;
3297                     });
3298             mWifiLogProto.linkProbeStats = linkProbeStats;
3299 
3300             mWifiLogProto.networkSelectionExperimentDecisionsList =
3301                     makeNetworkSelectionExperimentDecisionsList();
3302 
3303             mWifiNetworkRequestApiLog.networkMatchSizeHistogram =
3304                     mWifiNetworkRequestApiMatchSizeHistogram.toProto();
3305             mWifiLogProto.wifiNetworkRequestApiLog = mWifiNetworkRequestApiLog;
3306 
3307             mWifiNetworkSuggestionApiLog.networkListSizeHistogram =
3308                     mWifiNetworkSuggestionApiListSizeHistogram.toProto();
3309             mWifiLogProto.wifiNetworkSuggestionApiLog = mWifiNetworkSuggestionApiLog;
3310 
3311             mWifiLockStats.highPerfLockAcqDurationSecHistogram =
3312                     mWifiLockHighPerfAcqDurationSecHistogram.toProto();
3313 
3314             mWifiLockStats.lowLatencyLockAcqDurationSecHistogram =
3315                     mWifiLockLowLatencyAcqDurationSecHistogram.toProto();
3316 
3317             mWifiLockStats.highPerfActiveSessionDurationSecHistogram =
3318                     mWifiLockHighPerfActiveSessionDurationSecHistogram.toProto();
3319 
3320             mWifiLockStats.lowLatencyActiveSessionDurationSecHistogram =
3321                     mWifiLockLowLatencyActiveSessionDurationSecHistogram.toProto();
3322 
3323             mWifiLogProto.wifiLockStats = mWifiLockStats;
3324             mWifiLogProto.wifiToggleStats = mWifiToggleStats;
3325 
3326             /**
3327              * Convert the SparseIntArray of passpoint provision failure code
3328              * and counts to the proto's repeated IntKeyVal array.
3329              */
3330             mWifiLogProto.passpointProvisionStats = new PasspointProvisionStats();
3331             mWifiLogProto.passpointProvisionStats.numProvisionSuccess = mNumProvisionSuccess;
3332             mWifiLogProto.passpointProvisionStats.provisionFailureCount =
3333                     mPasspointProvisionFailureCounts.toProto(ProvisionFailureCount.class,
3334                             (key, count) -> {
3335                                 ProvisionFailureCount entry = new ProvisionFailureCount();
3336                                 entry.failureCode = key;
3337                                 entry.count = count;
3338                                 return entry;
3339                             });
3340         }
3341     }
3342 
linkProbeFailureReasonToProto(@ifiNative.SendMgmtFrameError int reason)3343     private static int linkProbeFailureReasonToProto(@WifiNative.SendMgmtFrameError int reason) {
3344         switch (reason) {
3345             case WifiNative.SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED:
3346                 return LinkProbeStats.LINK_PROBE_FAILURE_REASON_MCS_UNSUPPORTED;
3347             case WifiNative.SEND_MGMT_FRAME_ERROR_NO_ACK:
3348                 return LinkProbeStats.LINK_PROBE_FAILURE_REASON_NO_ACK;
3349             case WifiNative.SEND_MGMT_FRAME_ERROR_TIMEOUT:
3350                 return LinkProbeStats.LINK_PROBE_FAILURE_REASON_TIMEOUT;
3351             case WifiNative.SEND_MGMT_FRAME_ERROR_ALREADY_STARTED:
3352                 return LinkProbeStats.LINK_PROBE_FAILURE_REASON_ALREADY_STARTED;
3353             default:
3354                 return LinkProbeStats.LINK_PROBE_FAILURE_REASON_UNKNOWN;
3355         }
3356     }
3357 
makeNetworkSelectionExperimentDecisionsList()3358     private NetworkSelectionExperimentDecisions[] makeNetworkSelectionExperimentDecisionsList() {
3359         NetworkSelectionExperimentDecisions[] results = new NetworkSelectionExperimentDecisions[
3360                 mNetworkSelectionExperimentPairNumChoicesCounts.size()];
3361         int i = 0;
3362         for (Map.Entry<Pair<Integer, Integer>, NetworkSelectionExperimentResults> entry :
3363                 mNetworkSelectionExperimentPairNumChoicesCounts.entrySet()) {
3364             NetworkSelectionExperimentDecisions result = new NetworkSelectionExperimentDecisions();
3365             result.experiment1Id = entry.getKey().first;
3366             result.experiment2Id = entry.getKey().second;
3367             result.sameSelectionNumChoicesCounter =
3368                     entry.getValue().sameSelectionNumChoicesCounter.toProto();
3369             result.differentSelectionNumChoicesCounter =
3370                     entry.getValue().differentSelectionNumChoicesCounter.toProto();
3371             results[i] = result;
3372             i++;
3373         }
3374         return results;
3375     }
3376 
3377     /** Sets the scoring experiment id to current value */
consolidateScoringParams()3378     private void consolidateScoringParams() {
3379         synchronized (mLock) {
3380             if (mScoringParams != null) {
3381                 int experimentIdentifier = mScoringParams.getExperimentIdentifier();
3382                 if (experimentIdentifier == 0) {
3383                     mWifiLogProto.scoreExperimentId = "";
3384                 } else {
3385                     mWifiLogProto.scoreExperimentId = "x" + experimentIdentifier;
3386                 }
3387             }
3388         }
3389     }
3390 
makeNumConnectableNetworksBucketArray( SparseIntArray sia)3391     private WifiMetricsProto.NumConnectableNetworksBucket[] makeNumConnectableNetworksBucketArray(
3392             SparseIntArray sia) {
3393         WifiMetricsProto.NumConnectableNetworksBucket[] array =
3394                 new WifiMetricsProto.NumConnectableNetworksBucket[sia.size()];
3395         for (int i = 0; i < sia.size(); i++) {
3396             WifiMetricsProto.NumConnectableNetworksBucket keyVal =
3397                     new WifiMetricsProto.NumConnectableNetworksBucket();
3398             keyVal.numConnectableNetworks = sia.keyAt(i);
3399             keyVal.count = sia.valueAt(i);
3400             array[i] = keyVal;
3401         }
3402         return array;
3403     }
3404 
3405     private WifiMetricsProto.WifiConfigStoreIO.DurationBucket[]
makeWifiConfigStoreIODurationBucketArray(SparseIntArray sia)3406             makeWifiConfigStoreIODurationBucketArray(SparseIntArray sia) {
3407         MetricsUtils.GenericBucket[] genericBuckets =
3408                 MetricsUtils.linearHistogramToGenericBuckets(sia,
3409                         WIFI_CONFIG_STORE_IO_DURATION_BUCKET_RANGES_MS);
3410         WifiMetricsProto.WifiConfigStoreIO.DurationBucket[] array =
3411                 new WifiMetricsProto.WifiConfigStoreIO.DurationBucket[genericBuckets.length];
3412         try {
3413             for (int i = 0; i < genericBuckets.length; i++) {
3414                 array[i] = new WifiMetricsProto.WifiConfigStoreIO.DurationBucket();
3415                 array[i].rangeStartMs = toIntExact(genericBuckets[i].start);
3416                 array[i].rangeEndMs = toIntExact(genericBuckets[i].end);
3417                 array[i].count = genericBuckets[i].count;
3418             }
3419         } catch (ArithmeticException e) {
3420             // Return empty array on any overflow errors.
3421             array = new WifiMetricsProto.WifiConfigStoreIO.DurationBucket[0];
3422         }
3423         return array;
3424     }
3425 
3426     /**
3427      * Clear all WifiMetrics, except for currentConnectionEvent and Open Network Notification
3428      * feature enabled state, blacklist size.
3429      */
clear()3430     private void clear() {
3431         synchronized (mLock) {
3432             loadSettings();
3433             mConnectionEventList.clear();
3434             if (mCurrentConnectionEvent != null) {
3435                 mConnectionEventList.add(mCurrentConnectionEvent);
3436             }
3437             mScanReturnEntries.clear();
3438             mWifiSystemStateEntries.clear();
3439             mRecordStartTimeSec = mClock.getElapsedSinceBootMillis() / 1000;
3440             mRssiPollCountsMap.clear();
3441             mRssiDeltaCounts.clear();
3442             mLinkSpeedCounts.clear();
3443             mWifiAlertReasonCounts.clear();
3444             mWifiScoreCounts.clear();
3445             mWifiUsabilityScoreCounts.clear();
3446             mWifiLogProto.clear();
3447             mScanResultRssiTimestampMillis = -1;
3448             mSoftApManagerReturnCodeCounts.clear();
3449             mStaEventList.clear();
3450             mWifiAwareMetrics.clear();
3451             mRttMetrics.clear();
3452             mTotalSsidsInScanHistogram.clear();
3453             mTotalBssidsInScanHistogram.clear();
3454             mAvailableOpenSsidsInScanHistogram.clear();
3455             mAvailableOpenBssidsInScanHistogram.clear();
3456             mAvailableSavedSsidsInScanHistogram.clear();
3457             mAvailableSavedBssidsInScanHistogram.clear();
3458             mAvailableOpenOrSavedSsidsInScanHistogram.clear();
3459             mAvailableOpenOrSavedBssidsInScanHistogram.clear();
3460             mAvailableSavedPasspointProviderProfilesInScanHistogram.clear();
3461             mAvailableSavedPasspointProviderBssidsInScanHistogram.clear();
3462             mPnoScanMetrics.clear();
3463             mWifiLinkLayerUsageStats.clear();
3464             mConnectToNetworkNotificationCount.clear();
3465             mConnectToNetworkNotificationActionCount.clear();
3466             mNumOpenNetworkRecommendationUpdates = 0;
3467             mNumOpenNetworkConnectMessageFailedToSend = 0;
3468             mObservedHotspotR1ApInScanHistogram.clear();
3469             mObservedHotspotR2ApInScanHistogram.clear();
3470             mObservedHotspotR1EssInScanHistogram.clear();
3471             mObservedHotspotR2EssInScanHistogram.clear();
3472             mObservedHotspotR1ApsPerEssInScanHistogram.clear();
3473             mObservedHotspotR2ApsPerEssInScanHistogram.clear();
3474             mSoftApEventListTethered.clear();
3475             mSoftApEventListLocalOnly.clear();
3476             mWpsMetrics.clear();
3477             mWifiWakeMetrics.clear();
3478             mObserved80211mcApInScanHistogram.clear();
3479             mWifiIsUnusableList.clear();
3480             mInstalledPasspointProfileTypeForR1.clear();
3481             mInstalledPasspointProfileTypeForR2.clear();
3482             mWifiUsabilityStatsListGood.clear();
3483             mWifiUsabilityStatsListBad.clear();
3484             mWifiUsabilityStatsEntriesList.clear();
3485             mMobilityStatePnoStatsMap.clear();
3486             mWifiP2pMetrics.clear();
3487             mDppMetrics.clear();
3488             mWifiUsabilityStatsCounter = 0;
3489             mLastBssid = null;
3490             mLastFrequency = -1;
3491             mSeqNumInsideFramework = 0;
3492             mLastWifiUsabilityScore = -1;
3493             mLastWifiUsabilityScoreNoReset = -1;
3494             mLastPredictionHorizonSec = -1;
3495             mLastPredictionHorizonSecNoReset = -1;
3496             mSeqNumToFramework = -1;
3497             mProbeStatusSinceLastUpdate =
3498                     android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE;
3499             mProbeElapsedTimeSinceLastUpdateMs = -1;
3500             mProbeMcsRateSinceLastUpdate = -1;
3501             mScoreBreachLowTimeMillis = -1;
3502             mWifiConfigStoreReadDurationHistogram.clear();
3503             mWifiConfigStoreWriteDurationHistogram.clear();
3504             mLinkProbeSuccessRssiCounts.clear();
3505             mLinkProbeFailureRssiCounts.clear();
3506             mLinkProbeSuccessLinkSpeedCounts.clear();
3507             mLinkProbeFailureLinkSpeedCounts.clear();
3508             mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram.clear();
3509             mLinkProbeFailureSecondsSinceLastTxSuccessHistogram.clear();
3510             mLinkProbeSuccessElapsedTimeMsHistogram.clear();
3511             mLinkProbeFailureReasonCounts.clear();
3512             mLinkProbeExperimentProbeCounts.clear();
3513             mLinkProbeStaEventCount = 0;
3514             mNetworkSelectionExperimentPairNumChoicesCounts.clear();
3515             mWifiNetworkSuggestionApiLog.clear();
3516             mWifiNetworkSuggestionApiLog.clear();
3517             mWifiNetworkRequestApiMatchSizeHistogram.clear();
3518             mWifiNetworkSuggestionApiListSizeHistogram.clear();
3519             mWifiLockHighPerfAcqDurationSecHistogram.clear();
3520             mWifiLockLowLatencyAcqDurationSecHistogram.clear();
3521             mWifiLockHighPerfActiveSessionDurationSecHistogram.clear();
3522             mWifiLockLowLatencyActiveSessionDurationSecHistogram.clear();
3523             mWifiLockStats.clear();
3524             mWifiToggleStats.clear();
3525             mPasspointProvisionFailureCounts.clear();
3526             mNumProvisionSuccess = 0;
3527         }
3528     }
3529 
3530     /**
3531      *  Set screen state (On/Off)
3532      */
setScreenState(boolean screenOn)3533     public void setScreenState(boolean screenOn) {
3534         synchronized (mLock) {
3535             mScreenOn = screenOn;
3536         }
3537     }
3538 
3539     /**
3540      *  Set wifi state (WIFI_UNKNOWN, WIFI_DISABLED, WIFI_DISCONNECTED, WIFI_ASSOCIATED)
3541      */
setWifiState(int wifiState)3542     public void setWifiState(int wifiState) {
3543         synchronized (mLock) {
3544             mWifiState = wifiState;
3545             mWifiWins = (wifiState == WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
3546             mWifiWinsUsabilityScore = (wifiState == WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
3547         }
3548     }
3549 
3550     /**
3551      * Message handler for interesting WifiMonitor messages. Generates StaEvents
3552      */
processMessage(Message msg)3553     private void processMessage(Message msg) {
3554         StaEvent event = new StaEvent();
3555         boolean logEvent = true;
3556         switch (msg.what) {
3557             case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
3558                 event.type = StaEvent.TYPE_ASSOCIATION_REJECTION_EVENT;
3559                 event.associationTimedOut = msg.arg1 > 0 ? true : false;
3560                 event.status = msg.arg2;
3561                 break;
3562             case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
3563                 event.type = StaEvent.TYPE_AUTHENTICATION_FAILURE_EVENT;
3564                 switch (msg.arg1) {
3565                     case WifiManager.ERROR_AUTH_FAILURE_NONE:
3566                         event.authFailureReason = StaEvent.AUTH_FAILURE_NONE;
3567                         break;
3568                     case WifiManager.ERROR_AUTH_FAILURE_TIMEOUT:
3569                         event.authFailureReason = StaEvent.AUTH_FAILURE_TIMEOUT;
3570                         break;
3571                     case WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD:
3572                         event.authFailureReason = StaEvent.AUTH_FAILURE_WRONG_PSWD;
3573                         break;
3574                     case WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE:
3575                         event.authFailureReason = StaEvent.AUTH_FAILURE_EAP_FAILURE;
3576                         break;
3577                     default:
3578                         break;
3579                 }
3580                 break;
3581             case WifiMonitor.NETWORK_CONNECTION_EVENT:
3582                 event.type = StaEvent.TYPE_NETWORK_CONNECTION_EVENT;
3583                 break;
3584             case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
3585                 event.type = StaEvent.TYPE_NETWORK_DISCONNECTION_EVENT;
3586                 event.reason = msg.arg2;
3587                 event.localGen = msg.arg1 == 0 ? false : true;
3588                 break;
3589             case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
3590                 logEvent = false;
3591                 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
3592                 mSupplicantStateChangeBitmask |= supplicantStateToBit(stateChangeResult.state);
3593                 break;
3594             case ClientModeImpl.CMD_ASSOCIATED_BSSID:
3595                 event.type = StaEvent.TYPE_CMD_ASSOCIATED_BSSID;
3596                 break;
3597             case ClientModeImpl.CMD_TARGET_BSSID:
3598                 event.type = StaEvent.TYPE_CMD_TARGET_BSSID;
3599                 break;
3600             default:
3601                 return;
3602         }
3603         if (logEvent) {
3604             addStaEvent(event);
3605         }
3606     }
3607     /**
3608      * Log a StaEvent from ClientModeImpl. The StaEvent must not be one of the supplicant
3609      * generated event types, which are logged through 'sendMessage'
3610      * @param type StaEvent.EventType describing the event
3611      */
logStaEvent(int type)3612     public void logStaEvent(int type) {
3613         logStaEvent(type, StaEvent.DISCONNECT_UNKNOWN, null);
3614     }
3615     /**
3616      * Log a StaEvent from ClientModeImpl. The StaEvent must not be one of the supplicant
3617      * generated event types, which are logged through 'sendMessage'
3618      * @param type StaEvent.EventType describing the event
3619      * @param config WifiConfiguration for a framework initiated connection attempt
3620      */
logStaEvent(int type, WifiConfiguration config)3621     public void logStaEvent(int type, WifiConfiguration config) {
3622         logStaEvent(type, StaEvent.DISCONNECT_UNKNOWN, config);
3623     }
3624     /**
3625      * Log a StaEvent from ClientModeImpl. The StaEvent must not be one of the supplicant
3626      * generated event types, which are logged through 'sendMessage'
3627      * @param type StaEvent.EventType describing the event
3628      * @param frameworkDisconnectReason StaEvent.FrameworkDisconnectReason explaining why framework
3629      *                                  initiated a FRAMEWORK_DISCONNECT
3630      */
logStaEvent(int type, int frameworkDisconnectReason)3631     public void logStaEvent(int type, int frameworkDisconnectReason) {
3632         logStaEvent(type, frameworkDisconnectReason, null);
3633     }
3634     /**
3635      * Log a StaEvent from ClientModeImpl. The StaEvent must not be one of the supplicant
3636      * generated event types, which are logged through 'sendMessage'
3637      * @param type StaEvent.EventType describing the event
3638      * @param frameworkDisconnectReason StaEvent.FrameworkDisconnectReason explaining why framework
3639      *                                  initiated a FRAMEWORK_DISCONNECT
3640      * @param config WifiConfiguration for a framework initiated connection attempt
3641      */
logStaEvent(int type, int frameworkDisconnectReason, WifiConfiguration config)3642     public void logStaEvent(int type, int frameworkDisconnectReason, WifiConfiguration config) {
3643         switch (type) {
3644             case StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL:
3645             case StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST:
3646             case StaEvent.TYPE_CMD_IP_REACHABILITY_LOST:
3647             case StaEvent.TYPE_CMD_START_CONNECT:
3648             case StaEvent.TYPE_CMD_START_ROAM:
3649             case StaEvent.TYPE_CONNECT_NETWORK:
3650             case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK:
3651             case StaEvent.TYPE_FRAMEWORK_DISCONNECT:
3652             case StaEvent.TYPE_SCORE_BREACH:
3653             case StaEvent.TYPE_MAC_CHANGE:
3654             case StaEvent.TYPE_WIFI_ENABLED:
3655             case StaEvent.TYPE_WIFI_DISABLED:
3656             case StaEvent.TYPE_WIFI_USABILITY_SCORE_BREACH:
3657                 break;
3658             default:
3659                 Log.e(TAG, "Unknown StaEvent:" + type);
3660                 return;
3661         }
3662         StaEvent event = new StaEvent();
3663         event.type = type;
3664         if (frameworkDisconnectReason != StaEvent.DISCONNECT_UNKNOWN) {
3665             event.frameworkDisconnectReason = frameworkDisconnectReason;
3666         }
3667         event.configInfo = createConfigInfo(config);
3668         addStaEvent(event);
3669     }
3670 
addStaEvent(StaEvent staEvent)3671     private void addStaEvent(StaEvent staEvent) {
3672         staEvent.startTimeMillis = mClock.getElapsedSinceBootMillis();
3673         staEvent.lastRssi = mLastPollRssi;
3674         staEvent.lastFreq = mLastPollFreq;
3675         staEvent.lastLinkSpeed = mLastPollLinkSpeed;
3676         staEvent.supplicantStateChangesBitmask = mSupplicantStateChangeBitmask;
3677         staEvent.lastScore = mLastScore;
3678         staEvent.lastWifiUsabilityScore = mLastWifiUsabilityScore;
3679         staEvent.lastPredictionHorizonSec = mLastPredictionHorizonSec;
3680         mSupplicantStateChangeBitmask = 0;
3681         mLastPollRssi = -127;
3682         mLastPollFreq = -1;
3683         mLastPollLinkSpeed = -1;
3684         mLastScore = -1;
3685         mLastWifiUsabilityScore = -1;
3686         mLastPredictionHorizonSec = -1;
3687         mStaEventList.add(new StaEventWithTime(staEvent, mClock.getWallClockMillis()));
3688         // Prune StaEventList if it gets too long
3689         if (mStaEventList.size() > MAX_STA_EVENTS) mStaEventList.remove();
3690     }
3691 
createConfigInfo(WifiConfiguration config)3692     private ConfigInfo createConfigInfo(WifiConfiguration config) {
3693         if (config == null) return null;
3694         ConfigInfo info = new ConfigInfo();
3695         info.allowedKeyManagement = bitSetToInt(config.allowedKeyManagement);
3696         info.allowedProtocols = bitSetToInt(config.allowedProtocols);
3697         info.allowedAuthAlgorithms = bitSetToInt(config.allowedAuthAlgorithms);
3698         info.allowedPairwiseCiphers = bitSetToInt(config.allowedPairwiseCiphers);
3699         info.allowedGroupCiphers = bitSetToInt(config.allowedGroupCiphers);
3700         info.hiddenSsid = config.hiddenSSID;
3701         info.isPasspoint = config.isPasspoint();
3702         info.isEphemeral = config.isEphemeral();
3703         info.hasEverConnected = config.getNetworkSelectionStatus().getHasEverConnected();
3704         ScanResult candidate = config.getNetworkSelectionStatus().getCandidate();
3705         if (candidate != null) {
3706             info.scanRssi = candidate.level;
3707             info.scanFreq = candidate.frequency;
3708         }
3709         return info;
3710     }
3711 
getHandler()3712     public Handler getHandler() {
3713         return mHandler;
3714     }
3715 
getWifiAwareMetrics()3716     public WifiAwareMetrics getWifiAwareMetrics() {
3717         return mWifiAwareMetrics;
3718     }
3719 
getWakeupMetrics()3720     public WifiWakeMetrics getWakeupMetrics() {
3721         return mWifiWakeMetrics;
3722     }
3723 
getRttMetrics()3724     public RttMetrics getRttMetrics() {
3725         return mRttMetrics;
3726     }
3727 
3728     // Rather than generate a StaEvent for each SUPPLICANT_STATE_CHANGE, cache these in a bitmask
3729     // and attach it to the next event which is generated.
3730     private int mSupplicantStateChangeBitmask = 0;
3731 
3732     /**
3733      * Converts a SupplicantState value to a single bit, with position defined by
3734      * {@code StaEvent.SupplicantState}
3735      */
supplicantStateToBit(SupplicantState state)3736     public static int supplicantStateToBit(SupplicantState state) {
3737         switch(state) {
3738             case DISCONNECTED:
3739                 return 1 << StaEvent.STATE_DISCONNECTED;
3740             case INTERFACE_DISABLED:
3741                 return 1 << StaEvent.STATE_INTERFACE_DISABLED;
3742             case INACTIVE:
3743                 return 1 << StaEvent.STATE_INACTIVE;
3744             case SCANNING:
3745                 return 1 << StaEvent.STATE_SCANNING;
3746             case AUTHENTICATING:
3747                 return 1 << StaEvent.STATE_AUTHENTICATING;
3748             case ASSOCIATING:
3749                 return 1 << StaEvent.STATE_ASSOCIATING;
3750             case ASSOCIATED:
3751                 return 1 << StaEvent.STATE_ASSOCIATED;
3752             case FOUR_WAY_HANDSHAKE:
3753                 return 1 << StaEvent.STATE_FOUR_WAY_HANDSHAKE;
3754             case GROUP_HANDSHAKE:
3755                 return 1 << StaEvent.STATE_GROUP_HANDSHAKE;
3756             case COMPLETED:
3757                 return 1 << StaEvent.STATE_COMPLETED;
3758             case DORMANT:
3759                 return 1 << StaEvent.STATE_DORMANT;
3760             case UNINITIALIZED:
3761                 return 1 << StaEvent.STATE_UNINITIALIZED;
3762             case INVALID:
3763                 return 1 << StaEvent.STATE_INVALID;
3764             default:
3765                 Log.wtf(TAG, "Got unknown supplicant state: " + state.ordinal());
3766                 return 0;
3767         }
3768     }
3769 
supplicantStateChangesBitmaskToString(int mask)3770     private static String supplicantStateChangesBitmaskToString(int mask) {
3771         StringBuilder sb = new StringBuilder();
3772         sb.append("supplicantStateChangeEvents: {");
3773         if ((mask & (1 << StaEvent.STATE_DISCONNECTED)) > 0) sb.append(" DISCONNECTED");
3774         if ((mask & (1 << StaEvent.STATE_INTERFACE_DISABLED)) > 0) sb.append(" INTERFACE_DISABLED");
3775         if ((mask & (1 << StaEvent.STATE_INACTIVE)) > 0) sb.append(" INACTIVE");
3776         if ((mask & (1 << StaEvent.STATE_SCANNING)) > 0) sb.append(" SCANNING");
3777         if ((mask & (1 << StaEvent.STATE_AUTHENTICATING)) > 0) sb.append(" AUTHENTICATING");
3778         if ((mask & (1 << StaEvent.STATE_ASSOCIATING)) > 0) sb.append(" ASSOCIATING");
3779         if ((mask & (1 << StaEvent.STATE_ASSOCIATED)) > 0) sb.append(" ASSOCIATED");
3780         if ((mask & (1 << StaEvent.STATE_FOUR_WAY_HANDSHAKE)) > 0) sb.append(" FOUR_WAY_HANDSHAKE");
3781         if ((mask & (1 << StaEvent.STATE_GROUP_HANDSHAKE)) > 0) sb.append(" GROUP_HANDSHAKE");
3782         if ((mask & (1 << StaEvent.STATE_COMPLETED)) > 0) sb.append(" COMPLETED");
3783         if ((mask & (1 << StaEvent.STATE_DORMANT)) > 0) sb.append(" DORMANT");
3784         if ((mask & (1 << StaEvent.STATE_UNINITIALIZED)) > 0) sb.append(" UNINITIALIZED");
3785         if ((mask & (1 << StaEvent.STATE_INVALID)) > 0) sb.append(" INVALID");
3786         sb.append(" }");
3787         return sb.toString();
3788     }
3789 
3790     /**
3791      * Returns a human readable string from a Sta Event. Only adds information relevant to the event
3792      * type.
3793      */
staEventToString(StaEvent event)3794     public static String staEventToString(StaEvent event) {
3795         if (event == null) return "<NULL>";
3796         StringBuilder sb = new StringBuilder();
3797         switch (event.type) {
3798             case StaEvent.TYPE_ASSOCIATION_REJECTION_EVENT:
3799                 sb.append("ASSOCIATION_REJECTION_EVENT")
3800                         .append(" timedOut=").append(event.associationTimedOut)
3801                         .append(" status=").append(event.status).append(":")
3802                         .append(ISupplicantStaIfaceCallback.StatusCode.toString(event.status));
3803                 break;
3804             case StaEvent.TYPE_AUTHENTICATION_FAILURE_EVENT:
3805                 sb.append("AUTHENTICATION_FAILURE_EVENT reason=").append(event.authFailureReason)
3806                         .append(":").append(authFailureReasonToString(event.authFailureReason));
3807                 break;
3808             case StaEvent.TYPE_NETWORK_CONNECTION_EVENT:
3809                 sb.append("NETWORK_CONNECTION_EVENT");
3810                 break;
3811             case StaEvent.TYPE_NETWORK_DISCONNECTION_EVENT:
3812                 sb.append("NETWORK_DISCONNECTION_EVENT")
3813                         .append(" local_gen=").append(event.localGen)
3814                         .append(" reason=").append(event.reason).append(":")
3815                         .append(ISupplicantStaIfaceCallback.ReasonCode.toString(
3816                                 (event.reason >= 0 ? event.reason : -1 * event.reason)));
3817                 break;
3818             case StaEvent.TYPE_CMD_ASSOCIATED_BSSID:
3819                 sb.append("CMD_ASSOCIATED_BSSID");
3820                 break;
3821             case StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL:
3822                 sb.append("CMD_IP_CONFIGURATION_SUCCESSFUL");
3823                 break;
3824             case StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST:
3825                 sb.append("CMD_IP_CONFIGURATION_LOST");
3826                 break;
3827             case StaEvent.TYPE_CMD_IP_REACHABILITY_LOST:
3828                 sb.append("CMD_IP_REACHABILITY_LOST");
3829                 break;
3830             case StaEvent.TYPE_CMD_TARGET_BSSID:
3831                 sb.append("CMD_TARGET_BSSID");
3832                 break;
3833             case StaEvent.TYPE_CMD_START_CONNECT:
3834                 sb.append("CMD_START_CONNECT");
3835                 break;
3836             case StaEvent.TYPE_CMD_START_ROAM:
3837                 sb.append("CMD_START_ROAM");
3838                 break;
3839             case StaEvent.TYPE_CONNECT_NETWORK:
3840                 sb.append("CONNECT_NETWORK");
3841                 break;
3842             case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK:
3843                 sb.append("NETWORK_AGENT_VALID_NETWORK");
3844                 break;
3845             case StaEvent.TYPE_FRAMEWORK_DISCONNECT:
3846                 sb.append("FRAMEWORK_DISCONNECT")
3847                         .append(" reason=")
3848                         .append(frameworkDisconnectReasonToString(event.frameworkDisconnectReason));
3849                 break;
3850             case StaEvent.TYPE_SCORE_BREACH:
3851                 sb.append("SCORE_BREACH");
3852                 break;
3853             case StaEvent.TYPE_MAC_CHANGE:
3854                 sb.append("MAC_CHANGE");
3855                 break;
3856             case StaEvent.TYPE_WIFI_ENABLED:
3857                 sb.append("WIFI_ENABLED");
3858                 break;
3859             case StaEvent.TYPE_WIFI_DISABLED:
3860                 sb.append("WIFI_DISABLED");
3861                 break;
3862             case StaEvent.TYPE_WIFI_USABILITY_SCORE_BREACH:
3863                 sb.append("WIFI_USABILITY_SCORE_BREACH");
3864                 break;
3865             case StaEvent.TYPE_LINK_PROBE:
3866                 sb.append("LINK_PROBE");
3867                 sb.append(" linkProbeWasSuccess=").append(event.linkProbeWasSuccess);
3868                 if (event.linkProbeWasSuccess) {
3869                     sb.append(" linkProbeSuccessElapsedTimeMs=")
3870                             .append(event.linkProbeSuccessElapsedTimeMs);
3871                 } else {
3872                     sb.append(" linkProbeFailureReason=").append(event.linkProbeFailureReason);
3873                 }
3874                 break;
3875             default:
3876                 sb.append("UNKNOWN " + event.type + ":");
3877                 break;
3878         }
3879         if (event.lastRssi != -127) sb.append(" lastRssi=").append(event.lastRssi);
3880         if (event.lastFreq != -1) sb.append(" lastFreq=").append(event.lastFreq);
3881         if (event.lastLinkSpeed != -1) sb.append(" lastLinkSpeed=").append(event.lastLinkSpeed);
3882         if (event.lastScore != -1) sb.append(" lastScore=").append(event.lastScore);
3883         if (event.lastWifiUsabilityScore != -1) {
3884             sb.append(" lastWifiUsabilityScore=").append(event.lastWifiUsabilityScore);
3885             sb.append(" lastPredictionHorizonSec=").append(event.lastPredictionHorizonSec);
3886         }
3887         if (event.supplicantStateChangesBitmask != 0) {
3888             sb.append(", ").append(supplicantStateChangesBitmaskToString(
3889                     event.supplicantStateChangesBitmask));
3890         }
3891         if (event.configInfo != null) {
3892             sb.append(", ").append(configInfoToString(event.configInfo));
3893         }
3894 
3895         return sb.toString();
3896     }
3897 
authFailureReasonToString(int authFailureReason)3898     private static String authFailureReasonToString(int authFailureReason) {
3899         switch (authFailureReason) {
3900             case StaEvent.AUTH_FAILURE_NONE:
3901                 return "ERROR_AUTH_FAILURE_NONE";
3902             case StaEvent.AUTH_FAILURE_TIMEOUT:
3903                 return "ERROR_AUTH_FAILURE_TIMEOUT";
3904             case StaEvent.AUTH_FAILURE_WRONG_PSWD:
3905                 return "ERROR_AUTH_FAILURE_WRONG_PSWD";
3906             case StaEvent.AUTH_FAILURE_EAP_FAILURE:
3907                 return "ERROR_AUTH_FAILURE_EAP_FAILURE";
3908             default:
3909                 return "";
3910         }
3911     }
3912 
frameworkDisconnectReasonToString(int frameworkDisconnectReason)3913     private static String frameworkDisconnectReasonToString(int frameworkDisconnectReason) {
3914         switch (frameworkDisconnectReason) {
3915             case StaEvent.DISCONNECT_API:
3916                 return "DISCONNECT_API";
3917             case StaEvent.DISCONNECT_GENERIC:
3918                 return "DISCONNECT_GENERIC";
3919             case StaEvent.DISCONNECT_UNWANTED:
3920                 return "DISCONNECT_UNWANTED";
3921             case StaEvent.DISCONNECT_ROAM_WATCHDOG_TIMER:
3922                 return "DISCONNECT_ROAM_WATCHDOG_TIMER";
3923             case StaEvent.DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST:
3924                 return "DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST";
3925             case StaEvent.DISCONNECT_RESET_SIM_NETWORKS:
3926                 return "DISCONNECT_RESET_SIM_NETWORKS";
3927             default:
3928                 return "DISCONNECT_UNKNOWN=" + frameworkDisconnectReason;
3929         }
3930     }
3931 
configInfoToString(ConfigInfo info)3932     private static String configInfoToString(ConfigInfo info) {
3933         StringBuilder sb = new StringBuilder();
3934         sb.append("ConfigInfo:")
3935                 .append(" allowed_key_management=").append(info.allowedKeyManagement)
3936                 .append(" allowed_protocols=").append(info.allowedProtocols)
3937                 .append(" allowed_auth_algorithms=").append(info.allowedAuthAlgorithms)
3938                 .append(" allowed_pairwise_ciphers=").append(info.allowedPairwiseCiphers)
3939                 .append(" allowed_group_ciphers=").append(info.allowedGroupCiphers)
3940                 .append(" hidden_ssid=").append(info.hiddenSsid)
3941                 .append(" is_passpoint=").append(info.isPasspoint)
3942                 .append(" is_ephemeral=").append(info.isEphemeral)
3943                 .append(" has_ever_connected=").append(info.hasEverConnected)
3944                 .append(" scan_rssi=").append(info.scanRssi)
3945                 .append(" scan_freq=").append(info.scanFreq);
3946         return sb.toString();
3947     }
3948 
3949     /**
3950      * Converts the first 31 bits of a BitSet to a little endian int
3951      */
bitSetToInt(BitSet bits)3952     private static int bitSetToInt(BitSet bits) {
3953         int value = 0;
3954         int nBits = bits.length() < 31 ? bits.length() : 31;
3955         for (int i = 0; i < nBits; i++) {
3956             value += bits.get(i) ? (1 << i) : 0;
3957         }
3958         return value;
3959     }
3960     private void incrementSsid(SparseIntArray sia, int element) {
3961         increment(sia, Math.min(element, MAX_CONNECTABLE_SSID_NETWORK_BUCKET));
3962     }
3963     private void incrementBssid(SparseIntArray sia, int element) {
3964         increment(sia, Math.min(element, MAX_CONNECTABLE_BSSID_NETWORK_BUCKET));
3965     }
3966     private void incrementTotalScanResults(SparseIntArray sia, int element) {
3967         increment(sia, Math.min(element, MAX_TOTAL_SCAN_RESULTS_BUCKET));
3968     }
3969     private void incrementTotalScanSsids(SparseIntArray sia, int element) {
3970         increment(sia, Math.min(element, MAX_TOTAL_SCAN_RESULT_SSIDS_BUCKET));
3971     }
3972     private void incrementTotalPasspointAps(SparseIntArray sia, int element) {
3973         increment(sia, Math.min(element, MAX_TOTAL_PASSPOINT_APS_BUCKET));
3974     }
3975     private void incrementTotalUniquePasspointEss(SparseIntArray sia, int element) {
3976         increment(sia, Math.min(element, MAX_TOTAL_PASSPOINT_UNIQUE_ESS_BUCKET));
3977     }
3978     private void incrementPasspointPerUniqueEss(SparseIntArray sia, int element) {
3979         increment(sia, Math.min(element, MAX_PASSPOINT_APS_PER_UNIQUE_ESS_BUCKET));
3980     }
3981     private void increment80211mcAps(SparseIntArray sia, int element) {
3982         increment(sia, Math.min(element, MAX_TOTAL_80211MC_APS_BUCKET));
3983     }
3984     private void increment(SparseIntArray sia, int element) {
3985         int count = sia.get(element);
3986         sia.put(element, count + 1);
3987     }
3988 
3989     private static class StaEventWithTime {
3990         public StaEvent staEvent;
3991         public long wallClockMillis;
3992 
3993         StaEventWithTime(StaEvent event, long wallClockMillis) {
3994             staEvent = event;
3995             this.wallClockMillis = wallClockMillis;
3996         }
3997 
3998         public String toString() {
3999             StringBuilder sb = new StringBuilder();
4000             Calendar c = Calendar.getInstance();
4001             c.setTimeInMillis(wallClockMillis);
4002             if (wallClockMillis != 0) {
4003                 sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
4004             } else {
4005                 sb.append("                  ");
4006             }
4007             sb.append(" ").append(staEventToString(staEvent));
4008             return sb.toString();
4009         }
4010     }
4011 
4012     private LinkedList<WifiIsUnusableWithTime> mWifiIsUnusableList =
4013             new LinkedList<WifiIsUnusableWithTime>();
4014     private long mTxScucessDelta = 0;
4015     private long mTxRetriesDelta = 0;
4016     private long mTxBadDelta = 0;
4017     private long mRxSuccessDelta = 0;
4018     private long mLlStatsUpdateTimeDelta = 0;
4019     private long mLlStatsLastUpdateTime = 0;
4020     private int mLastScoreNoReset = -1;
4021     private long mLastDataStallTime = Long.MIN_VALUE;
4022 
4023     private static class WifiIsUnusableWithTime {
4024         public WifiIsUnusableEvent event;
4025         public long wallClockMillis;
4026 
4027         WifiIsUnusableWithTime(WifiIsUnusableEvent event, long wallClockMillis) {
4028             this.event = event;
4029             this.wallClockMillis = wallClockMillis;
4030         }
4031 
4032         public String toString() {
4033             if (event == null) return "<NULL>";
4034             StringBuilder sb = new StringBuilder();
4035             if (wallClockMillis != 0) {
4036                 Calendar c = Calendar.getInstance();
4037                 c.setTimeInMillis(wallClockMillis);
4038                 sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
4039             } else {
4040                 sb.append("                  ");
4041             }
4042             sb.append(" ");
4043 
4044             switch(event.type) {
4045                 case WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX:
4046                     sb.append("DATA_STALL_BAD_TX");
4047                     break;
4048                 case WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX:
4049                     sb.append("DATA_STALL_TX_WITHOUT_RX");
4050                     break;
4051                 case WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH:
4052                     sb.append("DATA_STALL_BOTH");
4053                     break;
4054                 case WifiIsUnusableEvent.TYPE_FIRMWARE_ALERT:
4055                     sb.append("FIRMWARE_ALERT");
4056                     break;
4057                 default:
4058                     sb.append("UNKNOWN " + event.type);
4059                     break;
4060             }
4061 
4062             sb.append(" lastScore=").append(event.lastScore);
4063             sb.append(" txSuccessDelta=").append(event.txSuccessDelta);
4064             sb.append(" txRetriesDelta=").append(event.txRetriesDelta);
4065             sb.append(" txBadDelta=").append(event.txBadDelta);
4066             sb.append(" rxSuccessDelta=").append(event.rxSuccessDelta);
4067             sb.append(" packetUpdateTimeDelta=").append(event.packetUpdateTimeDelta)
4068                     .append("ms");
4069             if (event.firmwareAlertCode != -1) {
4070                 sb.append(" firmwareAlertCode=").append(event.firmwareAlertCode);
4071             }
4072             sb.append(" lastWifiUsabilityScore=").append(event.lastWifiUsabilityScore);
4073             sb.append(" lastPredictionHorizonSec=").append(event.lastPredictionHorizonSec);
4074             return sb.toString();
4075         }
4076     }
4077 
4078     /**
4079      * Update the difference between the last two WifiLinkLayerStats for WifiIsUnusableEvent
4080      */
4081     public void updateWifiIsUnusableLinkLayerStats(long txSuccessDelta, long txRetriesDelta,
4082             long txBadDelta, long rxSuccessDelta, long updateTimeDelta) {
4083         mTxScucessDelta = txSuccessDelta;
4084         mTxRetriesDelta = txRetriesDelta;
4085         mTxBadDelta = txBadDelta;
4086         mRxSuccessDelta = rxSuccessDelta;
4087         mLlStatsUpdateTimeDelta = updateTimeDelta;
4088         mLlStatsLastUpdateTime = mClock.getElapsedSinceBootMillis();
4089     }
4090 
4091     /**
4092      * Clear the saved difference between the last two WifiLinkLayerStats
4093      */
4094     public void resetWifiIsUnusableLinkLayerStats() {
4095         mTxScucessDelta = 0;
4096         mTxRetriesDelta = 0;
4097         mTxBadDelta = 0;
4098         mRxSuccessDelta = 0;
4099         mLlStatsUpdateTimeDelta = 0;
4100         mLlStatsLastUpdateTime = 0;
4101         mLastDataStallTime = Long.MIN_VALUE;
4102     }
4103 
4104     /**
4105      * Log a WifiIsUnusableEvent
4106      * @param triggerType WifiIsUnusableEvent.type describing the event
4107      */
4108     public void logWifiIsUnusableEvent(int triggerType) {
4109         logWifiIsUnusableEvent(triggerType, -1);
4110     }
4111 
4112     /**
4113      * Log a WifiIsUnusableEvent
4114      * @param triggerType WifiIsUnusableEvent.type describing the event
4115      * @param firmwareAlertCode WifiIsUnusableEvent.firmwareAlertCode for firmware alert code
4116      */
4117     public void logWifiIsUnusableEvent(int triggerType, int firmwareAlertCode) {
4118         mScoreBreachLowTimeMillis = -1;
4119         if (!mUnusableEventLogging) {
4120             return;
4121         }
4122 
4123         long currentBootTime = mClock.getElapsedSinceBootMillis();
4124         switch (triggerType) {
4125             case WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX:
4126             case WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX:
4127             case WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH:
4128                 // Have a time-based throttle for generating WifiIsUnusableEvent from data stalls
4129                 if (currentBootTime < mLastDataStallTime + MIN_DATA_STALL_WAIT_MS) {
4130                     return;
4131                 }
4132                 mLastDataStallTime = currentBootTime;
4133                 break;
4134             case WifiIsUnusableEvent.TYPE_FIRMWARE_ALERT:
4135                 break;
4136             case WifiIsUnusableEvent.TYPE_IP_REACHABILITY_LOST:
4137                 break;
4138             default:
4139                 Log.e(TAG, "Unknown WifiIsUnusableEvent: " + triggerType);
4140                 return;
4141         }
4142 
4143         WifiIsUnusableEvent event = new WifiIsUnusableEvent();
4144         event.type = triggerType;
4145         if (triggerType == WifiIsUnusableEvent.TYPE_FIRMWARE_ALERT) {
4146             event.firmwareAlertCode = firmwareAlertCode;
4147         }
4148         event.startTimeMillis = currentBootTime;
4149         event.lastScore = mLastScoreNoReset;
4150         event.lastWifiUsabilityScore = mLastWifiUsabilityScoreNoReset;
4151         event.lastPredictionHorizonSec = mLastPredictionHorizonSecNoReset;
4152         event.txSuccessDelta = mTxScucessDelta;
4153         event.txRetriesDelta = mTxRetriesDelta;
4154         event.txBadDelta = mTxBadDelta;
4155         event.rxSuccessDelta = mRxSuccessDelta;
4156         event.packetUpdateTimeDelta = mLlStatsUpdateTimeDelta;
4157         event.lastLinkLayerStatsUpdateTime = mLlStatsLastUpdateTime;
4158         event.screenOn = mScreenOn;
4159 
4160         mWifiIsUnusableList.add(new WifiIsUnusableWithTime(event, mClock.getWallClockMillis()));
4161         if (mWifiIsUnusableList.size() > MAX_UNUSABLE_EVENTS) {
4162             mWifiIsUnusableList.removeFirst();
4163         }
4164     }
4165 
4166     /**
4167      * Sets whether or not WifiIsUnusableEvent is logged in metrics
4168      */
4169     @VisibleForTesting
4170     public void setWifiIsUnusableLoggingEnabled(boolean enabled) {
4171         synchronized (mLock) {
4172             mExperimentValues.wifiIsUnusableLoggingEnabled = enabled;
4173         }
4174     }
4175 
4176     /**
4177      * Sets whether or not LinkSpeedCounts is logged in metrics
4178      */
4179     @VisibleForTesting
4180     public void setLinkSpeedCountsLoggingEnabled(boolean enabled) {
4181         synchronized (mLock) {
4182             mExperimentValues.linkSpeedCountsLoggingEnabled = enabled;
4183         }
4184     }
4185 
4186     /**
4187      * Sets the minimum number of txBad to trigger a data stall
4188      */
4189     public void setWifiDataStallMinTxBad(int minTxBad) {
4190         synchronized (mLock) {
4191             mExperimentValues.wifiDataStallMinTxBad = minTxBad;
4192         }
4193     }
4194 
4195     /**
4196      * Sets the minimum number of txSuccess to trigger a data stall
4197      * when rxSuccess is 0
4198      */
4199     public void setWifiDataStallMinRxWithoutTx(int minTxSuccessWithoutRx) {
4200         synchronized (mLock) {
4201             mExperimentValues.wifiDataStallMinTxSuccessWithoutRx = minTxSuccessWithoutRx;
4202         }
4203     }
4204 
4205     /**
4206      * Extract data from |info| and |stats| to build a WifiUsabilityStatsEntry and then adds it
4207      * into an internal ring buffer.
4208      * @param info
4209      * @param stats
4210      */
4211     public void updateWifiUsabilityStatsEntries(WifiInfo info, WifiLinkLayerStats stats) {
4212         synchronized (mLock) {
4213             if (info == null || stats == null) {
4214                 return;
4215             }
4216             WifiUsabilityStatsEntry wifiUsabilityStatsEntry =
4217                     mWifiUsabilityStatsEntriesList.size()
4218                     < MAX_WIFI_USABILITY_STATS_ENTRIES_LIST_SIZE
4219                     ? new WifiUsabilityStatsEntry() : mWifiUsabilityStatsEntriesList.remove();
4220             wifiUsabilityStatsEntry.timeStampMs = stats.timeStampInMs;
4221             wifiUsabilityStatsEntry.totalTxSuccess = stats.txmpdu_be + stats.txmpdu_bk
4222                     + stats.txmpdu_vi + stats.txmpdu_vo;
4223             wifiUsabilityStatsEntry.totalTxRetries = stats.retries_be + stats.retries_bk
4224                     + stats.retries_vi + stats.retries_vo;
4225             wifiUsabilityStatsEntry.totalTxBad = stats.lostmpdu_be + stats.lostmpdu_bk
4226                     + stats.lostmpdu_vi + stats.lostmpdu_vo;
4227             wifiUsabilityStatsEntry.totalRxSuccess = stats.rxmpdu_be + stats.rxmpdu_bk
4228                     + stats.rxmpdu_vi + stats.rxmpdu_vo;
4229             wifiUsabilityStatsEntry.totalRadioOnTimeMs = stats.on_time;
4230             wifiUsabilityStatsEntry.totalRadioTxTimeMs = stats.tx_time;
4231             wifiUsabilityStatsEntry.totalRadioRxTimeMs = stats.rx_time;
4232             wifiUsabilityStatsEntry.totalScanTimeMs = stats.on_time_scan;
4233             wifiUsabilityStatsEntry.totalNanScanTimeMs = stats.on_time_nan_scan;
4234             wifiUsabilityStatsEntry.totalBackgroundScanTimeMs = stats.on_time_background_scan;
4235             wifiUsabilityStatsEntry.totalRoamScanTimeMs = stats.on_time_roam_scan;
4236             wifiUsabilityStatsEntry.totalPnoScanTimeMs = stats.on_time_pno_scan;
4237             wifiUsabilityStatsEntry.totalHotspot2ScanTimeMs = stats.on_time_hs20_scan;
4238             wifiUsabilityStatsEntry.rssi = info.getRssi();
4239             wifiUsabilityStatsEntry.linkSpeedMbps = info.getLinkSpeed();
4240             WifiLinkLayerStats.ChannelStats statsMap =
4241                     stats.channelStatsMap.get(info.getFrequency());
4242             if (statsMap != null) {
4243                 wifiUsabilityStatsEntry.totalRadioOnFreqTimeMs = statsMap.radioOnTimeMs;
4244                 wifiUsabilityStatsEntry.totalCcaBusyFreqTimeMs = statsMap.ccaBusyTimeMs;
4245             }
4246             wifiUsabilityStatsEntry.totalBeaconRx = stats.beacon_rx;
4247 
4248             boolean isSameBssidAndFreq = mLastBssid == null || mLastFrequency == -1
4249                     || (mLastBssid.equals(info.getBSSID())
4250                     && mLastFrequency == info.getFrequency());
4251             mLastBssid = info.getBSSID();
4252             mLastFrequency = info.getFrequency();
4253             wifiUsabilityStatsEntry.wifiScore = mLastScoreNoReset;
4254             wifiUsabilityStatsEntry.wifiUsabilityScore = mLastWifiUsabilityScoreNoReset;
4255             wifiUsabilityStatsEntry.seqNumToFramework = mSeqNumToFramework;
4256             wifiUsabilityStatsEntry.predictionHorizonSec = mLastPredictionHorizonSecNoReset;
4257             switch (mProbeStatusSinceLastUpdate) {
4258                 case android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE:
4259                     wifiUsabilityStatsEntry.probeStatusSinceLastUpdate =
4260                             WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE;
4261                     break;
4262                 case android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS:
4263                     wifiUsabilityStatsEntry.probeStatusSinceLastUpdate =
4264                             WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS;
4265                     break;
4266                 case android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE:
4267                     wifiUsabilityStatsEntry.probeStatusSinceLastUpdate =
4268                             WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE;
4269                     break;
4270                 default:
4271                     wifiUsabilityStatsEntry.probeStatusSinceLastUpdate =
4272                             WifiUsabilityStatsEntry.PROBE_STATUS_UNKNOWN;
4273                     Log.e(TAG, "Unknown link probe status: " + mProbeStatusSinceLastUpdate);
4274             }
4275             wifiUsabilityStatsEntry.probeElapsedTimeSinceLastUpdateMs =
4276                     mProbeElapsedTimeSinceLastUpdateMs;
4277             wifiUsabilityStatsEntry.probeMcsRateSinceLastUpdate = mProbeMcsRateSinceLastUpdate;
4278             wifiUsabilityStatsEntry.rxLinkSpeedMbps = info.getRxLinkSpeedMbps();
4279             wifiUsabilityStatsEntry.isSameBssidAndFreq = isSameBssidAndFreq;
4280             wifiUsabilityStatsEntry.seqNumInsideFramework = mSeqNumInsideFramework;
4281             wifiUsabilityStatsEntry.deviceMobilityState = mCurrentDeviceMobilityState;
4282 
4283             CellularLinkLayerStats cls = mCellularLinkLayerStatsCollector.update();
4284             if (DBG) Log.v(TAG, "Latest Cellular Link Layer Stats: " + cls);
4285             wifiUsabilityStatsEntry.cellularDataNetworkType =
4286                     parseDataNetworkTypeToProto(cls.getDataNetworkType());
4287             wifiUsabilityStatsEntry.cellularSignalStrengthDbm = cls.getSignalStrengthDbm();
4288             wifiUsabilityStatsEntry.cellularSignalStrengthDb = cls.getSignalStrengthDb();
4289             wifiUsabilityStatsEntry.isSameRegisteredCell = cls.getIsSameRegisteredCell();
4290 
4291             mWifiUsabilityStatsEntriesList.add(wifiUsabilityStatsEntry);
4292             mWifiUsabilityStatsCounter++;
4293             if (mWifiUsabilityStatsCounter >= NUM_WIFI_USABILITY_STATS_ENTRIES_PER_WIFI_GOOD) {
4294                 addToWifiUsabilityStatsList(WifiUsabilityStats.LABEL_GOOD,
4295                         WifiUsabilityStats.TYPE_UNKNOWN, -1);
4296             }
4297             if (mScoreBreachLowTimeMillis != -1) {
4298                 long elapsedTime =  mClock.getElapsedSinceBootMillis() - mScoreBreachLowTimeMillis;
4299                 if (elapsedTime >= MIN_SCORE_BREACH_TO_GOOD_STATS_WAIT_TIME_MS) {
4300                     mScoreBreachLowTimeMillis = -1;
4301                     if (elapsedTime <= VALIDITY_PERIOD_OF_SCORE_BREACH_LOW_MS) {
4302                         addToWifiUsabilityStatsList(WifiUsabilityStats.LABEL_GOOD,
4303                                 WifiUsabilityStats.TYPE_UNKNOWN, -1);
4304                     }
4305                 }
4306             }
4307 
4308             // Invoke Wifi usability stats listener.
4309             sendWifiUsabilityStats(mSeqNumInsideFramework, isSameBssidAndFreq,
4310                     createNewWifiUsabilityStatsEntryParcelable(wifiUsabilityStatsEntry));
4311 
4312             mSeqNumInsideFramework++;
4313             mProbeStatusSinceLastUpdate =
4314                     android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE;
4315             mProbeElapsedTimeSinceLastUpdateMs = -1;
4316             mProbeMcsRateSinceLastUpdate = -1;
4317         }
4318     }
4319 
4320     private int parseDataNetworkTypeToProto(int cellularDataNetworkType) {
4321         switch (cellularDataNetworkType) {
4322             case TelephonyManager.NETWORK_TYPE_UNKNOWN:
4323                 return WifiUsabilityStatsEntry.NETWORK_TYPE_UNKNOWN;
4324             case TelephonyManager.NETWORK_TYPE_GSM:
4325                 return WifiUsabilityStatsEntry.NETWORK_TYPE_GSM;
4326             case TelephonyManager.NETWORK_TYPE_CDMA:
4327                 return WifiUsabilityStatsEntry.NETWORK_TYPE_CDMA;
4328             case TelephonyManager.NETWORK_TYPE_EVDO_0:
4329                 return WifiUsabilityStatsEntry.NETWORK_TYPE_EVDO_0;
4330             case TelephonyManager.NETWORK_TYPE_UMTS:
4331                 return WifiUsabilityStatsEntry.NETWORK_TYPE_UMTS;
4332             case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
4333                 return WifiUsabilityStatsEntry.NETWORK_TYPE_TD_SCDMA;
4334             case TelephonyManager.NETWORK_TYPE_LTE:
4335                 return WifiUsabilityStatsEntry.NETWORK_TYPE_LTE;
4336             case TelephonyManager.NETWORK_TYPE_NR:
4337                 return WifiUsabilityStatsEntry.NETWORK_TYPE_NR;
4338             default:
4339                 Log.e(TAG, "Unknown data network type : " + cellularDataNetworkType);
4340                 return WifiUsabilityStatsEntry.NETWORK_TYPE_UNKNOWN;
4341         }
4342     }
4343 
4344     private int parseDataNetworkTypeFromProto(int cellularDataNetworkType) {
4345         switch (cellularDataNetworkType) {
4346             case WifiUsabilityStatsEntry.NETWORK_TYPE_UNKNOWN:
4347                 return TelephonyManager.NETWORK_TYPE_UNKNOWN;
4348             case WifiUsabilityStatsEntry.NETWORK_TYPE_GSM:
4349                 return TelephonyManager.NETWORK_TYPE_GSM;
4350             case WifiUsabilityStatsEntry.NETWORK_TYPE_CDMA:
4351                 return TelephonyManager.NETWORK_TYPE_CDMA;
4352             case WifiUsabilityStatsEntry.NETWORK_TYPE_EVDO_0:
4353                 return TelephonyManager.NETWORK_TYPE_EVDO_0;
4354             case WifiUsabilityStatsEntry.NETWORK_TYPE_UMTS:
4355                 return TelephonyManager.NETWORK_TYPE_UMTS;
4356             case WifiUsabilityStatsEntry.NETWORK_TYPE_TD_SCDMA:
4357                 return TelephonyManager.NETWORK_TYPE_TD_SCDMA;
4358             case WifiUsabilityStatsEntry.NETWORK_TYPE_LTE:
4359                 return TelephonyManager.NETWORK_TYPE_LTE;
4360             case WifiUsabilityStatsEntry.NETWORK_TYPE_NR:
4361                 return TelephonyManager.NETWORK_TYPE_NR;
4362             default:
4363                 Log.e(TAG, "Unknown data network type : " + cellularDataNetworkType);
4364                 return TelephonyManager.NETWORK_TYPE_UNKNOWN;
4365         }
4366     }
4367     /**
4368      * Send Wifi usability stats.
4369      * @param seqNum
4370      * @param isSameBssidAndFreq
4371      * @param statsEntry
4372      */
4373     private void sendWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
4374             android.net.wifi.WifiUsabilityStatsEntry statsEntry) {
4375         for (IOnWifiUsabilityStatsListener listener : mOnWifiUsabilityListeners.getCallbacks()) {
4376             try {
4377                 listener.onWifiUsabilityStats(seqNum, isSameBssidAndFreq, statsEntry);
4378             } catch (RemoteException e) {
4379                 Log.e(TAG, "Unable to invoke Wifi usability stats entry listener "
4380                         + listener, e);
4381             }
4382         }
4383     }
4384 
4385     private android.net.wifi.WifiUsabilityStatsEntry createNewWifiUsabilityStatsEntryParcelable(
4386             WifiUsabilityStatsEntry s) {
4387         int probeStatus;
4388         switch (s.probeStatusSinceLastUpdate) {
4389             case WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE:
4390                 probeStatus = android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE;
4391                 break;
4392             case WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS:
4393                 probeStatus = android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS;
4394                 break;
4395             case WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE:
4396                 probeStatus = android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE;
4397                 break;
4398             default:
4399                 probeStatus = android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_UNKNOWN;
4400                 Log.e(TAG, "Unknown link probe status: " + s.probeStatusSinceLastUpdate);
4401         }
4402         int cellularDataNetworkType = parseDataNetworkTypeFromProto(s.cellularDataNetworkType);
4403         return new android.net.wifi.WifiUsabilityStatsEntry(s.timeStampMs, s.rssi,
4404                 s.linkSpeedMbps, s.totalTxSuccess, s.totalTxRetries,
4405                 s.totalTxBad, s.totalRxSuccess, s.totalRadioOnTimeMs,
4406                 s.totalRadioTxTimeMs, s.totalRadioRxTimeMs, s.totalScanTimeMs,
4407                 s.totalNanScanTimeMs, s.totalBackgroundScanTimeMs, s.totalRoamScanTimeMs,
4408                 s.totalPnoScanTimeMs, s.totalHotspot2ScanTimeMs, s.totalCcaBusyFreqTimeMs,
4409                 s.totalRadioOnFreqTimeMs, s.totalBeaconRx, probeStatus,
4410                 s.probeElapsedTimeSinceLastUpdateMs, s.probeMcsRateSinceLastUpdate,
4411                 s.rxLinkSpeedMbps, cellularDataNetworkType,
4412                 s.cellularSignalStrengthDbm, s.cellularSignalStrengthDb,
4413                 s.isSameRegisteredCell
4414         );
4415     }
4416 
4417     private WifiUsabilityStatsEntry createNewWifiUsabilityStatsEntry(WifiUsabilityStatsEntry s) {
4418         WifiUsabilityStatsEntry out = new WifiUsabilityStatsEntry();
4419         out.timeStampMs = s.timeStampMs;
4420         out.totalTxSuccess = s.totalTxSuccess;
4421         out.totalTxRetries = s.totalTxRetries;
4422         out.totalTxBad = s.totalTxBad;
4423         out.totalRxSuccess = s.totalRxSuccess;
4424         out.totalRadioOnTimeMs = s.totalRadioOnTimeMs;
4425         out.totalRadioTxTimeMs = s.totalRadioTxTimeMs;
4426         out.totalRadioRxTimeMs = s.totalRadioRxTimeMs;
4427         out.totalScanTimeMs = s.totalScanTimeMs;
4428         out.totalNanScanTimeMs = s.totalNanScanTimeMs;
4429         out.totalBackgroundScanTimeMs = s.totalBackgroundScanTimeMs;
4430         out.totalRoamScanTimeMs = s.totalRoamScanTimeMs;
4431         out.totalPnoScanTimeMs = s.totalPnoScanTimeMs;
4432         out.totalHotspot2ScanTimeMs = s.totalHotspot2ScanTimeMs;
4433         out.rssi = s.rssi;
4434         out.linkSpeedMbps = s.linkSpeedMbps;
4435         out.totalCcaBusyFreqTimeMs = s.totalCcaBusyFreqTimeMs;
4436         out.totalRadioOnFreqTimeMs = s.totalRadioOnFreqTimeMs;
4437         out.totalBeaconRx = s.totalBeaconRx;
4438         out.wifiScore = s.wifiScore;
4439         out.wifiUsabilityScore = s.wifiUsabilityScore;
4440         out.seqNumToFramework = s.seqNumToFramework;
4441         out.predictionHorizonSec = s.predictionHorizonSec;
4442         out.probeStatusSinceLastUpdate = s.probeStatusSinceLastUpdate;
4443         out.probeElapsedTimeSinceLastUpdateMs = s.probeElapsedTimeSinceLastUpdateMs;
4444         out.probeMcsRateSinceLastUpdate = s.probeMcsRateSinceLastUpdate;
4445         out.rxLinkSpeedMbps = s.rxLinkSpeedMbps;
4446         out.isSameBssidAndFreq = s.isSameBssidAndFreq;
4447         out.seqNumInsideFramework = s.seqNumInsideFramework;
4448         out.cellularDataNetworkType = s.cellularDataNetworkType;
4449         out.cellularSignalStrengthDbm = s.cellularSignalStrengthDbm;
4450         out.cellularSignalStrengthDb = s.cellularSignalStrengthDb;
4451         out.isSameRegisteredCell = s.isSameRegisteredCell;
4452         out.deviceMobilityState = s.deviceMobilityState;
4453         return out;
4454     }
4455 
4456     private WifiUsabilityStats createWifiUsabilityStatsWithLabel(int label, int triggerType,
4457             int firmwareAlertCode) {
4458         WifiUsabilityStats wifiUsabilityStats = new WifiUsabilityStats();
4459         wifiUsabilityStats.label = label;
4460         wifiUsabilityStats.triggerType = triggerType;
4461         wifiUsabilityStats.firmwareAlertCode = firmwareAlertCode;
4462         wifiUsabilityStats.timeStampMs = mClock.getElapsedSinceBootMillis();
4463         wifiUsabilityStats.stats =
4464                 new WifiUsabilityStatsEntry[mWifiUsabilityStatsEntriesList.size()];
4465         for (int i = 0; i < mWifiUsabilityStatsEntriesList.size(); i++) {
4466             wifiUsabilityStats.stats[i] =
4467                     createNewWifiUsabilityStatsEntry(mWifiUsabilityStatsEntriesList.get(i));
4468         }
4469         return wifiUsabilityStats;
4470     }
4471 
4472     /**
4473      * Label the current snapshot of WifiUsabilityStatsEntrys and save the labeled data in memory.
4474      * @param label WifiUsabilityStats.LABEL_GOOD or WifiUsabilityStats.LABEL_BAD
4475      * @param triggerType what event triggers WifiUsabilityStats
4476      * @param firmwareAlertCode the firmware alert code when the stats was triggered by a
4477      *        firmware alert
4478      */
4479     public void addToWifiUsabilityStatsList(int label, int triggerType, int firmwareAlertCode) {
4480         synchronized (mLock) {
4481             if (mWifiUsabilityStatsEntriesList.isEmpty() || !mScreenOn) {
4482                 return;
4483             }
4484             if (label == WifiUsabilityStats.LABEL_GOOD) {
4485                 // Only add a good event if at least |MIN_WIFI_GOOD_USABILITY_STATS_PERIOD_MS|
4486                 // has passed.
4487                 if (mWifiUsabilityStatsListGood.isEmpty()
4488                         || mWifiUsabilityStatsListGood.getLast().stats[mWifiUsabilityStatsListGood
4489                         .getLast().stats.length - 1].timeStampMs
4490                         + MIN_WIFI_GOOD_USABILITY_STATS_PERIOD_MS
4491                         < mWifiUsabilityStatsEntriesList.getLast().timeStampMs) {
4492                     while (mWifiUsabilityStatsListGood.size()
4493                             >= MAX_WIFI_USABILITY_STATS_LIST_SIZE_PER_TYPE) {
4494                         mWifiUsabilityStatsListGood.remove(
4495                                 mRand.nextInt(mWifiUsabilityStatsListGood.size()));
4496                     }
4497                     mWifiUsabilityStatsListGood.add(
4498                             createWifiUsabilityStatsWithLabel(label, triggerType,
4499                                     firmwareAlertCode));
4500                 }
4501             } else {
4502                 // Only add a bad event if at least |MIN_DATA_STALL_WAIT_MS|
4503                 // has passed.
4504                 mScoreBreachLowTimeMillis = -1;
4505                 if (mWifiUsabilityStatsListBad.isEmpty()
4506                         || (mWifiUsabilityStatsListBad.getLast().stats[mWifiUsabilityStatsListBad
4507                         .getLast().stats.length - 1].timeStampMs
4508                         + MIN_DATA_STALL_WAIT_MS
4509                         < mWifiUsabilityStatsEntriesList.getLast().timeStampMs)) {
4510                     while (mWifiUsabilityStatsListBad.size()
4511                             >= MAX_WIFI_USABILITY_STATS_LIST_SIZE_PER_TYPE) {
4512                         mWifiUsabilityStatsListBad.remove(
4513                                 mRand.nextInt(mWifiUsabilityStatsListBad.size()));
4514                     }
4515                     mWifiUsabilityStatsListBad.add(
4516                             createWifiUsabilityStatsWithLabel(label, triggerType,
4517                                     firmwareAlertCode));
4518                 }
4519             }
4520             mWifiUsabilityStatsCounter = 0;
4521         }
4522     }
4523 
4524     private DeviceMobilityStatePnoScanStats getOrCreateDeviceMobilityStatePnoScanStats(
4525             @DeviceMobilityState int deviceMobilityState) {
4526         DeviceMobilityStatePnoScanStats stats = mMobilityStatePnoStatsMap.get(deviceMobilityState);
4527         if (stats == null) {
4528             stats = new DeviceMobilityStatePnoScanStats();
4529             stats.deviceMobilityState = deviceMobilityState;
4530             stats.numTimesEnteredState = 0;
4531             stats.totalDurationMs = 0;
4532             stats.pnoDurationMs = 0;
4533             mMobilityStatePnoStatsMap.put(deviceMobilityState, stats);
4534         }
4535         return stats;
4536     }
4537 
4538     /**
4539      * Updates the current device mobility state's total duration. This method should be called
4540      * before entering a new device mobility state.
4541      */
4542     private void updateCurrentMobilityStateTotalDuration(long now) {
4543         DeviceMobilityStatePnoScanStats stats =
4544                 getOrCreateDeviceMobilityStatePnoScanStats(mCurrentDeviceMobilityState);
4545         stats.totalDurationMs += now - mCurrentDeviceMobilityStateStartMs;
4546         mCurrentDeviceMobilityStateStartMs = now;
4547     }
4548 
4549     /**
4550      * Convert the IntCounter of passpoint profile types and counts to proto's
4551      * repeated IntKeyVal array.
4552      *
4553      * @param passpointProfileTypes passpoint profile types and counts.
4554      */
4555     private PasspointProfileTypeCount[] convertPasspointProfilesToProto(
4556                 IntCounter passpointProfileTypes) {
4557         return passpointProfileTypes.toProto(PasspointProfileTypeCount.class, (key, count) -> {
4558             PasspointProfileTypeCount entry = new PasspointProfileTypeCount();
4559             entry.eapMethodType = key;
4560             entry.count = count;
4561             return entry;
4562         });
4563     }
4564 
4565     /**
4566      * Reports that the device entered a new mobility state.
4567      *
4568      * @param newState the new device mobility state.
4569      */
4570     public void enterDeviceMobilityState(@DeviceMobilityState int newState) {
4571         synchronized (mLock) {
4572             long now = mClock.getElapsedSinceBootMillis();
4573             updateCurrentMobilityStateTotalDuration(now);
4574 
4575             if (newState == mCurrentDeviceMobilityState) return;
4576 
4577             mCurrentDeviceMobilityState = newState;
4578             DeviceMobilityStatePnoScanStats stats =
4579                     getOrCreateDeviceMobilityStatePnoScanStats(mCurrentDeviceMobilityState);
4580             stats.numTimesEnteredState++;
4581         }
4582     }
4583 
4584     /**
4585      * Logs the start of a PNO scan.
4586      */
4587     public void logPnoScanStart() {
4588         synchronized (mLock) {
4589             long now = mClock.getElapsedSinceBootMillis();
4590             mCurrentDeviceMobilityStatePnoScanStartMs = now;
4591             updateCurrentMobilityStateTotalDuration(now);
4592         }
4593     }
4594 
4595     /**
4596      * Logs the end of a PNO scan. This is attributed to the current device mobility state, as
4597      * logged by {@link #enterDeviceMobilityState(int)}. Thus, if the mobility state changes during
4598      * a PNO scan, one should call {@link #logPnoScanStop()}, {@link #enterDeviceMobilityState(int)}
4599      * , then {@link #logPnoScanStart()} so that the portion of PNO scan before the mobility state
4600      * change can be correctly attributed to the previous mobility state.
4601      */
4602     public void logPnoScanStop() {
4603         synchronized (mLock) {
4604             if (mCurrentDeviceMobilityStatePnoScanStartMs < 0) {
4605                 Log.e(TAG, "Called WifiMetrics#logPNoScanStop() without calling "
4606                         + "WifiMetrics#logPnoScanStart() first!");
4607                 return;
4608             }
4609             DeviceMobilityStatePnoScanStats stats =
4610                     getOrCreateDeviceMobilityStatePnoScanStats(mCurrentDeviceMobilityState);
4611             long now = mClock.getElapsedSinceBootMillis();
4612             stats.pnoDurationMs += now - mCurrentDeviceMobilityStatePnoScanStartMs;
4613             mCurrentDeviceMobilityStatePnoScanStartMs = -1;
4614             updateCurrentMobilityStateTotalDuration(now);
4615         }
4616     }
4617 
4618     /**
4619      * Add a new listener for Wi-Fi usability stats handling.
4620      */
4621     public void addOnWifiUsabilityListener(IBinder binder, IOnWifiUsabilityStatsListener listener,
4622             int listenerIdentifier) {
4623         if (!mOnWifiUsabilityListeners.add(binder, listener, listenerIdentifier)) {
4624             Log.e(TAG, "Failed to add listener");
4625             return;
4626         }
4627         if (DBG) {
4628             Log.v(TAG, "Adding listener. Num listeners: "
4629                     + mOnWifiUsabilityListeners.getNumCallbacks());
4630         }
4631     }
4632 
4633     /**
4634      * Remove an existing listener for Wi-Fi usability stats handling.
4635      */
4636     public void removeOnWifiUsabilityListener(int listenerIdentifier) {
4637         mOnWifiUsabilityListeners.remove(listenerIdentifier);
4638         if (DBG) {
4639             Log.v(TAG, "Removing listener. Num listeners: "
4640                     + mOnWifiUsabilityListeners.getNumCallbacks());
4641         }
4642     }
4643 
4644     /**
4645      * Updates the Wi-Fi usability score and increments occurence of a particular Wifi usability
4646      * score passed in from outside framework. Scores are bounded within
4647      * [MIN_WIFI_USABILITY_SCORE, MAX_WIFI_USABILITY_SCORE].
4648      *
4649      * Also records events when the Wifi usability score breaches significant thresholds.
4650      *
4651      * @param seqNum Sequence number of the Wi-Fi usability score.
4652      * @param score The Wi-Fi usability score.
4653      * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score.
4654      */
4655     public void incrementWifiUsabilityScoreCount(int seqNum, int score, int predictionHorizonSec) {
4656         if (score < MIN_WIFI_USABILITY_SCORE || score > MAX_WIFI_USABILITY_SCORE) {
4657             return;
4658         }
4659         synchronized (mLock) {
4660             mSeqNumToFramework = seqNum;
4661             mLastWifiUsabilityScore = score;
4662             mLastWifiUsabilityScoreNoReset = score;
4663             mWifiUsabilityScoreCounts.put(score, mWifiUsabilityScoreCounts.get(score) + 1);
4664             mLastPredictionHorizonSec = predictionHorizonSec;
4665             mLastPredictionHorizonSecNoReset = predictionHorizonSec;
4666 
4667             boolean wifiWins = mWifiWinsUsabilityScore;
4668             if (score > LOW_WIFI_USABILITY_SCORE) {
4669                 wifiWins = true;
4670             } else if (score < LOW_WIFI_USABILITY_SCORE) {
4671                 wifiWins = false;
4672             }
4673 
4674             if (wifiWins != mWifiWinsUsabilityScore) {
4675                 mWifiWinsUsabilityScore = wifiWins;
4676                 StaEvent event = new StaEvent();
4677                 event.type = StaEvent.TYPE_WIFI_USABILITY_SCORE_BREACH;
4678                 addStaEvent(event);
4679                 // Only record the first score breach by checking whether mScoreBreachLowTimeMillis
4680                 // has been set to -1
4681                 if (!wifiWins && mScoreBreachLowTimeMillis == -1) {
4682                     mScoreBreachLowTimeMillis = mClock.getElapsedSinceBootMillis();
4683                 }
4684             }
4685         }
4686     }
4687 
4688     /**
4689      * Reports stats for a successful link probe.
4690      *
4691      * @param timeSinceLastTxSuccessMs At {@code startTimestampMs}, the number of milliseconds since
4692      *                                 the last Tx success (according to
4693      *                                 {@link WifiInfo#txSuccess}).
4694      * @param rssi The Rx RSSI at {@code startTimestampMs}.
4695      * @param linkSpeed The Tx link speed in Mbps at {@code startTimestampMs}.
4696      * @param elapsedTimeMs The number of milliseconds between when the command to transmit the
4697      *                      probe was sent to the driver and when the driver responded that the
4698      *                      probe was ACKed. Note: this number should be correlated with the number
4699      *                      of retries that the driver attempted before the probe was ACKed.
4700      */
4701     public void logLinkProbeSuccess(long timeSinceLastTxSuccessMs,
4702             int rssi, int linkSpeed, int elapsedTimeMs) {
4703         synchronized (mLock) {
4704             mProbeStatusSinceLastUpdate =
4705                     android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS;
4706             mProbeElapsedTimeSinceLastUpdateMs = elapsedTimeMs;
4707 
4708             mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram.increment(
4709                     (int) (timeSinceLastTxSuccessMs / 1000));
4710             mLinkProbeSuccessRssiCounts.increment(rssi);
4711             mLinkProbeSuccessLinkSpeedCounts.increment(linkSpeed);
4712             mLinkProbeSuccessElapsedTimeMsHistogram.increment(elapsedTimeMs);
4713 
4714             if (mLinkProbeStaEventCount < MAX_LINK_PROBE_STA_EVENTS) {
4715                 StaEvent event = new StaEvent();
4716                 event.type = StaEvent.TYPE_LINK_PROBE;
4717                 event.linkProbeWasSuccess = true;
4718                 event.linkProbeSuccessElapsedTimeMs = elapsedTimeMs;
4719                 addStaEvent(event);
4720             }
4721             mLinkProbeStaEventCount++;
4722         }
4723     }
4724 
4725     /**
4726      * Reports stats for an unsuccessful link probe.
4727      *
4728      * @param timeSinceLastTxSuccessMs At {@code startTimestampMs}, the number of milliseconds since
4729      *                                 the last Tx success (according to
4730      *                                 {@link WifiInfo#txSuccess}).
4731      * @param rssi The Rx RSSI at {@code startTimestampMs}.
4732      * @param linkSpeed The Tx link speed in Mbps at {@code startTimestampMs}.
4733      * @param reason The error code for the failure. See {@link WifiNative.SendMgmtFrameError}.
4734      */
4735     public void logLinkProbeFailure(long timeSinceLastTxSuccessMs,
4736             int rssi, int linkSpeed, @WifiNative.SendMgmtFrameError int reason) {
4737         synchronized (mLock) {
4738             mProbeStatusSinceLastUpdate =
4739                     android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE;
4740             mProbeElapsedTimeSinceLastUpdateMs = Integer.MAX_VALUE;
4741 
4742             mLinkProbeFailureSecondsSinceLastTxSuccessHistogram.increment(
4743                     (int) (timeSinceLastTxSuccessMs / 1000));
4744             mLinkProbeFailureRssiCounts.increment(rssi);
4745             mLinkProbeFailureLinkSpeedCounts.increment(linkSpeed);
4746             mLinkProbeFailureReasonCounts.increment(reason);
4747 
4748             if (mLinkProbeStaEventCount < MAX_LINK_PROBE_STA_EVENTS) {
4749                 StaEvent event = new StaEvent();
4750                 event.type = StaEvent.TYPE_LINK_PROBE;
4751                 event.linkProbeWasSuccess = false;
4752                 event.linkProbeFailureReason = linkProbeFailureReasonToProto(reason);
4753                 addStaEvent(event);
4754             }
4755             mLinkProbeStaEventCount++;
4756         }
4757     }
4758 
4759     /**
4760      * Increments the number of probes triggered by the experiment `experimentId`.
4761      */
4762     public void incrementLinkProbeExperimentProbeCount(String experimentId) {
4763         synchronized (mLock) {
4764             mLinkProbeExperimentProbeCounts.increment(experimentId);
4765         }
4766     }
4767 
4768     /**
4769      * Update wifi config store read duration.
4770      *
4771      * @param timeMs Time it took to complete the operation, in milliseconds
4772      */
4773     public void noteWifiConfigStoreReadDuration(int timeMs) {
4774         synchronized (mLock) {
4775             MetricsUtils.addValueToLinearHistogram(timeMs, mWifiConfigStoreReadDurationHistogram,
4776                     WIFI_CONFIG_STORE_IO_DURATION_BUCKET_RANGES_MS);
4777         }
4778     }
4779 
4780     /**
4781      * Update wifi config store write duration.
4782      *
4783      * @param timeMs Time it took to complete the operation, in milliseconds
4784      */
4785     public void noteWifiConfigStoreWriteDuration(int timeMs) {
4786         synchronized (mLock) {
4787             MetricsUtils.addValueToLinearHistogram(timeMs, mWifiConfigStoreWriteDurationHistogram,
4788                     WIFI_CONFIG_STORE_IO_DURATION_BUCKET_RANGES_MS);
4789         }
4790     }
4791 
4792     /**
4793      * Logs the decision of a network selection algorithm when compared against another network
4794      * selection algorithm.
4795      *
4796      * @param experiment1Id ID of one experiment
4797      * @param experiment2Id ID of the other experiment
4798      * @param isSameDecision did the 2 experiments make the same decision?
4799      * @param numNetworkChoices the number of non-null network choices there were, where the null
4800      *                          choice is not selecting any network
4801      */
4802     public void logNetworkSelectionDecision(int experiment1Id, int experiment2Id,
4803             boolean isSameDecision, int numNetworkChoices) {
4804         if (numNetworkChoices < 0) {
4805             Log.e(TAG, "numNetworkChoices cannot be negative!");
4806             return;
4807         }
4808         if (experiment1Id == experiment2Id) {
4809             Log.e(TAG, "comparing the same experiment id: " + experiment1Id);
4810             return;
4811         }
4812 
4813         Pair<Integer, Integer> key = new Pair<>(experiment1Id, experiment2Id);
4814         synchronized (mLock) {
4815             NetworkSelectionExperimentResults results =
4816                     mNetworkSelectionExperimentPairNumChoicesCounts
4817                             .computeIfAbsent(key, k -> new NetworkSelectionExperimentResults());
4818 
4819             IntCounter counter = isSameDecision
4820                     ? results.sameSelectionNumChoicesCounter
4821                     : results.differentSelectionNumChoicesCounter;
4822 
4823             counter.increment(numNetworkChoices);
4824         }
4825     }
4826 
4827     /** Increment number of network request API usage stats */
4828     public void incrementNetworkRequestApiNumRequest() {
4829         synchronized (mLock) {
4830             mWifiNetworkRequestApiLog.numRequest++;
4831         }
4832     }
4833 
4834     /** Add to the network request API match size histogram */
4835     public void incrementNetworkRequestApiMatchSizeHistogram(int matchSize) {
4836         synchronized (mLock) {
4837             mWifiNetworkRequestApiMatchSizeHistogram.increment(matchSize);
4838         }
4839     }
4840 
4841     /** Increment number of connection success via network request API */
4842     public void incrementNetworkRequestApiNumConnectSuccess() {
4843         synchronized (mLock) {
4844             mWifiNetworkRequestApiLog.numConnectSuccess++;
4845         }
4846     }
4847 
4848     /** Increment number of requests that bypassed user approval via network request API */
4849     public void incrementNetworkRequestApiNumUserApprovalBypass() {
4850         synchronized (mLock) {
4851             mWifiNetworkRequestApiLog.numUserApprovalBypass++;
4852         }
4853     }
4854 
4855     /** Increment number of requests that user rejected via network request API */
4856     public void incrementNetworkRequestApiNumUserReject() {
4857         synchronized (mLock) {
4858             mWifiNetworkRequestApiLog.numUserReject++;
4859         }
4860     }
4861 
4862     /** Increment number of requests from unique apps via network request API */
4863     public void incrementNetworkRequestApiNumApps() {
4864         synchronized (mLock) {
4865             mWifiNetworkRequestApiLog.numApps++;
4866         }
4867     }
4868 
4869     /** Increment number of network suggestion API modification by app stats */
4870     public void incrementNetworkSuggestionApiNumModification() {
4871         synchronized (mLock) {
4872             mWifiNetworkSuggestionApiLog.numModification++;
4873         }
4874     }
4875 
4876     /** Increment number of connection success via network suggestion API */
4877     public void incrementNetworkSuggestionApiNumConnectSuccess() {
4878         synchronized (mLock) {
4879             mWifiNetworkSuggestionApiLog.numConnectSuccess++;
4880         }
4881     }
4882 
4883     /** Increment number of connection failure via network suggestion API */
4884     public void incrementNetworkSuggestionApiNumConnectFailure() {
4885         synchronized (mLock) {
4886             mWifiNetworkSuggestionApiLog.numConnectFailure++;
4887         }
4888     }
4889 
4890     /** Clear and set the latest network suggestion API max list size histogram */
4891     public void noteNetworkSuggestionApiListSizeHistogram(List<Integer> listSizes) {
4892         synchronized (mLock) {
4893             mWifiNetworkSuggestionApiListSizeHistogram.clear();
4894             for (Integer listSize : listSizes) {
4895                 mWifiNetworkSuggestionApiListSizeHistogram.increment(listSize);
4896             }
4897         }
4898     }
4899 
4900     /**
4901      * Sets the nominator for a network (i.e. which entity made the suggestion to connect)
4902      * @param networkId the ID of the network, from its {@link WifiConfiguration}
4903      * @param nominatorId the entity that made the suggestion to connect to this network,
4904      *                    from {@link WifiMetricsProto.ConnectionEvent.ConnectionNominator}
4905      */
4906     public void setNominatorForNetwork(int networkId, int nominatorId) {
4907         synchronized (mLock) {
4908             if (networkId == WifiConfiguration.INVALID_NETWORK_ID) return;
4909             mNetworkIdToNominatorId.put(networkId, nominatorId);
4910         }
4911     }
4912 
4913     /**
4914      * Sets the numeric CandidateScorer id.
4915      */
4916     public void setNetworkSelectorExperimentId(int expId) {
4917         synchronized (mLock) {
4918             mNetworkSelectorExperimentId = expId;
4919         }
4920     }
4921 
4922     /** Add a WifiLock acqusition session */
4923     public void addWifiLockAcqSession(int lockType, long duration) {
4924         switch (lockType) {
4925             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
4926                 mWifiLockHighPerfAcqDurationSecHistogram.increment((int) (duration / 1000));
4927                 break;
4928 
4929             case WifiManager.WIFI_MODE_FULL_LOW_LATENCY:
4930                 mWifiLockLowLatencyAcqDurationSecHistogram.increment((int) (duration / 1000));
4931                 break;
4932 
4933             default:
4934                 Log.e(TAG, "addWifiLockAcqSession: Invalid lock type: " + lockType);
4935                 break;
4936         }
4937     }
4938 
4939     /** Add a WifiLock active session */
4940     public void addWifiLockActiveSession(int lockType, long duration) {
4941         switch (lockType) {
4942             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
4943                 mWifiLockStats.highPerfActiveTimeMs += duration;
4944                 mWifiLockHighPerfActiveSessionDurationSecHistogram.increment(
4945                         (int) (duration / 1000));
4946                 break;
4947 
4948             case WifiManager.WIFI_MODE_FULL_LOW_LATENCY:
4949                 mWifiLockStats.lowLatencyActiveTimeMs += duration;
4950                 mWifiLockLowLatencyActiveSessionDurationSecHistogram.increment(
4951                         (int) (duration / 1000));
4952                 break;
4953 
4954             default:
4955                 Log.e(TAG, "addWifiLockActiveSession: Invalid lock type: " + lockType);
4956                 break;
4957         }
4958     }
4959 
4960     /** Increments metrics counting number of addOrUpdateNetwork calls. **/
4961     public void incrementNumAddOrUpdateNetworkCalls() {
4962         synchronized (mLock) {
4963             mWifiLogProto.numAddOrUpdateNetworkCalls++;
4964         }
4965     }
4966 
4967     /** Increments metrics counting number of enableNetwork calls. **/
4968     public void incrementNumEnableNetworkCalls() {
4969         synchronized (mLock) {
4970             mWifiLogProto.numEnableNetworkCalls++;
4971         }
4972     }
4973 
4974     /** Add to WifiToggleStats **/
4975     public void incrementNumWifiToggles(boolean isPrivileged, boolean enable) {
4976         synchronized (mLock) {
4977             if (isPrivileged && enable) {
4978                 mWifiToggleStats.numToggleOnPrivileged++;
4979             } else if (isPrivileged && !enable) {
4980                 mWifiToggleStats.numToggleOffPrivileged++;
4981             } else if (!isPrivileged && enable) {
4982                 mWifiToggleStats.numToggleOnNormal++;
4983             } else {
4984                 mWifiToggleStats.numToggleOffNormal++;
4985             }
4986         }
4987     }
4988 
4989     /**
4990      * Increment number of passpoint provision failure
4991      * @param failureCode indicates error condition
4992      */
4993     public void incrementPasspointProvisionFailure(int failureCode) {
4994         int provisionFailureCode;
4995         synchronized (mLock) {
4996             switch (failureCode) {
4997                 case ProvisioningCallback.OSU_FAILURE_AP_CONNECTION:
4998                     provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_AP_CONNECTION;
4999                     break;
5000                 case ProvisioningCallback.OSU_FAILURE_SERVER_URL_INVALID:
5001                     provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_SERVER_URL_INVALID;
5002                     break;
5003                 case ProvisioningCallback.OSU_FAILURE_SERVER_CONNECTION:
5004                     provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_SERVER_CONNECTION;
5005                     break;
5006                 case ProvisioningCallback.OSU_FAILURE_SERVER_VALIDATION:
5007                     provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_SERVER_VALIDATION;
5008                     break;
5009                 case ProvisioningCallback.OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION:
5010                     provisionFailureCode = PasspointProvisionStats
5011                             .OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION;
5012                     break;
5013                 case ProvisioningCallback.OSU_FAILURE_PROVISIONING_ABORTED:
5014                     provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_PROVISIONING_ABORTED;
5015                     break;
5016                 case ProvisioningCallback.OSU_FAILURE_PROVISIONING_NOT_AVAILABLE:
5017                     provisionFailureCode = PasspointProvisionStats
5018                             .OSU_FAILURE_PROVISIONING_NOT_AVAILABLE;
5019                     break;
5020                 case ProvisioningCallback.OSU_FAILURE_INVALID_URL_FORMAT_FOR_OSU:
5021                     provisionFailureCode = PasspointProvisionStats
5022                             .OSU_FAILURE_INVALID_URL_FORMAT_FOR_OSU;
5023                     break;
5024                 case ProvisioningCallback.OSU_FAILURE_UNEXPECTED_COMMAND_TYPE:
5025                     provisionFailureCode = PasspointProvisionStats
5026                             .OSU_FAILURE_UNEXPECTED_COMMAND_TYPE;
5027                     break;
5028                 case ProvisioningCallback.OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE:
5029                     provisionFailureCode = PasspointProvisionStats
5030                             .OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE;
5031                     break;
5032                 case ProvisioningCallback.OSU_FAILURE_SOAP_MESSAGE_EXCHANGE:
5033                     provisionFailureCode = PasspointProvisionStats
5034                             .OSU_FAILURE_SOAP_MESSAGE_EXCHANGE;
5035                     break;
5036                 case ProvisioningCallback.OSU_FAILURE_START_REDIRECT_LISTENER:
5037                     provisionFailureCode = PasspointProvisionStats
5038                             .OSU_FAILURE_START_REDIRECT_LISTENER;
5039                     break;
5040                 case ProvisioningCallback.OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER:
5041                     provisionFailureCode = PasspointProvisionStats
5042                             .OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER;
5043                     break;
5044                 case ProvisioningCallback.OSU_FAILURE_NO_OSU_ACTIVITY_FOUND:
5045                     provisionFailureCode = PasspointProvisionStats
5046                             .OSU_FAILURE_NO_OSU_ACTIVITY_FOUND;
5047                     break;
5048                 case ProvisioningCallback.OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS:
5049                     provisionFailureCode = PasspointProvisionStats
5050                             .OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS;
5051                     break;
5052                 case ProvisioningCallback.OSU_FAILURE_NO_PPS_MO:
5053                     provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_NO_PPS_MO;
5054                     break;
5055                 case ProvisioningCallback.OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE:
5056                     provisionFailureCode = PasspointProvisionStats
5057                             .OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE;
5058                     break;
5059                 case ProvisioningCallback.OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE:
5060                     provisionFailureCode = PasspointProvisionStats
5061                             .OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE;
5062                     break;
5063                 case ProvisioningCallback.OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE:
5064                     provisionFailureCode = PasspointProvisionStats
5065                             .OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE;
5066                     break;
5067                 case ProvisioningCallback.OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES:
5068                     provisionFailureCode = PasspointProvisionStats
5069                             .OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES;
5070                     break;
5071                 case ProvisioningCallback.OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE:
5072                     provisionFailureCode = PasspointProvisionStats
5073                             .OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE;
5074                     break;
5075                 case ProvisioningCallback.OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION:
5076                     provisionFailureCode = PasspointProvisionStats
5077                             .OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION;
5078                     break;
5079                 case ProvisioningCallback.OSU_FAILURE_OSU_PROVIDER_NOT_FOUND:
5080                     provisionFailureCode = PasspointProvisionStats
5081                             .OSU_FAILURE_OSU_PROVIDER_NOT_FOUND;
5082                     break;
5083                 default:
5084                     provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_UNKNOWN;
5085             }
5086             mPasspointProvisionFailureCounts.increment(provisionFailureCode);
5087         }
5088     }
5089 
5090     /**
5091      * Increment number of passpoint provision success
5092      */
5093     public void incrementPasspointProvisionSuccess() {
5094         synchronized (mLock) {
5095             mNumProvisionSuccess++;
5096         }
5097     }
5098 }
5099