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