• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.net.wifi.WifiConfiguration.MeteredOverride;
20 
21 import static java.lang.StrictMath.toIntExact;
22 
23 import android.annotation.IntDef;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.app.ActivityManager;
27 import android.content.BroadcastReceiver;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.IntentFilter;
31 import android.content.pm.PackageManager;
32 import android.content.pm.ResolveInfo;
33 import android.net.wifi.EAPConstants;
34 import android.net.wifi.IOnWifiUsabilityStatsListener;
35 import android.net.wifi.ScanResult;
36 import android.net.wifi.SoftApCapability;
37 import android.net.wifi.SoftApConfiguration;
38 import android.net.wifi.SoftApInfo;
39 import android.net.wifi.SupplicantState;
40 import android.net.wifi.WifiConfiguration;
41 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
42 import android.net.wifi.WifiEnterpriseConfig;
43 import android.net.wifi.WifiInfo;
44 import android.net.wifi.WifiManager;
45 import android.net.wifi.WifiManager.DeviceMobilityState;
46 import android.net.wifi.WifiUsabilityStatsEntry.ProbeStatus;
47 import android.net.wifi.hotspot2.PasspointConfiguration;
48 import android.net.wifi.hotspot2.ProvisioningCallback;
49 import android.net.wifi.hotspot2.ProvisioningCallback.OsuFailure;
50 import android.net.wifi.nl80211.WifiNl80211Manager;
51 import android.net.wifi.util.ScanResultUtil;
52 import android.os.Handler;
53 import android.os.Looper;
54 import android.os.Message;
55 import android.os.PowerManager;
56 import android.os.RemoteCallbackList;
57 import android.os.RemoteException;
58 import android.os.SystemProperties;
59 import android.os.WorkSource;
60 import android.provider.Settings;
61 import android.telephony.TelephonyManager;
62 import android.text.TextUtils;
63 import android.util.ArrayMap;
64 import android.util.ArraySet;
65 import android.util.Base64;
66 import android.util.Log;
67 import android.util.Pair;
68 import android.util.SparseArray;
69 import android.util.SparseBooleanArray;
70 import android.util.SparseIntArray;
71 
72 import com.android.internal.annotations.VisibleForTesting;
73 import com.android.server.wifi.SupplicantStaIfaceHal.StaIfaceReasonCode;
74 import com.android.server.wifi.SupplicantStaIfaceHal.StaIfaceStatusCode;
75 import com.android.server.wifi.aware.WifiAwareMetrics;
76 import com.android.server.wifi.hotspot2.ANQPNetworkKey;
77 import com.android.server.wifi.hotspot2.NetworkDetail;
78 import com.android.server.wifi.hotspot2.PasspointManager;
79 import com.android.server.wifi.hotspot2.PasspointMatch;
80 import com.android.server.wifi.hotspot2.PasspointProvider;
81 import com.android.server.wifi.hotspot2.Utils;
82 import com.android.server.wifi.p2p.WifiP2pMetrics;
83 import com.android.server.wifi.proto.WifiStatsLog;
84 import com.android.server.wifi.proto.nano.WifiMetricsProto;
85 import com.android.server.wifi.proto.nano.WifiMetricsProto.ConnectToNetworkNotificationAndActionCount;
86 import com.android.server.wifi.proto.nano.WifiMetricsProto.ContentionTimeStats;
87 import com.android.server.wifi.proto.nano.WifiMetricsProto.DeviceMobilityStatePnoScanStats;
88 import com.android.server.wifi.proto.nano.WifiMetricsProto.ExperimentValues;
89 import com.android.server.wifi.proto.nano.WifiMetricsProto.FirstConnectAfterBootStats;
90 import com.android.server.wifi.proto.nano.WifiMetricsProto.FirstConnectAfterBootStats.Attempt;
91 import com.android.server.wifi.proto.nano.WifiMetricsProto.HealthMonitorMetrics;
92 import com.android.server.wifi.proto.nano.WifiMetricsProto.InitPartialScanStats;
93 import com.android.server.wifi.proto.nano.WifiMetricsProto.LinkProbeStats;
94 import com.android.server.wifi.proto.nano.WifiMetricsProto.LinkProbeStats.ExperimentProbeCounts;
95 import com.android.server.wifi.proto.nano.WifiMetricsProto.LinkProbeStats.LinkProbeFailureReasonCount;
96 import com.android.server.wifi.proto.nano.WifiMetricsProto.LinkSpeedCount;
97 import com.android.server.wifi.proto.nano.WifiMetricsProto.MeteredNetworkStats;
98 import com.android.server.wifi.proto.nano.WifiMetricsProto.NetworkDisableReason;
99 import com.android.server.wifi.proto.nano.WifiMetricsProto.NetworkSelectionExperimentDecisions;
100 import com.android.server.wifi.proto.nano.WifiMetricsProto.PasspointProfileTypeCount;
101 import com.android.server.wifi.proto.nano.WifiMetricsProto.PasspointProvisionStats;
102 import com.android.server.wifi.proto.nano.WifiMetricsProto.PasspointProvisionStats.ProvisionFailureCount;
103 import com.android.server.wifi.proto.nano.WifiMetricsProto.PnoScanMetrics;
104 import com.android.server.wifi.proto.nano.WifiMetricsProto.RadioStats;
105 import com.android.server.wifi.proto.nano.WifiMetricsProto.RateStats;
106 import com.android.server.wifi.proto.nano.WifiMetricsProto.SoftApConnectedClientsEvent;
107 import com.android.server.wifi.proto.nano.WifiMetricsProto.StaEvent;
108 import com.android.server.wifi.proto.nano.WifiMetricsProto.StaEvent.ConfigInfo;
109 import com.android.server.wifi.proto.nano.WifiMetricsProto.TargetNetworkInfo;
110 import com.android.server.wifi.proto.nano.WifiMetricsProto.UserActionEvent;
111 import com.android.server.wifi.proto.nano.WifiMetricsProto.UserReactionToApprovalUiEvent;
112 import com.android.server.wifi.proto.nano.WifiMetricsProto.UserReactionToApprovalUiEvent.UserReaction;
113 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiIsUnusableEvent;
114 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiLinkLayerUsageStats;
115 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiLockStats;
116 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiNetworkRequestApiLog;
117 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiNetworkSuggestionApiLog;
118 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiNetworkSuggestionApiLog.SuggestionAppCount;
119 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiStatus;
120 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiToWifiSwitchStats;
121 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiToggleStats;
122 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStats;
123 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStatsEntry;
124 import com.android.server.wifi.rtt.RttMetrics;
125 import com.android.server.wifi.scanner.KnownBandsChannelHelper;
126 import com.android.server.wifi.util.InformationElementUtil;
127 import com.android.server.wifi.util.IntCounter;
128 import com.android.server.wifi.util.IntHistogram;
129 import com.android.server.wifi.util.MetricsUtils;
130 import com.android.server.wifi.util.ObjectCounter;
131 import com.android.wifi.resources.R;
132 
133 import org.json.JSONArray;
134 import org.json.JSONException;
135 import org.json.JSONObject;
136 
137 import java.io.FileDescriptor;
138 import java.io.PrintWriter;
139 import java.time.Duration;
140 import java.util.ArrayDeque;
141 import java.util.ArrayList;
142 import java.util.Arrays;
143 import java.util.BitSet;
144 import java.util.Calendar;
145 import java.util.Deque;
146 import java.util.HashMap;
147 import java.util.HashSet;
148 import java.util.LinkedList;
149 import java.util.List;
150 import java.util.Map;
151 import java.util.Random;
152 import java.util.Set;
153 
154 /**
155  * Provides storage for wireless connectivity metrics, as they are generated.
156  * Metrics logged by this class include:
157  *   Aggregated connection stats (num of connections, num of failures, ...)
158  *   Discrete connection event stats (time, duration, failure codes, ...)
159  *   Router details (technology type, authentication type, ...)
160  *   Scan stats
161  */
162 public class WifiMetrics {
163     private static final String TAG = "WifiMetrics";
164     private static final boolean DBG = false;
165 
166     /**
167      * Clamp the RSSI poll counts to values between [MIN,MAX]_RSSI_POLL
168      */
169     private static final int MAX_RSSI_POLL = 0;
170     private static final int MIN_RSSI_POLL = -127;
171     public static final int MAX_RSSI_DELTA = 127;
172     public static final int MIN_RSSI_DELTA = -127;
173     /** Minimum link speed (Mbps) to count for link_speed_counts */
174     public static final int MIN_LINK_SPEED_MBPS = 0;
175     /** Maximum time period between ScanResult and RSSI poll to generate rssi delta datapoint */
176     public static final long TIMEOUT_RSSI_DELTA_MILLIS =  3000;
177     private static final int MIN_WIFI_SCORE = 0;
178     private static final int MAX_WIFI_SCORE = ConnectedScore.WIFI_MAX_SCORE;
179     private static final int MIN_WIFI_USABILITY_SCORE = 0; // inclusive
180     private static final int MAX_WIFI_USABILITY_SCORE = 100; // inclusive
181     @VisibleForTesting
182     static final int LOW_WIFI_SCORE = 50; // Mobile data score
183     @VisibleForTesting
184     static final int LOW_WIFI_USABILITY_SCORE = 50; // Mobile data score
185     private final Object mLock = new Object();
186     private static final int MAX_CONNECTION_EVENTS = 256;
187     // Largest bucket in the NumConnectableNetworkCount histogram,
188     // anything large will be stored in this bucket
189     public static final int MAX_CONNECTABLE_SSID_NETWORK_BUCKET = 20;
190     public static final int MAX_CONNECTABLE_BSSID_NETWORK_BUCKET = 50;
191     public static final int MAX_TOTAL_SCAN_RESULT_SSIDS_BUCKET = 100;
192     public static final int MAX_TOTAL_SCAN_RESULTS_BUCKET = 250;
193     public static final int MAX_TOTAL_PASSPOINT_APS_BUCKET = 50;
194     public static final int MAX_TOTAL_PASSPOINT_UNIQUE_ESS_BUCKET = 20;
195     public static final int MAX_PASSPOINT_APS_PER_UNIQUE_ESS_BUCKET = 50;
196     public static final int MAX_TOTAL_80211MC_APS_BUCKET = 20;
197     private static final int CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER = 1000;
198     // Max limit for number of soft AP related events, extra events will be dropped.
199     private static final int MAX_NUM_SOFT_AP_EVENTS = 256;
200     // Maximum number of WifiIsUnusableEvent
201     public static final int MAX_UNUSABLE_EVENTS = 20;
202     // Minimum time wait before generating next WifiIsUnusableEvent from data stall
203     public static final int MIN_DATA_STALL_WAIT_MS = 120 * 1000; // 2 minutes
204     // Max number of WifiUsabilityStatsEntry elements to store in the ringbuffer.
205     public static final int MAX_WIFI_USABILITY_STATS_ENTRIES_LIST_SIZE = 40;
206     // Max number of WifiUsabilityStats elements to store for each type.
207     public static final int MAX_WIFI_USABILITY_STATS_LIST_SIZE_PER_TYPE = 10;
208     // Max number of WifiUsabilityStats per labeled type to upload to server
209     public static final int MAX_WIFI_USABILITY_STATS_PER_TYPE_TO_UPLOAD = 2;
210     public static final int NUM_WIFI_USABILITY_STATS_ENTRIES_PER_WIFI_GOOD = 100;
211     public static final int MIN_WIFI_GOOD_USABILITY_STATS_PERIOD_MS = 1000 * 3600; // 1 hour
212     public static final int PASSPOINT_DEAUTH_IMMINENT_SCOPE_ESS = 0;
213     public static final int PASSPOINT_DEAUTH_IMMINENT_SCOPE_BSS = 1;
214     public static final int COUNTRY_CODE_CONFLICT_WIFI_SCAN = -1;
215     public static final int COUNTRY_CODE_CONFLICT_WIFI_SCAN_TELEPHONY = -2;
216     public static final int MAX_COUNTRY_CODE_COUNT = 4;
217     // Histogram for WifiConfigStore IO duration times. Indicates the following 5 buckets (in ms):
218     //   < 50
219     //   [50, 100)
220     //   [100, 150)
221     //   [150, 200)
222     //   [200, 300)
223     //   >= 300
224     private static final int[] WIFI_CONFIG_STORE_IO_DURATION_BUCKET_RANGES_MS =
225             {50, 100, 150, 200, 300};
226     // Minimum time wait before generating a LABEL_GOOD stats after score breaching low.
227     public static final int MIN_SCORE_BREACH_TO_GOOD_STATS_WAIT_TIME_MS = 60 * 1000; // 1 minute
228     // Maximum time that a score breaching low event stays valid.
229     public static final int VALIDITY_PERIOD_OF_SCORE_BREACH_LOW_MS = 90 * 1000; // 1.5 minutes
230 
231     private static final int WIFI_RECONNECT_DURATION_SHORT_MILLIS = 10 * 1000;
232     private static final int WIFI_RECONNECT_DURATION_MEDIUM_MILLIS = 60 * 1000;
233     // Number of WME Access Categories
234     private static final int NUM_WME_ACCESS_CATEGORIES = 4;
235     private static final int MBB_LINGERING_DURATION_MAX_SECONDS = 30;
236 
237     private Clock mClock;
238     private boolean mScreenOn;
239     private int mWifiState;
240     private WifiAwareMetrics mWifiAwareMetrics;
241     private RttMetrics mRttMetrics;
242     private final PnoScanMetrics mPnoScanMetrics = new PnoScanMetrics();
243     private final WifiLinkLayerUsageStats mWifiLinkLayerUsageStats = new WifiLinkLayerUsageStats();
244     private final TelephonyManager mTelephonyManager;
245     /** Mapping of radio id values to RadioStats objects. */
246     private final SparseArray<RadioStats> mRadioStats = new SparseArray<>();
247     private final ExperimentValues mExperimentValues = new ExperimentValues();
248     private Handler mHandler;
249     private ScoringParams mScoringParams;
250     private WifiConfigManager mWifiConfigManager;
251     private WifiBlocklistMonitor mWifiBlocklistMonitor;
252     private WifiNetworkSelector mWifiNetworkSelector;
253     private PasspointManager mPasspointManager;
254     private Context mContext;
255     private FrameworkFacade mFacade;
256     private WifiDataStall mWifiDataStall;
257     private WifiLinkLayerStats mLastLinkLayerStats;
258     private WifiHealthMonitor mWifiHealthMonitor;
259     private WifiScoreCard mWifiScoreCard;
260     private SessionData mPreviousSession;
261     private SessionData mCurrentSession;
262     private String mLastBssid;
263     private int mLastFrequency = -1;
264     private int mSeqNumInsideFramework = 0;
265     private int mLastWifiUsabilityScore = -1;
266     private int mLastWifiUsabilityScoreNoReset = -1;
267     private int mLastPredictionHorizonSec = -1;
268     private int mLastPredictionHorizonSecNoReset = -1;
269     private int mSeqNumToFramework = -1;
270     @ProbeStatus private int mProbeStatusSinceLastUpdate =
271             android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE;
272     private int mProbeElapsedTimeSinceLastUpdateMs = -1;
273     private int mProbeMcsRateSinceLastUpdate = -1;
274     private long mScoreBreachLowTimeMillis = -1;
275 
276     public static final int MAX_STA_EVENTS = 768;
277     @VisibleForTesting static final int MAX_USER_ACTION_EVENTS = 200;
278     private LinkedList<StaEventWithTime> mStaEventList = new LinkedList<>();
279     private LinkedList<UserActionEventWithTime> mUserActionEventList = new LinkedList<>();
280     private WifiStatusBuilder mWifiStatusBuilder = new WifiStatusBuilder();
281     private int mLastPollRssi = -127;
282     private int mLastPollLinkSpeed = -1;
283     private int mLastPollRxLinkSpeed = -1;
284     private int mLastPollFreq = -1;
285     private int mLastScore = -1;
286     private boolean mAdaptiveConnectivityEnabled = true;
287     private ScanMetrics mScanMetrics;
288     private WifiChannelUtilization mWifiChannelUtilization;
289     private WifiSettingsStore mWifiSettingsStore;
290     private IntCounter mPasspointDeauthImminentScope = new IntCounter();
291     private IntCounter mRecentFailureAssociationStatus = new IntCounter();
292     private boolean mFirstConnectionAfterBoot = true;
293 
294     /**
295      * Metrics are stored within an instance of the WifiLog proto during runtime,
296      * The ConnectionEvent, SystemStateEntries & ScanReturnEntries metrics are stored during
297      * runtime in member lists of this WifiMetrics class, with the final WifiLog proto being pieced
298      * together at dump-time
299      */
300     private final WifiMetricsProto.WifiLog mWifiLogProto = new WifiMetricsProto.WifiLog();
301     /**
302      * Session information that gets logged for every Wifi connection attempt.
303      */
304     private final Deque<ConnectionEvent> mConnectionEventList = new ArrayDeque<>();
305     /**
306      * The latest started (but un-ended) connection attempt per interface.
307      */
308     private final Map<String, ConnectionEvent> mCurrentConnectionEventPerIface = new ArrayMap<>();
309     /**
310      * Count of number of times each scan return code, indexed by WifiLog.ScanReturnCode
311      */
312     private final SparseIntArray mScanReturnEntries = new SparseIntArray();
313     /**
314      * Mapping of system state to the counts of scans requested in that wifi state * screenOn
315      * combination. Indexed by WifiLog.WifiState * (1 + screenOn)
316      */
317     private final SparseIntArray mWifiSystemStateEntries = new SparseIntArray();
318     /** Mapping of channel frequency to its RSSI distribution histogram **/
319     private final Map<Integer, SparseIntArray> mRssiPollCountsMap = new HashMap<>();
320     /** Mapping of RSSI scan-poll delta values to counts. */
321     private final SparseIntArray mRssiDeltaCounts = new SparseIntArray();
322     /** Mapping of link speed values to LinkSpeedCount objects. */
323     private final SparseArray<LinkSpeedCount> mLinkSpeedCounts = new SparseArray<>();
324 
325     private final IntCounter mTxLinkSpeedCount2g = new IntCounter();
326     private final IntCounter mTxLinkSpeedCount5gLow = new IntCounter();
327     private final IntCounter mTxLinkSpeedCount5gMid = new IntCounter();
328     private final IntCounter mTxLinkSpeedCount5gHigh = new IntCounter();
329     private final IntCounter mTxLinkSpeedCount6gLow = new IntCounter();
330     private final IntCounter mTxLinkSpeedCount6gMid = new IntCounter();
331     private final IntCounter mTxLinkSpeedCount6gHigh = new IntCounter();
332 
333     private final IntCounter mRxLinkSpeedCount2g = new IntCounter();
334     private final IntCounter mRxLinkSpeedCount5gLow = new IntCounter();
335     private final IntCounter mRxLinkSpeedCount5gMid = new IntCounter();
336     private final IntCounter mRxLinkSpeedCount5gHigh = new IntCounter();
337     private final IntCounter mRxLinkSpeedCount6gLow = new IntCounter();
338     private final IntCounter mRxLinkSpeedCount6gMid = new IntCounter();
339     private final IntCounter mRxLinkSpeedCount6gHigh = new IntCounter();
340 
341     private final IntCounter mMakeBeforeBreakLingeringDurationSeconds = new IntCounter();
342 
343     /** RSSI of the scan result for the last connection event*/
344     private int mScanResultRssi = 0;
345     /** Boot-relative timestamp when the last candidate scanresult was received, used to calculate
346         RSSI deltas. -1 designates no candidate scanResult being tracked */
347     private long mScanResultRssiTimestampMillis = -1;
348     /** Mapping of alert reason to the respective alert count. */
349     private final SparseIntArray mWifiAlertReasonCounts = new SparseIntArray();
350     /**
351      * Records the getElapsedSinceBootMillis (in seconds) that represents the beginning of data
352      * capture for for this WifiMetricsProto
353      */
354     private long mRecordStartTimeSec;
355     /** Mapping of Wifi Scores to counts */
356     private final SparseIntArray mWifiScoreCounts = new SparseIntArray();
357     /** Mapping of Wifi Usability Scores to counts */
358     private final SparseIntArray mWifiUsabilityScoreCounts = new SparseIntArray();
359     /** Mapping of SoftApManager start SoftAp return codes to counts */
360     private final SparseIntArray mSoftApManagerReturnCodeCounts = new SparseIntArray();
361 
362     private final SparseIntArray mTotalSsidsInScanHistogram = new SparseIntArray();
363     private final SparseIntArray mTotalBssidsInScanHistogram = new SparseIntArray();
364     private final SparseIntArray mAvailableOpenSsidsInScanHistogram = new SparseIntArray();
365     private final SparseIntArray mAvailableOpenBssidsInScanHistogram = new SparseIntArray();
366     private final SparseIntArray mAvailableSavedSsidsInScanHistogram = new SparseIntArray();
367     private final SparseIntArray mAvailableSavedBssidsInScanHistogram = new SparseIntArray();
368     private final SparseIntArray mAvailableOpenOrSavedSsidsInScanHistogram = new SparseIntArray();
369     private final SparseIntArray mAvailableOpenOrSavedBssidsInScanHistogram = new SparseIntArray();
370     private final SparseIntArray mAvailableSavedPasspointProviderProfilesInScanHistogram =
371             new SparseIntArray();
372     private final SparseIntArray mAvailableSavedPasspointProviderBssidsInScanHistogram =
373             new SparseIntArray();
374 
375     private final IntCounter mInstalledPasspointProfileTypeForR1 = new IntCounter();
376     private final IntCounter mInstalledPasspointProfileTypeForR2 = new IntCounter();
377 
378     /** Mapping of "Connect to Network" notifications to counts. */
379     private final SparseIntArray mConnectToNetworkNotificationCount = new SparseIntArray();
380     /** Mapping of "Connect to Network" notification user actions to counts. */
381     private final SparseIntArray mConnectToNetworkNotificationActionCount = new SparseIntArray();
382     private int mOpenNetworkRecommenderBlocklistSize = 0;
383     private boolean mIsWifiNetworksAvailableNotificationOn = false;
384     private int mNumOpenNetworkConnectMessageFailedToSend = 0;
385     private int mNumOpenNetworkRecommendationUpdates = 0;
386     /** List of soft AP events related to number of connected clients in tethered mode */
387     private final List<SoftApConnectedClientsEvent> mSoftApEventListTethered = new ArrayList<>();
388     /** List of soft AP events related to number of connected clients in local only mode */
389     private final List<SoftApConnectedClientsEvent> mSoftApEventListLocalOnly = new ArrayList<>();
390 
391     private final SparseIntArray mObservedHotspotR1ApInScanHistogram = new SparseIntArray();
392     private final SparseIntArray mObservedHotspotR2ApInScanHistogram = new SparseIntArray();
393     private final SparseIntArray mObservedHotspotR3ApInScanHistogram = new SparseIntArray();
394     private final SparseIntArray mObservedHotspotR1EssInScanHistogram = new SparseIntArray();
395     private final SparseIntArray mObservedHotspotR2EssInScanHistogram = new SparseIntArray();
396     private final SparseIntArray mObservedHotspotR3EssInScanHistogram = new SparseIntArray();
397     private final SparseIntArray mObservedHotspotR1ApsPerEssInScanHistogram = new SparseIntArray();
398     private final SparseIntArray mObservedHotspotR2ApsPerEssInScanHistogram = new SparseIntArray();
399     private final SparseIntArray mObservedHotspotR3ApsPerEssInScanHistogram = new SparseIntArray();
400 
401     private final SparseIntArray mObserved80211mcApInScanHistogram = new SparseIntArray();
402     private final IntCounter mCountryCodeScanHistogram = new IntCounter();
403 
404     // link probing stats
405     private final IntCounter mLinkProbeSuccessRssiCounts = new IntCounter(-85, -65);
406     private final IntCounter mLinkProbeFailureRssiCounts = new IntCounter(-85, -65);
407     private final IntCounter mLinkProbeSuccessLinkSpeedCounts = new IntCounter();
408     private final IntCounter mLinkProbeFailureLinkSpeedCounts = new IntCounter();
409 
410     private static final int[] LINK_PROBE_TIME_SINCE_LAST_TX_SUCCESS_SECONDS_HISTOGRAM_BUCKETS =
411             {5, 15, 45, 135};
412     private final IntHistogram mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram =
413             new IntHistogram(LINK_PROBE_TIME_SINCE_LAST_TX_SUCCESS_SECONDS_HISTOGRAM_BUCKETS);
414     private final IntHistogram mLinkProbeFailureSecondsSinceLastTxSuccessHistogram =
415             new IntHistogram(LINK_PROBE_TIME_SINCE_LAST_TX_SUCCESS_SECONDS_HISTOGRAM_BUCKETS);
416 
417     private static final int[] LINK_PROBE_ELAPSED_TIME_MS_HISTOGRAM_BUCKETS =
418             {5, 10, 15, 20, 25, 50, 100, 200, 400, 800};
419     private final IntHistogram mLinkProbeSuccessElapsedTimeMsHistogram = new IntHistogram(
420             LINK_PROBE_ELAPSED_TIME_MS_HISTOGRAM_BUCKETS);
421     private final IntCounter mLinkProbeFailureReasonCounts = new IntCounter();
422     private final MeteredNetworkStatsBuilder mMeteredNetworkStatsBuilder =
423             new MeteredNetworkStatsBuilder();
424 
425     /**
426      * Maps a String link probe experiment ID to the number of link probes that were sent for this
427      * experiment.
428      */
429     private final ObjectCounter<String> mLinkProbeExperimentProbeCounts = new ObjectCounter<>();
430     private int mLinkProbeStaEventCount = 0;
431     @VisibleForTesting static final int MAX_LINK_PROBE_STA_EVENTS = MAX_STA_EVENTS / 4;
432 
433     private final LinkedList<WifiUsabilityStatsEntry> mWifiUsabilityStatsEntriesList =
434             new LinkedList<>();
435     private final LinkedList<WifiUsabilityStats> mWifiUsabilityStatsListBad = new LinkedList<>();
436     private final LinkedList<WifiUsabilityStats> mWifiUsabilityStatsListGood = new LinkedList<>();
437     private int mWifiUsabilityStatsCounter = 0;
438     private final Random mRand = new Random();
439     private final RemoteCallbackList<IOnWifiUsabilityStatsListener> mOnWifiUsabilityListeners;
440 
441     private final SparseArray<DeviceMobilityStatePnoScanStats> mMobilityStatePnoStatsMap =
442             new SparseArray<>();
443     private int mCurrentDeviceMobilityState;
444     /**
445      * The timestamp of the start of the current device mobility state.
446      */
447     private long mCurrentDeviceMobilityStateStartMs;
448     /**
449      * The timestamp of when the PNO scan started in the current device mobility state.
450      */
451     private long mCurrentDeviceMobilityStatePnoScanStartMs;
452 
453     /** Wifi power metrics*/
454     private WifiPowerMetrics mWifiPowerMetrics;
455 
456     /** Wifi Wake metrics */
457     private final WifiWakeMetrics mWifiWakeMetrics = new WifiWakeMetrics();
458 
459     /** Wifi P2p metrics */
460     private final WifiP2pMetrics mWifiP2pMetrics;
461 
462     /** DPP */
463     private final DppMetrics mDppMetrics;
464 
465     private final WifiMonitor mWifiMonitor;
466     private ActiveModeWarden mActiveModeWarden;
467     private final Map<String, ActiveModeManager.ClientRole> mIfaceToRoleMap = new ArrayMap<>();
468 
469     /** WifiConfigStore read duration histogram. */
470     private SparseIntArray mWifiConfigStoreReadDurationHistogram = new SparseIntArray();
471 
472     /** WifiConfigStore write duration histogram. */
473     private SparseIntArray mWifiConfigStoreWriteDurationHistogram = new SparseIntArray();
474 
475     /** New  API surface metrics */
476     private final WifiNetworkRequestApiLog mWifiNetworkRequestApiLog =
477             new WifiNetworkRequestApiLog();
478     private static final int[] NETWORK_REQUEST_API_MATCH_SIZE_HISTOGRAM_BUCKETS =
479             {0, 1, 5, 10};
480     private final IntHistogram mWifiNetworkRequestApiMatchSizeHistogram =
481             new IntHistogram(NETWORK_REQUEST_API_MATCH_SIZE_HISTOGRAM_BUCKETS);
482 
483     private static final int[] NETWORK_REQUEST_API_DURATION_SEC_BUCKETS =
484             {0, toIntExact(Duration.ofMinutes(3).getSeconds()),
485                     toIntExact(Duration.ofMinutes(10).getSeconds()),
486                     toIntExact(Duration.ofMinutes(30).getSeconds()),
487                     toIntExact(Duration.ofHours(1).getSeconds()),
488                     toIntExact(Duration.ofHours(6).getSeconds())};
489     private final IntHistogram mWifiNetworkRequestApiConnectionDurationSecOnPrimaryIfaceHistogram =
490             new IntHistogram(NETWORK_REQUEST_API_DURATION_SEC_BUCKETS);
491     private final IntHistogram
492             mWifiNetworkRequestApiConnectionDurationSecOnSecondaryIfaceHistogram =
493             new IntHistogram(NETWORK_REQUEST_API_DURATION_SEC_BUCKETS);
494     private final IntHistogram mWifiNetworkRequestApiConcurrentConnectionDurationSecHistogram =
495             new IntHistogram(NETWORK_REQUEST_API_DURATION_SEC_BUCKETS);
496 
497     private final WifiNetworkSuggestionApiLog mWifiNetworkSuggestionApiLog =
498             new WifiNetworkSuggestionApiLog();
499     private static final int[] NETWORK_SUGGESTION_API_LIST_SIZE_HISTOGRAM_BUCKETS =
500             {5, 20, 50, 100, 500};
501     private final IntHistogram mWifiNetworkSuggestionApiListSizeHistogram =
502             new IntHistogram(NETWORK_SUGGESTION_API_LIST_SIZE_HISTOGRAM_BUCKETS);
503     private final IntCounter mWifiNetworkSuggestionApiAppTypeCounter = new IntCounter();
504     private final List<UserReaction> mUserApprovalSuggestionAppUiReactionList =
505             new ArrayList<>();
506     private final List<UserReaction> mUserApprovalCarrierUiReactionList =
507             new ArrayList<>();
508     private final SparseBooleanArray mWifiNetworkSuggestionPriorityGroups =
509             new SparseBooleanArray();
510     private final Set<String> mWifiNetworkSuggestionCoexistSavedNetworks = new ArraySet<>();
511 
512     private final WifiLockStats mWifiLockStats = new WifiLockStats();
513     private static final int[] WIFI_LOCK_SESSION_DURATION_HISTOGRAM_BUCKETS =
514             {1, 10, 60, 600, 3600};
515     private final WifiToggleStats mWifiToggleStats = new WifiToggleStats();
516     private BssidBlocklistStats mBssidBlocklistStats = new BssidBlocklistStats();
517 
518     private final IntHistogram mWifiLockHighPerfAcqDurationSecHistogram =
519             new IntHistogram(WIFI_LOCK_SESSION_DURATION_HISTOGRAM_BUCKETS);
520     private final IntHistogram mWifiLockLowLatencyAcqDurationSecHistogram =
521             new IntHistogram(WIFI_LOCK_SESSION_DURATION_HISTOGRAM_BUCKETS);
522 
523     private final IntHistogram mWifiLockHighPerfActiveSessionDurationSecHistogram =
524             new IntHistogram(WIFI_LOCK_SESSION_DURATION_HISTOGRAM_BUCKETS);
525     private final IntHistogram mWifiLockLowLatencyActiveSessionDurationSecHistogram =
526             new IntHistogram(WIFI_LOCK_SESSION_DURATION_HISTOGRAM_BUCKETS);
527 
528     /**
529      * (experiment1Id, experiment2Id) =>
530      *     (sameSelectionNumChoicesCounter, differentSelectionNumChoicesCounter)
531      */
532     private Map<Pair<Integer, Integer>, NetworkSelectionExperimentResults>
533             mNetworkSelectionExperimentPairNumChoicesCounts = new ArrayMap<>();
534 
535     private int mNetworkSelectorExperimentId;
536 
537     /**
538      * Tracks the nominator for each network (i.e. which entity made the suggestion to connect).
539      * This object should not be cleared.
540      */
541     private final SparseIntArray mNetworkIdToNominatorId = new SparseIntArray();
542 
543     /** passpoint provision success count */
544     private int mNumProvisionSuccess = 0;
545 
546     /** Mapping of failure code to the respective passpoint provision failure count. */
547     private final IntCounter mPasspointProvisionFailureCounts = new IntCounter();
548 
549     // Connection duration stats collected while link layer stats reports are on
550     private final ConnectionDurationStats mConnectionDurationStats = new ConnectionDurationStats();
551 
552     private static final int[] CHANNEL_UTILIZATION_BUCKETS =
553             {25, 50, 75, 100, 125, 150, 175, 200, 225};
554 
555     private final IntHistogram mChannelUtilizationHistogram2G =
556             new IntHistogram(CHANNEL_UTILIZATION_BUCKETS);
557 
558     private final IntHistogram mChannelUtilizationHistogramAbove2G =
559             new IntHistogram(CHANNEL_UTILIZATION_BUCKETS);
560 
561     private static final int[] THROUGHPUT_MBPS_BUCKETS =
562             {1, 5, 10, 15, 25, 50, 100, 150, 200, 300, 450, 600, 800, 1200, 1600};
563     private final IntHistogram mTxThroughputMbpsHistogram2G =
564             new IntHistogram(THROUGHPUT_MBPS_BUCKETS);
565     private final IntHistogram mRxThroughputMbpsHistogram2G =
566             new IntHistogram(THROUGHPUT_MBPS_BUCKETS);
567     private final IntHistogram mTxThroughputMbpsHistogramAbove2G =
568             new IntHistogram(THROUGHPUT_MBPS_BUCKETS);
569     private final IntHistogram mRxThroughputMbpsHistogramAbove2G =
570             new IntHistogram(THROUGHPUT_MBPS_BUCKETS);
571 
572     // Init partial scan metrics
573     private int mInitPartialScanTotalCount;
574     private int mInitPartialScanSuccessCount;
575     private int mInitPartialScanFailureCount;
576     private static final int[] INIT_PARTIAL_SCAN_HISTOGRAM_BUCKETS =
577             {1, 3, 5, 10};
578     private final IntHistogram mInitPartialScanSuccessHistogram =
579             new IntHistogram(INIT_PARTIAL_SCAN_HISTOGRAM_BUCKETS);
580     private final IntHistogram mInitPartialScanFailureHistogram =
581             new IntHistogram(INIT_PARTIAL_SCAN_HISTOGRAM_BUCKETS);
582 
583     // Wi-Fi off metrics
584     private final WifiOffMetrics mWifiOffMetrics = new WifiOffMetrics();
585 
586     private final SoftApConfigLimitationMetrics mSoftApConfigLimitationMetrics =
587             new SoftApConfigLimitationMetrics();
588 
589     private final CarrierWifiMetrics mCarrierWifiMetrics =
590             new CarrierWifiMetrics();
591 
592     @Nullable
593     private FirstConnectAfterBootStats mFirstConnectAfterBootStats =
594             new FirstConnectAfterBootStats();
595     private boolean mIsFirstConnectionAttemptComplete = false;
596 
597     private final WifiToWifiSwitchStats mWifiToWifiSwitchStats = new WifiToWifiSwitchStats();
598 
599     @VisibleForTesting
600     static class NetworkSelectionExperimentResults {
601         public static final int MAX_CHOICES = 10;
602 
603         public IntCounter sameSelectionNumChoicesCounter = new IntCounter(0, MAX_CHOICES);
604         public IntCounter differentSelectionNumChoicesCounter = new IntCounter(0, MAX_CHOICES);
605 
606         @Override
toString()607         public String toString() {
608             return "NetworkSelectionExperimentResults{"
609                     + "sameSelectionNumChoicesCounter="
610                     + sameSelectionNumChoicesCounter
611                     + ", differentSelectionNumChoicesCounter="
612                     + differentSelectionNumChoicesCounter
613                     + '}';
614         }
615     }
616 
617     private static class SessionData {
618         private String mSsid;
619         private long mSessionStartTimeMillis;
620         private long mSessionEndTimeMillis;
621         private int mBand;
622         private int mAuthType;
623 
SessionData(String ssid, long sessionStartTimeMillis, int band, int authType)624         SessionData(String ssid, long sessionStartTimeMillis, int band, int authType) {
625             mSsid = ssid;
626             mSessionStartTimeMillis = sessionStartTimeMillis;
627             mBand = band;
628             mAuthType = authType;
629         }
630     }
631 
632     class RouterFingerPrint {
633         private final WifiMetricsProto.RouterFingerPrint mRouterFingerPrintProto =
634                 new WifiMetricsProto.RouterFingerPrint();
635 
toString()636         public String toString() {
637             StringBuilder sb = new StringBuilder();
638             synchronized (mLock) {
639                 sb.append("mConnectionEvent.roamType=" + mRouterFingerPrintProto.roamType);
640                 sb.append(", mChannelInfo=" + mRouterFingerPrintProto.channelInfo);
641                 sb.append(", mDtim=" + mRouterFingerPrintProto.dtim);
642                 sb.append(", mAuthentication=" + mRouterFingerPrintProto.authentication);
643                 sb.append(", mHidden=" + mRouterFingerPrintProto.hidden);
644                 sb.append(", mRouterTechnology=" + mRouterFingerPrintProto.routerTechnology);
645                 sb.append(", mSupportsIpv6=" + mRouterFingerPrintProto.supportsIpv6);
646                 sb.append(", mEapMethod=" + mRouterFingerPrintProto.eapMethod);
647                 sb.append(", mAuthPhase2Method=" + mRouterFingerPrintProto.authPhase2Method);
648                 sb.append(", mOcspType=" + mRouterFingerPrintProto.ocspType);
649                 sb.append(", mPmkCache=" + mRouterFingerPrintProto.pmkCacheEnabled);
650                 sb.append(", mMaxSupportedTxLinkSpeedMbps=" + mRouterFingerPrintProto
651                         .maxSupportedTxLinkSpeedMbps);
652                 sb.append(", mMaxSupportedRxLinkSpeedMbps=" + mRouterFingerPrintProto
653                         .maxSupportedRxLinkSpeedMbps);
654             }
655             return sb.toString();
656         }
657 
setPmkCache(boolean isEnabled)658         public void setPmkCache(boolean isEnabled) {
659             synchronized (mLock) {
660                 mRouterFingerPrintProto.pmkCacheEnabled = isEnabled;
661             }
662         }
663 
setMaxSupportedLinkSpeedMbps(int maxSupportedTxLinkSpeedMbps, int maxSupportedRxLinkSpeedMbps)664         public void setMaxSupportedLinkSpeedMbps(int maxSupportedTxLinkSpeedMbps,
665                 int maxSupportedRxLinkSpeedMbps) {
666             synchronized (mLock) {
667                 mRouterFingerPrintProto.maxSupportedTxLinkSpeedMbps = maxSupportedTxLinkSpeedMbps;
668                 mRouterFingerPrintProto.maxSupportedRxLinkSpeedMbps = maxSupportedRxLinkSpeedMbps;
669             }
670         }
671     }
getEapMethodProto(int eapMethod)672     private int getEapMethodProto(int eapMethod) {
673         switch (eapMethod) {
674             case WifiEnterpriseConfig.Eap.WAPI_CERT:
675                 return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_WAPI_CERT;
676             case WifiEnterpriseConfig.Eap.TLS:
677                 return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_TLS;
678             case WifiEnterpriseConfig.Eap.UNAUTH_TLS:
679                 return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_UNAUTH_TLS;
680             case WifiEnterpriseConfig.Eap.PEAP:
681                 return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_PEAP;
682             case WifiEnterpriseConfig.Eap.PWD:
683                 return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_PWD;
684             case WifiEnterpriseConfig.Eap.TTLS:
685                 return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_TTLS;
686             case WifiEnterpriseConfig.Eap.SIM:
687                 return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_SIM;
688             case WifiEnterpriseConfig.Eap.AKA:
689                 return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_AKA;
690             case WifiEnterpriseConfig.Eap.AKA_PRIME:
691                 return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_AKA_PRIME;
692             default:
693                 return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_UNKNOWN;
694         }
695     }
getAuthPhase2MethodProto(int phase2Method)696     private int getAuthPhase2MethodProto(int phase2Method) {
697         switch (phase2Method) {
698             case WifiEnterpriseConfig.Phase2.PAP:
699                 return WifiMetricsProto.RouterFingerPrint.TYPE_PHASE2_PAP;
700             case WifiEnterpriseConfig.Phase2.MSCHAP:
701                 return WifiMetricsProto.RouterFingerPrint.TYPE_PHASE2_MSCHAP;
702             case WifiEnterpriseConfig.Phase2.MSCHAPV2:
703                 return WifiMetricsProto.RouterFingerPrint.TYPE_PHASE2_MSCHAPV2;
704             case WifiEnterpriseConfig.Phase2.GTC:
705                 return WifiMetricsProto.RouterFingerPrint.TYPE_PHASE2_GTC;
706             case WifiEnterpriseConfig.Phase2.SIM:
707                 return WifiMetricsProto.RouterFingerPrint.TYPE_PHASE2_SIM;
708             case WifiEnterpriseConfig.Phase2.AKA:
709                 return WifiMetricsProto.RouterFingerPrint.TYPE_PHASE2_AKA;
710             case WifiEnterpriseConfig.Phase2.AKA_PRIME:
711                 return WifiMetricsProto.RouterFingerPrint.TYPE_PHASE2_AKA_PRIME;
712             default:
713                 return WifiMetricsProto.RouterFingerPrint.TYPE_PHASE2_NONE;
714         }
715     }
716 
getOcspTypeProto(int ocspType)717     private int getOcspTypeProto(int ocspType) {
718         switch (ocspType) {
719             case WifiEnterpriseConfig.OCSP_NONE:
720                 return WifiMetricsProto.RouterFingerPrint.TYPE_OCSP_NONE;
721             case WifiEnterpriseConfig.OCSP_REQUEST_CERT_STATUS:
722                 return WifiMetricsProto.RouterFingerPrint.TYPE_OCSP_REQUEST_CERT_STATUS;
723             case WifiEnterpriseConfig.OCSP_REQUIRE_CERT_STATUS:
724                 return WifiMetricsProto.RouterFingerPrint.TYPE_OCSP_REQUIRE_CERT_STATUS;
725             case WifiEnterpriseConfig.OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS:
726                 return WifiMetricsProto.RouterFingerPrint
727                         .TYPE_OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS;
728             default:
729                 return WifiMetricsProto.RouterFingerPrint.TYPE_OCSP_NONE;
730         }
731     }
732 
733     class BssidBlocklistStats {
734         public IntCounter networkSelectionFilteredBssidCount = new IntCounter();
735         public int numHighMovementConnectionSkipped = 0;
736         public int numHighMovementConnectionStarted = 0;
737         private final IntCounter mBlockedBssidPerReasonCount = new IntCounter();
738         private final IntCounter mBlockedConfigurationPerReasonCount = new IntCounter();
739 
toProto()740         public WifiMetricsProto.BssidBlocklistStats toProto() {
741             WifiMetricsProto.BssidBlocklistStats proto = new WifiMetricsProto.BssidBlocklistStats();
742             proto.networkSelectionFilteredBssidCount = networkSelectionFilteredBssidCount.toProto();
743             proto.highMovementMultipleScansFeatureEnabled = mContext.getResources().getBoolean(
744                     R.bool.config_wifiHighMovementNetworkSelectionOptimizationEnabled);
745             proto.numHighMovementConnectionSkipped = numHighMovementConnectionSkipped;
746             proto.numHighMovementConnectionStarted = numHighMovementConnectionStarted;
747             proto.bssidBlocklistPerReasonCount = mBlockedBssidPerReasonCount.toProto();
748             proto.wifiConfigBlocklistPerReasonCount = mBlockedConfigurationPerReasonCount.toProto();
749             return proto;
750         }
751 
incrementBssidBlocklistCount(int blockReason)752         public void incrementBssidBlocklistCount(int blockReason) {
753             mBlockedBssidPerReasonCount.increment(blockReason);
754         }
755 
incrementWificonfigurationBlocklistCount(int blockReason)756         public void incrementWificonfigurationBlocklistCount(int blockReason) {
757             mBlockedConfigurationPerReasonCount.increment(blockReason);
758         }
759 
760         @Override
toString()761         public String toString() {
762             StringBuilder sb = new StringBuilder();
763             sb.append("networkSelectionFilteredBssidCount=" + networkSelectionFilteredBssidCount);
764             sb.append("\nmBlockedBssidPerReasonCount=" + mBlockedBssidPerReasonCount);
765             sb.append("\nmBlockedConfigurationPerReasonCount="
766                     + mBlockedConfigurationPerReasonCount);
767 
768             sb.append(", highMovementMultipleScansFeatureEnabled="
769                     + mContext.getResources().getBoolean(
770                             R.bool.config_wifiHighMovementNetworkSelectionOptimizationEnabled));
771             sb.append(", numHighMovementConnectionSkipped=" + numHighMovementConnectionSkipped);
772             sb.append(", numHighMovementConnectionStarted=" + numHighMovementConnectionStarted);
773             sb.append(", mBlockedBssidPerReasonCount=" + mBlockedBssidPerReasonCount);
774             sb.append(", mBlockedConfigurationPerReasonCount="
775                     + mBlockedConfigurationPerReasonCount);
776             return sb.toString();
777         }
778     }
779 
780     class ConnectionDurationStats {
781         private int mConnectionDurationCellularDataOffMs;
782         private int mConnectionDurationSufficientThroughputMs;
783         private int mConnectionDurationInSufficientThroughputMs;
784         private int mConnectionDurationInSufficientThroughputDefaultWifiMs;
785 
toProto()786         public WifiMetricsProto.ConnectionDurationStats toProto() {
787             WifiMetricsProto.ConnectionDurationStats proto =
788                     new WifiMetricsProto.ConnectionDurationStats();
789             proto.totalTimeSufficientThroughputMs = mConnectionDurationSufficientThroughputMs;
790             proto.totalTimeInsufficientThroughputMs = mConnectionDurationInSufficientThroughputMs;
791             proto.totalTimeInsufficientThroughputDefaultWifiMs =
792                     mConnectionDurationInSufficientThroughputDefaultWifiMs;
793             proto.totalTimeCellularDataOffMs = mConnectionDurationCellularDataOffMs;
794             return proto;
795         }
clear()796         public void clear() {
797             mConnectionDurationCellularDataOffMs = 0;
798             mConnectionDurationSufficientThroughputMs = 0;
799             mConnectionDurationInSufficientThroughputMs = 0;
800             mConnectionDurationInSufficientThroughputDefaultWifiMs = 0;
801         }
incrementDurationCount(int timeDeltaLastTwoPollsMs, boolean isThroughputSufficient, boolean isCellularDataAvailable, boolean isDefaultOnWifi)802         public void incrementDurationCount(int timeDeltaLastTwoPollsMs,
803                 boolean isThroughputSufficient, boolean isCellularDataAvailable,
804                 boolean isDefaultOnWifi) {
805             if (!isCellularDataAvailable) {
806                 mConnectionDurationCellularDataOffMs += timeDeltaLastTwoPollsMs;
807             } else {
808                 if (isThroughputSufficient) {
809                     mConnectionDurationSufficientThroughputMs += timeDeltaLastTwoPollsMs;
810                 } else {
811                     mConnectionDurationInSufficientThroughputMs += timeDeltaLastTwoPollsMs;
812                     if (isDefaultOnWifi) {
813                         mConnectionDurationInSufficientThroughputDefaultWifiMs +=
814                                 timeDeltaLastTwoPollsMs;
815                     }
816                 }
817             }
818         }
819         @Override
toString()820         public String toString() {
821             StringBuilder sb = new StringBuilder();
822             sb.append("connectionDurationSufficientThroughputMs=")
823                     .append(mConnectionDurationSufficientThroughputMs)
824                     .append(", connectionDurationInSufficientThroughputMs=")
825                     .append(mConnectionDurationInSufficientThroughputMs)
826                     .append(", connectionDurationInSufficientThroughputDefaultWifiMs=")
827                     .append(mConnectionDurationInSufficientThroughputDefaultWifiMs)
828                     .append(", connectionDurationCellularDataOffMs=")
829                     .append(mConnectionDurationCellularDataOffMs);
830             return sb.toString();
831         }
832     }
833 
834     class WifiStatusBuilder {
835         private int mNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
836         private boolean mConnected;
837         private boolean mValidated;
838         private int mRssi;
839         private int mEstimatedTxKbps;
840         private int mEstimatedRxKbps;
841         private boolean mIsStuckDueToUserChoice;
842 
setNetworkId(int networkId)843         public void setNetworkId(int networkId) {
844             mNetworkId = networkId;
845         }
846 
getNetworkId()847         public int getNetworkId() {
848             return mNetworkId;
849         }
850 
setConnected(boolean connected)851         public void setConnected(boolean connected) {
852             mConnected = connected;
853         }
854 
setValidated(boolean validated)855         public void setValidated(boolean validated) {
856             mValidated = validated;
857         }
858 
setRssi(int rssi)859         public void setRssi(int rssi) {
860             mRssi = rssi;
861         }
862 
setEstimatedTxKbps(int estimatedTxKbps)863         public void setEstimatedTxKbps(int estimatedTxKbps) {
864             mEstimatedTxKbps = estimatedTxKbps;
865         }
866 
setEstimatedRxKbps(int estimatedRxKbps)867         public void setEstimatedRxKbps(int estimatedRxKbps) {
868             mEstimatedRxKbps = estimatedRxKbps;
869         }
870 
setUserChoice(boolean userChoice)871         public void setUserChoice(boolean userChoice) {
872             mIsStuckDueToUserChoice = userChoice;
873         }
874 
toProto()875         public WifiStatus toProto() {
876             WifiStatus result = new WifiStatus();
877             result.isConnected = mConnected;
878             result.isValidated = mValidated;
879             result.lastRssi = mRssi;
880             result.estimatedTxKbps = mEstimatedTxKbps;
881             result.estimatedRxKbps = mEstimatedRxKbps;
882             result.isStuckDueToUserConnectChoice = mIsStuckDueToUserChoice;
883             return result;
884         }
885     }
886 
convertToNetworkDisableReason( WifiConfiguration config, Set<Integer> bssidBlocklistReasons)887     private NetworkDisableReason convertToNetworkDisableReason(
888             WifiConfiguration config, Set<Integer> bssidBlocklistReasons) {
889         NetworkSelectionStatus status = config.getNetworkSelectionStatus();
890         NetworkDisableReason result = new NetworkDisableReason();
891         if (config.allowAutojoin) {
892             if (!status.isNetworkEnabled()) {
893                 result.disableReason =
894                         MetricsUtils.convertNetworkSelectionDisableReasonToWifiProtoEnum(
895                                 status.getNetworkSelectionDisableReason());
896                 if (status.isNetworkPermanentlyDisabled()) {
897                     result.configPermanentlyDisabled = true;
898                 } else {
899                     result.configTemporarilyDisabled = true;
900                 }
901             }
902         } else {
903             result.disableReason = NetworkDisableReason.REASON_AUTO_JOIN_DISABLED;
904             result.configPermanentlyDisabled = true;
905         }
906 
907         int[] convertedBssidBlockReasons = bssidBlocklistReasons.stream()
908                 .mapToInt(i -> MetricsUtils.convertBssidBlocklistReasonToWifiProtoEnum(i))
909                 .toArray();
910         if (convertedBssidBlockReasons.length > 0) {
911             result.bssidDisableReasons = convertedBssidBlockReasons;
912         }
913         return result;
914     }
915 
916     class UserActionEventWithTime {
917         private UserActionEvent mUserActionEvent;
918         private long mWallClockTimeMs = 0; // wall clock time for debugging only
919 
UserActionEventWithTime(int eventType, TargetNetworkInfo targetNetworkInfo)920         UserActionEventWithTime(int eventType, TargetNetworkInfo targetNetworkInfo) {
921             mUserActionEvent = new UserActionEvent();
922             mUserActionEvent.eventType = eventType;
923             mUserActionEvent.startTimeMillis = mClock.getElapsedSinceBootMillis();
924             mWallClockTimeMs = mClock.getWallClockMillis();
925             mUserActionEvent.targetNetworkInfo = targetNetworkInfo;
926             mUserActionEvent.wifiStatus = mWifiStatusBuilder.toProto();
927         }
928 
UserActionEventWithTime(int eventType, int targetNetId)929         UserActionEventWithTime(int eventType, int targetNetId) {
930             this(eventType, null);
931             if (targetNetId >= 0) {
932                 WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(targetNetId);
933                 if (config != null) {
934                     TargetNetworkInfo networkInfo = new TargetNetworkInfo();
935                     networkInfo.isEphemeral = config.isEphemeral();
936                     networkInfo.isPasspoint = config.isPasspoint();
937                     mUserActionEvent.targetNetworkInfo = networkInfo;
938                     mUserActionEvent.networkDisableReason = convertToNetworkDisableReason(
939                             config, mWifiBlocklistMonitor.getFailureReasonsForSsid(config.SSID));
940                 }
941             }
942         }
943 
toString()944         public String toString() {
945             StringBuilder sb = new StringBuilder();
946             Calendar c = Calendar.getInstance();
947             c.setTimeInMillis(mWallClockTimeMs);
948             sb.append(c.get(Calendar.MONTH)).append("-")
949                     .append(c.get(Calendar.DAY_OF_MONTH)).append(" ")
950                     .append(c.get(Calendar.HOUR_OF_DAY)).append(":")
951                     .append(c.get(Calendar.MINUTE)).append(":")
952                     .append(c.get(Calendar.SECOND)).append(".")
953                     .append(c.get(Calendar.MILLISECOND));
954             String eventType = "UNKNOWN";
955             switch (mUserActionEvent.eventType) {
956                 case UserActionEvent.EVENT_FORGET_WIFI:
957                     eventType = "EVENT_FORGET_WIFI";
958                     break;
959                 case UserActionEvent.EVENT_DISCONNECT_WIFI:
960                     eventType = "EVENT_DISCONNECT_WIFI";
961                     break;
962                 case UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_METERED:
963                     eventType = "EVENT_CONFIGURE_METERED_STATUS_METERED";
964                     break;
965                 case UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_UNMETERED:
966                     eventType = "EVENT_CONFIGURE_METERED_STATUS_UNMETERED";
967                     break;
968                 case UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_AUTO:
969                     eventType = "EVENT_CONFIGURE_METERED_STATUS_AUTO";
970                     break;
971                 case UserActionEvent.EVENT_CONFIGURE_MAC_RANDOMIZATION_ON:
972                     eventType = "EVENT_CONFIGURE_MAC_RANDOMIZATION_ON";
973                     break;
974                 case UserActionEvent.EVENT_CONFIGURE_MAC_RANDOMIZATION_OFF:
975                     eventType = "EVENT_CONFIGURE_MAC_RANDOMIZATION_OFF";
976                     break;
977                 case UserActionEvent.EVENT_CONFIGURE_AUTO_CONNECT_ON:
978                     eventType = "EVENT_CONFIGURE_AUTO_CONNECT_ON";
979                     break;
980                 case UserActionEvent.EVENT_CONFIGURE_AUTO_CONNECT_OFF:
981                     eventType = "EVENT_CONFIGURE_AUTO_CONNECT_OFF";
982                     break;
983                 case UserActionEvent.EVENT_TOGGLE_WIFI_ON:
984                     eventType = "EVENT_TOGGLE_WIFI_ON";
985                     break;
986                 case UserActionEvent.EVENT_TOGGLE_WIFI_OFF:
987                     eventType = "EVENT_TOGGLE_WIFI_OFF";
988                     break;
989                 case UserActionEvent.EVENT_MANUAL_CONNECT:
990                     eventType = "EVENT_MANUAL_CONNECT";
991                     break;
992                 case UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK:
993                     eventType = "EVENT_ADD_OR_UPDATE_NETWORK";
994                     break;
995                 case UserActionEvent.EVENT_RESTART_WIFI_SUB_SYSTEM:
996                     eventType = "EVENT_RESTART_WIFI_SUB_SYSTEM";
997                     break;
998             }
999             sb.append(" eventType=").append(eventType);
1000             sb.append(" startTimeMillis=").append(mUserActionEvent.startTimeMillis);
1001             TargetNetworkInfo networkInfo = mUserActionEvent.targetNetworkInfo;
1002             if (networkInfo != null) {
1003                 sb.append(" isEphemeral=").append(networkInfo.isEphemeral);
1004                 sb.append(" isPasspoint=").append(networkInfo.isPasspoint);
1005             }
1006             WifiStatus wifiStatus = mUserActionEvent.wifiStatus;
1007             if (wifiStatus != null) {
1008                 sb.append("\nWifiStatus: isConnected=").append(wifiStatus.isConnected);
1009                 sb.append(" isValidated=").append(wifiStatus.isValidated);
1010                 sb.append(" lastRssi=").append(wifiStatus.lastRssi);
1011                 sb.append(" estimatedTxKbps=").append(wifiStatus.estimatedTxKbps);
1012                 sb.append(" estimatedRxKbps=").append(wifiStatus.estimatedRxKbps);
1013                 sb.append(" isStuckDueToUserConnectChoice=")
1014                         .append(wifiStatus.isStuckDueToUserConnectChoice);
1015             }
1016             NetworkDisableReason disableReason = mUserActionEvent.networkDisableReason;
1017             if (disableReason != null) {
1018                 sb.append("\nNetworkDisableReason: DisableReason=")
1019                         .append(disableReason.disableReason);
1020                 sb.append(" configTemporarilyDisabled=")
1021                         .append(disableReason.configTemporarilyDisabled);
1022                 sb.append(" configPermanentlyDisabled=")
1023                         .append(disableReason.configPermanentlyDisabled);
1024                 sb.append(" bssidDisableReasons=")
1025                         .append(Arrays.toString(disableReason.bssidDisableReasons));
1026             }
1027             return sb.toString();
1028         }
1029 
toProto()1030         public UserActionEvent toProto() {
1031             return mUserActionEvent;
1032         }
1033     }
1034 
1035     /**
1036      * Log event, tracking the start time, end time and result of a wireless connection attempt.
1037      */
1038     class ConnectionEvent {
1039         final WifiMetricsProto.ConnectionEvent mConnectionEvent;
1040         //<TODO> Move these constants into a wifi.proto Enum, and create a new Failure Type field
1041         //covering more than just l2 failures. see b/27652362
1042         /**
1043          * Failure codes, used for the 'level_2_failure_code' Connection event field (covers a lot
1044          * more failures than just l2 though, since the proto does not have a place to log
1045          * framework failures)
1046          */
1047         // Failure is unknown
1048         public static final int FAILURE_UNKNOWN = 0;
1049         // NONE
1050         public static final int FAILURE_NONE = 1;
1051         // ASSOCIATION_REJECTION_EVENT
1052         public static final int FAILURE_ASSOCIATION_REJECTION = 2;
1053         // AUTHENTICATION_FAILURE_EVENT
1054         public static final int FAILURE_AUTHENTICATION_FAILURE = 3;
1055         // SSID_TEMP_DISABLED (Also Auth failure)
1056         public static final int FAILURE_SSID_TEMP_DISABLED = 4;
1057         // reconnect() or reassociate() call to WifiNative failed
1058         public static final int FAILURE_CONNECT_NETWORK_FAILED = 5;
1059         // NETWORK_DISCONNECTION_EVENT
1060         public static final int FAILURE_NETWORK_DISCONNECTION = 6;
1061         // NEW_CONNECTION_ATTEMPT before previous finished
1062         public static final int FAILURE_NEW_CONNECTION_ATTEMPT = 7;
1063         // New connection attempt to the same network & bssid
1064         public static final int FAILURE_REDUNDANT_CONNECTION_ATTEMPT = 8;
1065         // Roam Watchdog timer triggered (Roaming timed out)
1066         public static final int FAILURE_ROAM_TIMEOUT = 9;
1067         // DHCP failure
1068         public static final int FAILURE_DHCP = 10;
1069         // ASSOCIATION_TIMED_OUT
1070         public static final int FAILURE_ASSOCIATION_TIMED_OUT = 11;
1071         // NETWORK_NOT_FOUND
1072         public static final int FAILURE_NETWORK_NOT_FOUND = 12;
1073 
1074         RouterFingerPrint mRouterFingerPrint;
1075         private String mConfigSsid;
1076         private String mConfigBssid;
1077         private int mWifiState;
1078         private boolean mScreenOn;
1079         private int mAuthType;
1080         private int mTrigger;
1081         private boolean mHasEverConnected;
1082 
ConnectionEvent()1083         private ConnectionEvent() {
1084             mConnectionEvent = new WifiMetricsProto.ConnectionEvent();
1085             mRouterFingerPrint = new RouterFingerPrint();
1086             mConnectionEvent.routerFingerprint = mRouterFingerPrint.mRouterFingerPrintProto;
1087             mConfigSsid = "<NULL>";
1088             mConfigBssid = "<NULL>";
1089             mWifiState = WifiMetricsProto.WifiLog.WIFI_UNKNOWN;
1090             mScreenOn = false;
1091         }
1092 
toString()1093         public String toString() {
1094             StringBuilder sb = new StringBuilder();
1095             sb.append("startTime=");
1096             Calendar c = Calendar.getInstance();
1097             synchronized (mLock) {
1098                 c.setTimeInMillis(mConnectionEvent.startTimeMillis);
1099                 if (mConnectionEvent.startTimeMillis == 0) {
1100                     sb.append("            <null>");
1101                 } else {
1102                     sb.append(c.get(Calendar.MONTH)).append("-")
1103                             .append(c.get(Calendar.DAY_OF_MONTH)).append(" ")
1104                             .append(c.get(Calendar.HOUR_OF_DAY)).append(":")
1105                             .append(c.get(Calendar.MINUTE)).append(":")
1106                             .append(c.get(Calendar.SECOND)).append(".")
1107                             .append(c.get(Calendar.MILLISECOND));
1108                 }
1109                 sb.append(", SSID=");
1110                 sb.append(mConfigSsid);
1111                 sb.append(", BSSID=");
1112                 sb.append(mConfigBssid);
1113                 sb.append(", durationMillis=");
1114                 sb.append(mConnectionEvent.durationTakenToConnectMillis);
1115                 sb.append(", roamType=");
1116                 switch(mConnectionEvent.roamType) {
1117                     case 1:
1118                         sb.append("ROAM_NONE");
1119                         break;
1120                     case 2:
1121                         sb.append("ROAM_DBDC");
1122                         break;
1123                     case 3:
1124                         sb.append("ROAM_ENTERPRISE");
1125                         break;
1126                     case 4:
1127                         sb.append("ROAM_USER_SELECTED");
1128                         break;
1129                     case 5:
1130                         sb.append("ROAM_UNRELATED");
1131                         break;
1132                     default:
1133                         sb.append("ROAM_UNKNOWN");
1134                 }
1135                 sb.append(", connectionResult=");
1136                 sb.append(mConnectionEvent.connectionResult);
1137                 sb.append(", level2FailureCode=");
1138                 switch(mConnectionEvent.level2FailureCode) {
1139                     case FAILURE_NONE:
1140                         sb.append("NONE");
1141                         break;
1142                     case FAILURE_ASSOCIATION_REJECTION:
1143                         sb.append("ASSOCIATION_REJECTION");
1144                         break;
1145                     case FAILURE_AUTHENTICATION_FAILURE:
1146                         sb.append("AUTHENTICATION_FAILURE");
1147                         break;
1148                     case FAILURE_SSID_TEMP_DISABLED:
1149                         sb.append("SSID_TEMP_DISABLED");
1150                         break;
1151                     case FAILURE_CONNECT_NETWORK_FAILED:
1152                         sb.append("CONNECT_NETWORK_FAILED");
1153                         break;
1154                     case FAILURE_NETWORK_DISCONNECTION:
1155                         sb.append("NETWORK_DISCONNECTION");
1156                         break;
1157                     case FAILURE_NEW_CONNECTION_ATTEMPT:
1158                         sb.append("NEW_CONNECTION_ATTEMPT");
1159                         break;
1160                     case FAILURE_REDUNDANT_CONNECTION_ATTEMPT:
1161                         sb.append("REDUNDANT_CONNECTION_ATTEMPT");
1162                         break;
1163                     case FAILURE_ROAM_TIMEOUT:
1164                         sb.append("ROAM_TIMEOUT");
1165                         break;
1166                     case FAILURE_DHCP:
1167                         sb.append("DHCP");
1168                         break;
1169                     case FAILURE_ASSOCIATION_TIMED_OUT:
1170                         sb.append("ASSOCIATION_TIMED_OUT");
1171                         break;
1172                     case FAILURE_NETWORK_NOT_FOUND:
1173                         sb.append("FAILURE_NETWORK_NOT_FOUND");
1174                         break;
1175                     default:
1176                         sb.append("UNKNOWN");
1177                         break;
1178                 }
1179                 sb.append(", connectivityLevelFailureCode=");
1180                 switch(mConnectionEvent.connectivityLevelFailureCode) {
1181                     case WifiMetricsProto.ConnectionEvent.HLF_NONE:
1182                         sb.append("NONE");
1183                         break;
1184                     case WifiMetricsProto.ConnectionEvent.HLF_DHCP:
1185                         sb.append("DHCP");
1186                         break;
1187                     case WifiMetricsProto.ConnectionEvent.HLF_NO_INTERNET:
1188                         sb.append("NO_INTERNET");
1189                         break;
1190                     case WifiMetricsProto.ConnectionEvent.HLF_UNWANTED:
1191                         sb.append("UNWANTED");
1192                         break;
1193                     default:
1194                         sb.append("UNKNOWN");
1195                         break;
1196                 }
1197                 sb.append(", signalStrength=");
1198                 sb.append(mConnectionEvent.signalStrength);
1199                 sb.append(", wifiState=");
1200                 switch(mWifiState) {
1201                     case WifiMetricsProto.WifiLog.WIFI_DISABLED:
1202                         sb.append("WIFI_DISABLED");
1203                         break;
1204                     case WifiMetricsProto.WifiLog.WIFI_DISCONNECTED:
1205                         sb.append("WIFI_DISCONNECTED");
1206                         break;
1207                     case WifiMetricsProto.WifiLog.WIFI_ASSOCIATED:
1208                         sb.append("WIFI_ASSOCIATED");
1209                         break;
1210                     default:
1211                         sb.append("WIFI_UNKNOWN");
1212                         break;
1213                 }
1214                 sb.append(", screenOn=");
1215                 sb.append(mScreenOn);
1216                 sb.append(", mRouterFingerprint=");
1217                 sb.append(mRouterFingerPrint.toString());
1218                 sb.append(", useRandomizedMac=");
1219                 sb.append(mConnectionEvent.useRandomizedMac);
1220                 sb.append(", useAggressiveMac=" + mConnectionEvent.useAggressiveMac);
1221                 sb.append(", connectionNominator=");
1222                 switch (mConnectionEvent.connectionNominator) {
1223                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_UNKNOWN:
1224                         sb.append("NOMINATOR_UNKNOWN");
1225                         break;
1226                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_MANUAL:
1227                         sb.append("NOMINATOR_MANUAL");
1228                         break;
1229                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_SAVED:
1230                         sb.append("NOMINATOR_SAVED");
1231                         break;
1232                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_SUGGESTION:
1233                         sb.append("NOMINATOR_SUGGESTION");
1234                         break;
1235                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_PASSPOINT:
1236                         sb.append("NOMINATOR_PASSPOINT");
1237                         break;
1238                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_CARRIER:
1239                         sb.append("NOMINATOR_CARRIER");
1240                         break;
1241                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_EXTERNAL_SCORED:
1242                         sb.append("NOMINATOR_EXTERNAL_SCORED");
1243                         break;
1244                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_SPECIFIER:
1245                         sb.append("NOMINATOR_SPECIFIER");
1246                         break;
1247                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_SAVED_USER_CONNECT_CHOICE:
1248                         sb.append("NOMINATOR_SAVED_USER_CONNECT_CHOICE");
1249                         break;
1250                     case WifiMetricsProto.ConnectionEvent.NOMINATOR_OPEN_NETWORK_AVAILABLE:
1251                         sb.append("NOMINATOR_OPEN_NETWORK_AVAILABLE");
1252                         break;
1253                     default:
1254                         sb.append("UnrecognizedNominator(" + mConnectionEvent.connectionNominator
1255                                 + ")");
1256                 }
1257                 sb.append(", networkSelectorExperimentId=");
1258                 sb.append(mConnectionEvent.networkSelectorExperimentId);
1259                 sb.append(", numBssidInBlocklist=" + mConnectionEvent.numBssidInBlocklist);
1260                 sb.append(", level2FailureReason=");
1261                 switch(mConnectionEvent.level2FailureReason) {
1262                     case WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_NONE:
1263                         sb.append("AUTH_FAILURE_NONE");
1264                         break;
1265                     case WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_TIMEOUT:
1266                         sb.append("AUTH_FAILURE_TIMEOUT");
1267                         break;
1268                     case WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_WRONG_PSWD:
1269                         sb.append("AUTH_FAILURE_WRONG_PSWD");
1270                         break;
1271                     case WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_EAP_FAILURE:
1272                         sb.append("AUTH_FAILURE_EAP_FAILURE");
1273                         break;
1274                     case WifiMetricsProto.ConnectionEvent.DISCONNECTION_NON_LOCAL:
1275                         sb.append("DISCONNECTION_NON_LOCAL");
1276                         break;
1277                     default:
1278                         sb.append("FAILURE_REASON_UNKNOWN");
1279                         break;
1280                 }
1281                 sb.append(", networkType=");
1282                 switch(mConnectionEvent.networkType) {
1283                     case WifiMetricsProto.ConnectionEvent.TYPE_UNKNOWN:
1284                         sb.append("TYPE_UNKNOWN");
1285                         break;
1286                     case WifiMetricsProto.ConnectionEvent.TYPE_WPA2:
1287                         sb.append("TYPE_WPA2");
1288                         break;
1289                     case WifiMetricsProto.ConnectionEvent.TYPE_WPA3:
1290                         sb.append("TYPE_WPA3");
1291                         break;
1292                     case WifiMetricsProto.ConnectionEvent.TYPE_PASSPOINT:
1293                         sb.append("TYPE_PASSPOINT");
1294                         break;
1295                     case WifiMetricsProto.ConnectionEvent.TYPE_EAP:
1296                         sb.append("TYPE_EAP");
1297                         break;
1298                     case WifiMetricsProto.ConnectionEvent.TYPE_OWE:
1299                         sb.append("TYPE_OWE");
1300                         break;
1301                     case WifiMetricsProto.ConnectionEvent.TYPE_OPEN:
1302                         sb.append("TYPE_OPEN");
1303                         break;
1304                     case WifiMetricsProto.ConnectionEvent.TYPE_WAPI:
1305                         sb.append("TYPE_WAPI");
1306                         break;
1307                 }
1308                 sb.append(", networkCreator=");
1309                 switch (mConnectionEvent.networkCreator) {
1310                     case WifiMetricsProto.ConnectionEvent.CREATOR_UNKNOWN:
1311                         sb.append("CREATOR_UNKNOWN");
1312                         break;
1313                     case WifiMetricsProto.ConnectionEvent.CREATOR_USER:
1314                         sb.append("CREATOR_USER");
1315                         break;
1316                     case WifiMetricsProto.ConnectionEvent.CREATOR_CARRIER:
1317                         sb.append("CREATOR_CARRIER");
1318                         break;
1319                 }
1320                 sb.append(", numConsecutiveConnectionFailure="
1321                         + mConnectionEvent.numConsecutiveConnectionFailure);
1322                 sb.append(", isOsuProvisioned=" + mConnectionEvent.isOsuProvisioned);
1323                 sb.append(" interfaceName=").append(mConnectionEvent.interfaceName);
1324                 sb.append(" interfaceRole=").append(
1325                         clientRoleEnumToString(mConnectionEvent.interfaceRole));
1326                 sb.append(", isFirstConnectionAfterBoot="
1327                         + mConnectionEvent.isFirstConnectionAfterBoot);
1328                 return sb.toString();
1329             }
1330         }
1331 
updateFromWifiConfiguration(WifiConfiguration config)1332         private void updateFromWifiConfiguration(WifiConfiguration config) {
1333             synchronized (mLock) {
1334                 if (config != null) {
1335                     // Is this a hidden network
1336                     mRouterFingerPrint.mRouterFingerPrintProto.hidden = config.hiddenSSID;
1337                     // Config may not have a valid dtimInterval set yet, in which case dtim will be
1338                     // zero (These are only populated from beacon frame scan results, which are
1339                     // returned as scan results from the chip far less frequently than
1340                     // Probe-responses)
1341                     if (config.dtimInterval > 0) {
1342                         mRouterFingerPrint.mRouterFingerPrintProto.dtim = config.dtimInterval;
1343                     }
1344 
1345                     mConfigSsid = config.SSID;
1346                     // Get AuthType information from config (We do this again from ScanResult after
1347                     // associating with BSSID)
1348                     if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_OPEN)) {
1349                         mRouterFingerPrint.mRouterFingerPrintProto.authentication =
1350                                 WifiMetricsProto.RouterFingerPrint.AUTH_OPEN;
1351                     } else if (config.isEnterprise()) {
1352                         mRouterFingerPrint.mRouterFingerPrintProto.authentication =
1353                                 WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE;
1354                     } else {
1355                         mRouterFingerPrint.mRouterFingerPrintProto.authentication =
1356                                 WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL;
1357                     }
1358                     mRouterFingerPrint.mRouterFingerPrintProto.passpoint = config.isPasspoint();
1359                     mRouterFingerPrint.mRouterFingerPrintProto.isPasspointHomeProvider =
1360                             config.isHomeProviderNetwork;
1361                     // If there's a ScanResult candidate associated with this config already, get it
1362                     // and log (more accurate) metrics from it
1363                     ScanResult candidate = config.getNetworkSelectionStatus().getCandidate();
1364                     if (candidate != null) {
1365                         updateMetricsFromScanResult(this, candidate);
1366                     }
1367                     if (mRouterFingerPrint.mRouterFingerPrintProto.authentication
1368                             == WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE
1369                             && config.enterpriseConfig != null) {
1370                         int eapMethod = config.enterpriseConfig.getEapMethod();
1371                         mRouterFingerPrint.mRouterFingerPrintProto.eapMethod =
1372                                 getEapMethodProto(eapMethod);
1373                         int phase2Method = config.enterpriseConfig.getPhase2Method();
1374                         mRouterFingerPrint.mRouterFingerPrintProto.authPhase2Method =
1375                                 getAuthPhase2MethodProto(phase2Method);
1376                         int ocspType = config.enterpriseConfig.getOcsp();
1377                         mRouterFingerPrint.mRouterFingerPrintProto.ocspType =
1378                                 getOcspTypeProto(ocspType);
1379                     }
1380                 }
1381             }
1382         }
1383     }
1384 
1385     class WifiOffMetrics {
1386         public int numWifiOff = 0;
1387         public int numWifiOffDeferring = 0;
1388         public int numWifiOffDeferringTimeout = 0;
1389         public final IntCounter wifiOffDeferringTimeHistogram = new IntCounter();
1390 
toProto()1391         public WifiMetricsProto.WifiOffMetrics toProto() {
1392             WifiMetricsProto.WifiOffMetrics proto =
1393                     new WifiMetricsProto.WifiOffMetrics();
1394             proto.numWifiOff = numWifiOff;
1395             proto.numWifiOffDeferring = numWifiOffDeferring;
1396             proto.numWifiOffDeferringTimeout = numWifiOffDeferringTimeout;
1397             proto.wifiOffDeferringTimeHistogram = wifiOffDeferringTimeHistogram.toProto();
1398             return proto;
1399         }
1400 
clear()1401         public void clear() {
1402             numWifiOff = 0;
1403             numWifiOffDeferring = 0;
1404             numWifiOffDeferringTimeout = 0;
1405             wifiOffDeferringTimeHistogram.clear();
1406         }
1407 
1408         @Override
toString()1409         public String toString() {
1410             StringBuilder sb = new StringBuilder();
1411             sb.append("numWifiOff=")
1412                     .append(numWifiOff)
1413                     .append(", numWifiOffDeferring=")
1414                     .append(numWifiOffDeferring)
1415                     .append(", numWifiOffDeferringTimeout=")
1416                     .append(numWifiOffDeferringTimeout)
1417                     .append(", wifiOffDeferringTimeHistogram=")
1418                     .append(wifiOffDeferringTimeHistogram);
1419             return sb.toString();
1420         }
1421     }
1422 
1423     class SoftApConfigLimitationMetrics {
1424         // Collect the number of softap security setting reset to default during the restore
1425         public int numSecurityTypeResetToDefault = 0;
1426         // Collect the number of softap max client setting reset to default during the restore
1427         public int numMaxClientSettingResetToDefault = 0;
1428         // Collect the number of softap client control setting reset to default during the restore
1429         public int numClientControlByUserResetToDefault = 0;
1430         // Collect the max client setting when reach it cause client is blocked
1431         public final IntCounter maxClientSettingWhenReachHistogram = new IntCounter();
1432 
toProto()1433         public WifiMetricsProto.SoftApConfigLimitationMetrics toProto() {
1434             WifiMetricsProto.SoftApConfigLimitationMetrics proto =
1435                     new WifiMetricsProto.SoftApConfigLimitationMetrics();
1436             proto.numSecurityTypeResetToDefault = numSecurityTypeResetToDefault;
1437             proto.numMaxClientSettingResetToDefault = numMaxClientSettingResetToDefault;
1438             proto.numClientControlByUserResetToDefault = numClientControlByUserResetToDefault;
1439             proto.maxClientSettingWhenReachHistogram = maxClientSettingWhenReachHistogram.toProto();
1440             return proto;
1441         }
1442 
clear()1443         public void clear() {
1444             numSecurityTypeResetToDefault = 0;
1445             numMaxClientSettingResetToDefault = 0;
1446             numClientControlByUserResetToDefault = 0;
1447             maxClientSettingWhenReachHistogram.clear();
1448         }
1449 
1450         @Override
toString()1451         public String toString() {
1452             StringBuilder sb = new StringBuilder();
1453             sb.append("numSecurityTypeResetToDefault=")
1454                     .append(numSecurityTypeResetToDefault)
1455                     .append(", numMaxClientSettingResetToDefault=")
1456                     .append(numMaxClientSettingResetToDefault)
1457                     .append(", numClientControlByUserResetToDefault=")
1458                     .append(numClientControlByUserResetToDefault)
1459                     .append(", maxClientSettingWhenReachHistogram=")
1460                     .append(maxClientSettingWhenReachHistogram);
1461             return sb.toString();
1462         }
1463     }
1464 
1465     class CarrierWifiMetrics {
1466         public int numConnectionSuccess = 0;
1467         public int numConnectionAuthFailure = 0;
1468         public int numConnectionNonAuthFailure = 0;
1469 
toProto()1470         public WifiMetricsProto.CarrierWifiMetrics toProto() {
1471             WifiMetricsProto.CarrierWifiMetrics proto =
1472                     new WifiMetricsProto.CarrierWifiMetrics();
1473             proto.numConnectionSuccess = numConnectionSuccess;
1474             proto.numConnectionAuthFailure = numConnectionAuthFailure;
1475             proto.numConnectionNonAuthFailure = numConnectionNonAuthFailure;
1476             return proto;
1477         }
1478 
clear()1479         public void clear() {
1480             numConnectionSuccess = 0;
1481             numConnectionAuthFailure = 0;
1482             numConnectionNonAuthFailure = 0;
1483         }
1484 
1485         @Override
toString()1486         public String toString() {
1487             StringBuilder sb = new StringBuilder();
1488             sb.append("numConnectionSuccess=")
1489                     .append(numConnectionSuccess)
1490                     .append(", numConnectionAuthFailure=")
1491                     .append(numConnectionAuthFailure)
1492                     .append(", numConnectionNonAuthFailure")
1493                     .append(numConnectionNonAuthFailure);
1494             return sb.toString();
1495         }
1496     }
1497 
WifiMetrics(Context context, FrameworkFacade facade, Clock clock, Looper looper, WifiAwareMetrics awareMetrics, RttMetrics rttMetrics, WifiPowerMetrics wifiPowerMetrics, WifiP2pMetrics wifiP2pMetrics, DppMetrics dppMetrics, WifiMonitor wifiMonitor)1498     public WifiMetrics(Context context, FrameworkFacade facade, Clock clock, Looper looper,
1499             WifiAwareMetrics awareMetrics, RttMetrics rttMetrics,
1500             WifiPowerMetrics wifiPowerMetrics, WifiP2pMetrics wifiP2pMetrics,
1501             DppMetrics dppMetrics, WifiMonitor wifiMonitor) {
1502         mContext = context;
1503         mFacade = facade;
1504         mClock = clock;
1505         mWifiState = WifiMetricsProto.WifiLog.WIFI_DISABLED;
1506         mRecordStartTimeSec = mClock.getElapsedSinceBootMillis() / 1000;
1507         mWifiAwareMetrics = awareMetrics;
1508         mRttMetrics = rttMetrics;
1509         mWifiPowerMetrics = wifiPowerMetrics;
1510         mWifiP2pMetrics = wifiP2pMetrics;
1511         mDppMetrics = dppMetrics;
1512         mWifiMonitor = wifiMonitor;
1513         mHandler = new Handler(looper) {
1514             public void handleMessage(Message msg) {
1515                 synchronized (mLock) {
1516                     processMessage(msg);
1517                 }
1518             }
1519         };
1520 
1521         mCurrentDeviceMobilityState = WifiManager.DEVICE_MOBILITY_STATE_UNKNOWN;
1522         DeviceMobilityStatePnoScanStats unknownStateStats =
1523                 getOrCreateDeviceMobilityStatePnoScanStats(mCurrentDeviceMobilityState);
1524         unknownStateStats.numTimesEnteredState++;
1525         mCurrentDeviceMobilityStateStartMs = mClock.getElapsedSinceBootMillis();
1526         mCurrentDeviceMobilityStatePnoScanStartMs = -1;
1527         mOnWifiUsabilityListeners = new RemoteCallbackList<>();
1528 
1529         IntentFilter filter = new IntentFilter();
1530         filter.addAction(Intent.ACTION_SCREEN_ON);
1531         filter.addAction(Intent.ACTION_SCREEN_OFF);
1532         context.registerReceiver(
1533                 new BroadcastReceiver() {
1534                     @Override
1535                     public void onReceive(Context context, Intent intent) {
1536                         String action = intent.getAction();
1537                         if (action.equals(Intent.ACTION_SCREEN_ON)) {
1538                             setScreenState(true);
1539                         } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1540                             setScreenState(false);
1541                         }
1542                     }
1543                 }, filter, null, mHandler);
1544         setScreenState(context.getSystemService(PowerManager.class).isInteractive());
1545 
1546         mScanMetrics = new ScanMetrics(context, clock);
1547         mTelephonyManager = context.getSystemService(TelephonyManager.class);
1548     }
1549 
1550     /** Sets internal ScoringParams member */
setScoringParams(ScoringParams scoringParams)1551     public void setScoringParams(ScoringParams scoringParams) {
1552         mScoringParams = scoringParams;
1553     }
1554 
1555     /** Sets internal WifiConfigManager member */
setWifiConfigManager(WifiConfigManager wifiConfigManager)1556     public void setWifiConfigManager(WifiConfigManager wifiConfigManager) {
1557         mWifiConfigManager = wifiConfigManager;
1558     }
1559 
1560     /** Sets internal WifiNetworkSelector member */
setWifiNetworkSelector(WifiNetworkSelector wifiNetworkSelector)1561     public void setWifiNetworkSelector(WifiNetworkSelector wifiNetworkSelector) {
1562         mWifiNetworkSelector = wifiNetworkSelector;
1563     }
1564 
1565     /** Sets internal PasspointManager member */
setPasspointManager(PasspointManager passpointManager)1566     public void setPasspointManager(PasspointManager passpointManager) {
1567         mPasspointManager = passpointManager;
1568     }
1569 
1570     /** Sets internal WifiDataStall member */
setWifiDataStall(WifiDataStall wifiDataStall)1571     public void setWifiDataStall(WifiDataStall wifiDataStall) {
1572         mWifiDataStall = wifiDataStall;
1573     }
1574 
1575     /** Sets internal WifiBlocklistMonitor member */
setWifiBlocklistMonitor(WifiBlocklistMonitor wifiBlocklistMonitor)1576     public void setWifiBlocklistMonitor(WifiBlocklistMonitor wifiBlocklistMonitor) {
1577         mWifiBlocklistMonitor = wifiBlocklistMonitor;
1578     }
1579 
1580     /** Sets internal WifiHealthMonitor member */
setWifiHealthMonitor(WifiHealthMonitor wifiHealthMonitor)1581     public void setWifiHealthMonitor(WifiHealthMonitor wifiHealthMonitor) {
1582         mWifiHealthMonitor = wifiHealthMonitor;
1583     }
1584 
1585     /** Sets internal WifiScoreCard member */
setWifiScoreCard(WifiScoreCard wifiScoreCard)1586     public void setWifiScoreCard(WifiScoreCard wifiScoreCard) {
1587         mWifiScoreCard = wifiScoreCard;
1588     }
1589 
1590     /** Sets internal WifiChannelUtilization member */
setWifiChannelUtilization(WifiChannelUtilization wifiChannelUtilization)1591     public void setWifiChannelUtilization(WifiChannelUtilization wifiChannelUtilization) {
1592         mWifiChannelUtilization = wifiChannelUtilization;
1593     }
1594 
1595     /** Sets internal WifiSettingsStore member */
setWifiSettingsStore(WifiSettingsStore wifiSettingsStore)1596     public void setWifiSettingsStore(WifiSettingsStore wifiSettingsStore) {
1597         mWifiSettingsStore = wifiSettingsStore;
1598     }
1599 
1600     /** Sets internal ActiveModeWarden member */
setActiveModeWarden(ActiveModeWarden activeModeWarden)1601     public void setActiveModeWarden(ActiveModeWarden activeModeWarden) {
1602         mActiveModeWarden = activeModeWarden;
1603         mActiveModeWarden.registerModeChangeCallback(new ModeChangeCallback());
1604     }
1605 
1606     /**
1607      * Implements callbacks that set the internal ifaceName to ClientRole mapping.
1608      */
1609     @VisibleForTesting
1610     private class ModeChangeCallback implements ActiveModeWarden.ModeChangeCallback {
1611         @Override
onActiveModeManagerAdded(@onNull ActiveModeManager activeModeManager)1612         public void onActiveModeManagerAdded(@NonNull ActiveModeManager activeModeManager) {
1613             if (!(activeModeManager instanceof ConcreteClientModeManager)) {
1614                 return;
1615             }
1616             synchronized (mLock) {
1617                 ConcreteClientModeManager clientModeManager =
1618                         (ConcreteClientModeManager) activeModeManager;
1619                 mIfaceToRoleMap.put(clientModeManager.getInterfaceName(),
1620                         clientModeManager.getRole());
1621             }
1622         }
1623 
1624         @Override
onActiveModeManagerRemoved(@onNull ActiveModeManager activeModeManager)1625         public void onActiveModeManagerRemoved(@NonNull ActiveModeManager activeModeManager) {
1626             if (!(activeModeManager instanceof ConcreteClientModeManager)) {
1627                 return;
1628             }
1629             synchronized (mLock) {
1630                 ConcreteClientModeManager clientModeManager =
1631                         (ConcreteClientModeManager) activeModeManager;
1632                 mIfaceToRoleMap.remove(clientModeManager.getInterfaceName());
1633             }
1634         }
1635 
1636         @Override
onActiveModeManagerRoleChanged(@onNull ActiveModeManager activeModeManager)1637         public void onActiveModeManagerRoleChanged(@NonNull ActiveModeManager activeModeManager) {
1638             if (!(activeModeManager instanceof ConcreteClientModeManager)) {
1639                 return;
1640             }
1641             synchronized (mLock) {
1642                 ConcreteClientModeManager clientModeManager =
1643                         (ConcreteClientModeManager) activeModeManager;
1644                 mIfaceToRoleMap.put(clientModeManager.getInterfaceName(),
1645                         clientModeManager.getRole());
1646             }
1647         }
1648     }
1649 
1650     /**
1651      * Increment cumulative counters for link layer stats.
1652      * @param newStats
1653      */
incrementWifiLinkLayerUsageStats(String ifaceName, WifiLinkLayerStats newStats)1654     public void incrementWifiLinkLayerUsageStats(String ifaceName, WifiLinkLayerStats newStats) {
1655         // This is only collected for primary STA currently because RSSI polling is disabled for
1656         // non-primary STAs.
1657         if (!isPrimary(ifaceName)) {
1658             return;
1659         }
1660         if (newStats == null) {
1661             return;
1662         }
1663         if (mLastLinkLayerStats == null) {
1664             mLastLinkLayerStats = newStats;
1665             return;
1666         }
1667         if (!newLinkLayerStatsIsValid(mLastLinkLayerStats, newStats)) {
1668             // This could mean the radio chip is reset or the data is incorrectly reported.
1669             // Don't increment any counts and discard the possibly corrupt |newStats| completely.
1670             mLastLinkLayerStats = null;
1671             return;
1672         }
1673         mWifiLinkLayerUsageStats.loggingDurationMs +=
1674                 (newStats.timeStampInMs - mLastLinkLayerStats.timeStampInMs);
1675         mWifiLinkLayerUsageStats.radioOnTimeMs += (newStats.on_time - mLastLinkLayerStats.on_time);
1676         mWifiLinkLayerUsageStats.radioTxTimeMs += (newStats.tx_time - mLastLinkLayerStats.tx_time);
1677         mWifiLinkLayerUsageStats.radioRxTimeMs += (newStats.rx_time - mLastLinkLayerStats.rx_time);
1678         mWifiLinkLayerUsageStats.radioScanTimeMs +=
1679                 (newStats.on_time_scan - mLastLinkLayerStats.on_time_scan);
1680         mWifiLinkLayerUsageStats.radioNanScanTimeMs +=
1681                 (newStats.on_time_nan_scan - mLastLinkLayerStats.on_time_nan_scan);
1682         mWifiLinkLayerUsageStats.radioBackgroundScanTimeMs +=
1683                 (newStats.on_time_background_scan - mLastLinkLayerStats.on_time_background_scan);
1684         mWifiLinkLayerUsageStats.radioRoamScanTimeMs +=
1685                 (newStats.on_time_roam_scan - mLastLinkLayerStats.on_time_roam_scan);
1686         mWifiLinkLayerUsageStats.radioPnoScanTimeMs +=
1687                 (newStats.on_time_pno_scan - mLastLinkLayerStats.on_time_pno_scan);
1688         mWifiLinkLayerUsageStats.radioHs20ScanTimeMs +=
1689                 (newStats.on_time_hs20_scan - mLastLinkLayerStats.on_time_hs20_scan);
1690         incrementPerRadioUsageStats(mLastLinkLayerStats, newStats);
1691 
1692         mLastLinkLayerStats = newStats;
1693     }
1694 
1695     /**
1696      * Increment individual radio stats usage
1697      */
incrementPerRadioUsageStats(WifiLinkLayerStats oldStats, WifiLinkLayerStats newStats)1698     private void incrementPerRadioUsageStats(WifiLinkLayerStats oldStats,
1699             WifiLinkLayerStats newStats) {
1700         if (newStats.radioStats != null && newStats.radioStats.length > 0
1701                 && oldStats.radioStats != null && oldStats.radioStats.length > 0
1702                 && newStats.radioStats.length == oldStats.radioStats.length) {
1703             int numRadios = newStats.radioStats.length;
1704             for (int i = 0; i < numRadios; i++) {
1705                 WifiLinkLayerStats.RadioStat newRadio = newStats.radioStats[i];
1706                 WifiLinkLayerStats.RadioStat oldRadio = oldStats.radioStats[i];
1707                 if (newRadio.radio_id != oldRadio.radio_id) {
1708                     continue;
1709                 }
1710                 RadioStats radioStats = mRadioStats.get(newRadio.radio_id);
1711                 if (radioStats == null) {
1712                     radioStats = new RadioStats();
1713                     radioStats.radioId = newRadio.radio_id;
1714                     mRadioStats.put(newRadio.radio_id, radioStats);
1715                 }
1716                 radioStats.totalRadioOnTimeMs
1717                         += newRadio.on_time - oldRadio.on_time;
1718                 radioStats.totalRadioTxTimeMs
1719                         += newRadio.tx_time - oldRadio.tx_time;
1720                 radioStats.totalRadioRxTimeMs
1721                         += newRadio.rx_time - oldRadio.rx_time;
1722                 radioStats.totalScanTimeMs
1723                         += newRadio.on_time_scan - oldRadio.on_time_scan;
1724                 radioStats.totalNanScanTimeMs
1725                         += newRadio.on_time_nan_scan - oldRadio.on_time_nan_scan;
1726                 radioStats.totalBackgroundScanTimeMs
1727                         += newRadio.on_time_background_scan - oldRadio.on_time_background_scan;
1728                 radioStats.totalRoamScanTimeMs
1729                         += newRadio.on_time_roam_scan - oldRadio.on_time_roam_scan;
1730                 radioStats.totalPnoScanTimeMs
1731                         += newRadio.on_time_pno_scan - oldRadio.on_time_pno_scan;
1732                 radioStats.totalHotspot2ScanTimeMs
1733                         += newRadio.on_time_hs20_scan - oldRadio.on_time_hs20_scan;
1734             }
1735         }
1736     }
1737 
newLinkLayerStatsIsValid(WifiLinkLayerStats oldStats, WifiLinkLayerStats newStats)1738     private boolean newLinkLayerStatsIsValid(WifiLinkLayerStats oldStats,
1739             WifiLinkLayerStats newStats) {
1740         if (newStats.on_time < oldStats.on_time
1741                 || newStats.tx_time < oldStats.tx_time
1742                 || newStats.rx_time < oldStats.rx_time
1743                 || newStats.on_time_scan < oldStats.on_time_scan) {
1744             return false;
1745         }
1746         return true;
1747     }
1748 
1749     /**
1750      * Increment total number of attempts to start a pno scan
1751      */
incrementPnoScanStartAttemptCount()1752     public void incrementPnoScanStartAttemptCount() {
1753         synchronized (mLock) {
1754             mPnoScanMetrics.numPnoScanAttempts++;
1755         }
1756     }
1757 
1758     /**
1759      * Increment total number of attempts with pno scan failed
1760      */
incrementPnoScanFailedCount()1761     public void incrementPnoScanFailedCount() {
1762         synchronized (mLock) {
1763             mPnoScanMetrics.numPnoScanFailed++;
1764         }
1765     }
1766 
1767     /**
1768      * Increment number of times pno scan found a result
1769      */
incrementPnoFoundNetworkEventCount()1770     public void incrementPnoFoundNetworkEventCount() {
1771         synchronized (mLock) {
1772             mPnoScanMetrics.numPnoFoundNetworkEvents++;
1773         }
1774     }
1775 
1776     // Values used for indexing SystemStateEntries
1777     private static final int SCREEN_ON = 1;
1778     private static final int SCREEN_OFF = 0;
1779 
1780     /**
1781      * Create a new connection event and check if the new one overlaps with previous one.
1782      * Call when wifi attempts to make a new network connection
1783      * If there is a current 'un-ended' connection event, it will be ended with UNKNOWN connectivity
1784      * failure code.
1785      * Gathers and sets the RouterFingerPrint data as well
1786      *
1787      * @param ifaceName interface name for this connection event
1788      * @param config WifiConfiguration of the config used for the current connection attempt
1789      * @param roamType Roam type that caused connection attempt, see WifiMetricsProto.WifiLog.ROAM_X
1790      * @return The duration in ms since the last unfinished connection attempt,
1791      * or 0 if there is no unfinished connection
1792      */
startConnectionEvent( String ifaceName, WifiConfiguration config, String targetBSSID, int roamType)1793     public int startConnectionEvent(
1794             String ifaceName, WifiConfiguration config, String targetBSSID, int roamType) {
1795         synchronized (mLock) {
1796             int overlapWithLastConnectionMs = 0;
1797             ConnectionEvent currentConnectionEvent = mCurrentConnectionEventPerIface.get(ifaceName);
1798             if (currentConnectionEvent != null) {
1799                 overlapWithLastConnectionMs = (int) (mClock.getElapsedSinceBootMillis()
1800                         - currentConnectionEvent.mConnectionEvent.startTimeSinceBootMillis);
1801                 // Is this new Connection Event the same as the current one
1802                 if (currentConnectionEvent.mConfigSsid != null
1803                         && currentConnectionEvent.mConfigBssid != null
1804                         && config != null
1805                         && currentConnectionEvent.mConfigSsid.equals(config.SSID)
1806                         && (currentConnectionEvent.mConfigBssid.equals("any")
1807                         || currentConnectionEvent.mConfigBssid.equals(targetBSSID))) {
1808                     currentConnectionEvent.mConfigBssid = targetBSSID;
1809                     // End Connection Event due to new connection attempt to the same network
1810                     endConnectionEvent(ifaceName,
1811                             ConnectionEvent.FAILURE_REDUNDANT_CONNECTION_ATTEMPT,
1812                             WifiMetricsProto.ConnectionEvent.HLF_NONE,
1813                             WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN, 0);
1814                 } else {
1815                     // End Connection Event due to new connection attempt to different network
1816                     endConnectionEvent(ifaceName,
1817                             ConnectionEvent.FAILURE_NEW_CONNECTION_ATTEMPT,
1818                             WifiMetricsProto.ConnectionEvent.HLF_NONE,
1819                             WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN, 0);
1820                 }
1821             }
1822             // If past maximum connection events, start removing the oldest
1823             while(mConnectionEventList.size() >= MAX_CONNECTION_EVENTS) {
1824                 mConnectionEventList.removeFirst();
1825             }
1826             currentConnectionEvent = new ConnectionEvent();
1827             mCurrentConnectionEventPerIface.put(ifaceName, currentConnectionEvent);
1828             currentConnectionEvent.mConnectionEvent.interfaceName = ifaceName;
1829             currentConnectionEvent.mConnectionEvent.interfaceRole = convertIfaceToEnum(ifaceName);
1830             currentConnectionEvent.mConnectionEvent.startTimeMillis =
1831                     mClock.getWallClockMillis();
1832             currentConnectionEvent.mConnectionEvent.startTimeSinceBootMillis =
1833                     mClock.getElapsedSinceBootMillis();
1834             currentConnectionEvent.mConfigBssid = targetBSSID;
1835             currentConnectionEvent.mConnectionEvent.roamType = roamType;
1836             currentConnectionEvent.mConnectionEvent.networkSelectorExperimentId =
1837                     mNetworkSelectorExperimentId;
1838             currentConnectionEvent.updateFromWifiConfiguration(config);
1839             currentConnectionEvent.mConfigBssid = "any";
1840             currentConnectionEvent.mWifiState = mWifiState;
1841             currentConnectionEvent.mScreenOn = mScreenOn;
1842             currentConnectionEvent.mConnectionEvent.isFirstConnectionAfterBoot =
1843                     mFirstConnectionAfterBoot;
1844             mFirstConnectionAfterBoot = false;
1845             mConnectionEventList.add(currentConnectionEvent);
1846             mScanResultRssiTimestampMillis = -1;
1847             if (config != null) {
1848                 try {
1849                     currentConnectionEvent.mAuthType = config.getAuthType();
1850                 } catch (IllegalStateException e) {
1851                     currentConnectionEvent.mAuthType = 0;
1852                 }
1853                 currentConnectionEvent.mHasEverConnected =
1854                         config.getNetworkSelectionStatus().hasEverConnected();
1855                 currentConnectionEvent.mConnectionEvent.useRandomizedMac =
1856                         config.macRandomizationSetting
1857                         != WifiConfiguration.RANDOMIZATION_NONE;
1858                 currentConnectionEvent.mConnectionEvent.useAggressiveMac =
1859                         mWifiConfigManager.shouldUseNonPersistentRandomization(config);
1860                 currentConnectionEvent.mConnectionEvent.connectionNominator =
1861                         mNetworkIdToNominatorId.get(config.networkId,
1862                                 WifiMetricsProto.ConnectionEvent.NOMINATOR_UNKNOWN);
1863                 currentConnectionEvent.mConnectionEvent.isCarrierMerged = config.carrierMerged;
1864 
1865                 ScanResult candidate = config.getNetworkSelectionStatus().getCandidate();
1866                 if (candidate != null) {
1867                     // Cache the RSSI of the candidate, as the connection event level is updated
1868                     // from other sources (polls, bssid_associations) and delta requires the
1869                     // scanResult rssi
1870                     mScanResultRssi = candidate.level;
1871                     mScanResultRssiTimestampMillis = mClock.getElapsedSinceBootMillis();
1872                 }
1873                 currentConnectionEvent.mConnectionEvent.numBssidInBlocklist =
1874                         mWifiBlocklistMonitor.updateAndGetNumBlockedBssidsForSsid(config.SSID);
1875                 currentConnectionEvent.mConnectionEvent.networkType =
1876                         WifiMetricsProto.ConnectionEvent.TYPE_UNKNOWN;
1877                 currentConnectionEvent.mConnectionEvent.isOsuProvisioned = false;
1878                 if (config.isPasspoint()) {
1879                     currentConnectionEvent.mConnectionEvent.networkType =
1880                             WifiMetricsProto.ConnectionEvent.TYPE_PASSPOINT;
1881                     currentConnectionEvent.mConnectionEvent.isOsuProvisioned =
1882                             !TextUtils.isEmpty(config.updateIdentifier);
1883                 } else if (WifiConfigurationUtil.isConfigForSaeNetwork(config)) {
1884                     currentConnectionEvent.mConnectionEvent.networkType =
1885                             WifiMetricsProto.ConnectionEvent.TYPE_WPA3;
1886                 } else if (WifiConfigurationUtil.isConfigForWapiPskNetwork(config)) {
1887                     currentConnectionEvent.mConnectionEvent.networkType =
1888                             WifiMetricsProto.ConnectionEvent.TYPE_WAPI;
1889                 } else if (WifiConfigurationUtil.isConfigForWapiCertNetwork(config)) {
1890                     currentConnectionEvent.mConnectionEvent.networkType =
1891                             WifiMetricsProto.ConnectionEvent.TYPE_WAPI;
1892                 } else if (WifiConfigurationUtil.isConfigForPskNetwork(config)) {
1893                     currentConnectionEvent.mConnectionEvent.networkType =
1894                             WifiMetricsProto.ConnectionEvent.TYPE_WPA2;
1895                 } else if (WifiConfigurationUtil.isConfigForEapNetwork(config)) {
1896                     currentConnectionEvent.mConnectionEvent.networkType =
1897                             WifiMetricsProto.ConnectionEvent.TYPE_EAP;
1898                 } else if (WifiConfigurationUtil.isConfigForOweNetwork(config)) {
1899                     currentConnectionEvent.mConnectionEvent.networkType =
1900                             WifiMetricsProto.ConnectionEvent.TYPE_OWE;
1901                 } else if (WifiConfigurationUtil.isConfigForOpenNetwork(config)) {
1902                     currentConnectionEvent.mConnectionEvent.networkType =
1903                             WifiMetricsProto.ConnectionEvent.TYPE_OPEN;
1904                 }
1905 
1906                 if (!config.fromWifiNetworkSuggestion) {
1907                     currentConnectionEvent.mConnectionEvent.networkCreator =
1908                             WifiMetricsProto.ConnectionEvent.CREATOR_USER;
1909                 } else if (config.carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) {
1910                     currentConnectionEvent.mConnectionEvent.networkCreator =
1911                             WifiMetricsProto.ConnectionEvent.CREATOR_CARRIER;
1912                 } else {
1913                     currentConnectionEvent.mConnectionEvent.networkCreator =
1914                             WifiMetricsProto.ConnectionEvent.CREATOR_UNKNOWN;
1915                 }
1916 
1917                 currentConnectionEvent.mConnectionEvent.screenOn = mScreenOn;
1918                 if (currentConnectionEvent.mConfigSsid != null) {
1919                     WifiScoreCard.NetworkConnectionStats recentStats = mWifiScoreCard.lookupNetwork(
1920                             currentConnectionEvent.mConfigSsid).getRecentStats();
1921                     currentConnectionEvent.mConnectionEvent.numConsecutiveConnectionFailure =
1922                             recentStats.getCount(WifiScoreCard.CNT_CONSECUTIVE_CONNECTION_FAILURE);
1923                 }
1924 
1925                 String ssid = currentConnectionEvent.mConfigSsid;
1926                 int nominator = currentConnectionEvent.mConnectionEvent.connectionNominator;
1927                 int trigger = WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__UNKNOWN;
1928 
1929                 if (nominator == WifiMetricsProto.ConnectionEvent.NOMINATOR_MANUAL) {
1930                     trigger = WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__MANUAL;
1931                 } else if (mPreviousSession == null) {
1932                     trigger = WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__AUTOCONNECT_BOOT;
1933                 } else if (ssid != null && ssid.equals(mPreviousSession.mSsid)) {
1934                     trigger = WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__RECONNECT_SAME_NETWORK;
1935                 } else if (nominator != WifiMetricsProto.ConnectionEvent.NOMINATOR_UNKNOWN) {
1936                     trigger = WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__AUTOCONNECT_CONFIGURED_NETWORK;
1937                 }
1938                 currentConnectionEvent.mTrigger = trigger;
1939             }
1940 
1941             return overlapWithLastConnectionMs;
1942         }
1943     }
1944 
1945     /**
1946      * Set AP related metrics from ScanDetail
1947      */
setConnectionScanDetail(String ifaceName, ScanDetail scanDetail)1948     public void setConnectionScanDetail(String ifaceName, ScanDetail scanDetail) {
1949         synchronized (mLock) {
1950             ConnectionEvent currentConnectionEvent = mCurrentConnectionEventPerIface.get(ifaceName);
1951             if (currentConnectionEvent == null || scanDetail == null) {
1952                 return;
1953             }
1954             NetworkDetail networkDetail = scanDetail.getNetworkDetail();
1955             ScanResult scanResult = scanDetail.getScanResult();
1956             // Ensure that we have a networkDetail, and that it corresponds to the currently
1957             // tracked connection attempt
1958             if (networkDetail == null || scanResult == null
1959                     || currentConnectionEvent.mConfigSsid == null
1960                     || !currentConnectionEvent.mConfigSsid
1961                     .equals("\"" + networkDetail.getSSID() + "\"")) {
1962                 return;
1963             }
1964             updateMetricsFromNetworkDetail(currentConnectionEvent, networkDetail);
1965             updateMetricsFromScanResult(currentConnectionEvent, scanResult);
1966         }
1967     }
1968 
1969     /**
1970      * Set PMK cache status for a connection event
1971      */
setConnectionPmkCache(String ifaceName, boolean isEnabled)1972     public void setConnectionPmkCache(String ifaceName, boolean isEnabled) {
1973         synchronized (mLock) {
1974             ConnectionEvent currentConnectionEvent = mCurrentConnectionEventPerIface.get(ifaceName);
1975             if (currentConnectionEvent != null) {
1976                 currentConnectionEvent.mRouterFingerPrint.setPmkCache(isEnabled);
1977             }
1978         }
1979     }
1980 
1981     /**
1982      * Set the max link speed supported by current network
1983      */
setConnectionMaxSupportedLinkSpeedMbps( String ifaceName, int maxSupportedTxLinkSpeedMbps, int maxSupportedRxLinkSpeedMbps)1984     public void setConnectionMaxSupportedLinkSpeedMbps(
1985             String ifaceName, int maxSupportedTxLinkSpeedMbps, int maxSupportedRxLinkSpeedMbps) {
1986         synchronized (mLock) {
1987             ConnectionEvent currentConnectionEvent = mCurrentConnectionEventPerIface.get(ifaceName);
1988             if (currentConnectionEvent != null) {
1989                 currentConnectionEvent.mRouterFingerPrint.setMaxSupportedLinkSpeedMbps(
1990                         maxSupportedTxLinkSpeedMbps, maxSupportedRxLinkSpeedMbps);
1991             }
1992         }
1993     }
1994 
1995     /**
1996      * End a Connection event record. Call when wifi connection attempt succeeds or fails.
1997      * If a Connection event has not been started and is active when .end is called, then this
1998      * method will do nothing.
1999      *
2000      * @param ifaceName
2001      * @param level2FailureCode Level 2 failure code returned by supplicant
2002      * @param connectivityFailureCode WifiMetricsProto.ConnectionEvent.HLF_X
2003      * @param level2FailureReason Breakdown of level2FailureCode with more detailed reason
2004      */
endConnectionEvent( String ifaceName, int level2FailureCode, int connectivityFailureCode, int level2FailureReason, int frequency)2005     public void endConnectionEvent(
2006             String ifaceName,
2007             int level2FailureCode,
2008             int connectivityFailureCode,
2009             int level2FailureReason,
2010             int frequency) {
2011         synchronized (mLock) {
2012             ConnectionEvent currentConnectionEvent = mCurrentConnectionEventPerIface.get(ifaceName);
2013             if (currentConnectionEvent != null) {
2014                 boolean connectionSucceeded = (level2FailureCode == 1)
2015                         && (connectivityFailureCode == WifiMetricsProto.ConnectionEvent.HLF_NONE);
2016 
2017                 int band = KnownBandsChannelHelper.getBand(frequency);
2018                 int durationTakenToConnectMillis =
2019                         (int) (mClock.getElapsedSinceBootMillis()
2020                                 - currentConnectionEvent.mConnectionEvent.startTimeSinceBootMillis);
2021 
2022                 if (connectionSucceeded) {
2023                     mCurrentSession = new SessionData(currentConnectionEvent.mConfigSsid,
2024                             mClock.getElapsedSinceBootMillis(),
2025                             band, currentConnectionEvent.mAuthType);
2026 
2027                     // TODO(b/166309727) need to add ifaceName to WifiStatsLog
2028                     WifiStatsLog.write(WifiStatsLog.WIFI_CONNECTION_STATE_CHANGED,
2029                             true, band, currentConnectionEvent.mAuthType);
2030                 }
2031 
2032                 currentConnectionEvent.mConnectionEvent.connectionResult =
2033                         connectionSucceeded ? 1 : 0;
2034                 currentConnectionEvent.mConnectionEvent.durationTakenToConnectMillis =
2035                         durationTakenToConnectMillis;
2036                 currentConnectionEvent.mConnectionEvent.level2FailureCode = level2FailureCode;
2037                 currentConnectionEvent.mConnectionEvent.connectivityLevelFailureCode =
2038                         connectivityFailureCode;
2039                 currentConnectionEvent.mConnectionEvent.level2FailureReason = level2FailureReason;
2040 
2041                 // Write metrics to statsd
2042                 int wwFailureCode = getConnectionResultFailureCode(level2FailureCode,
2043                         level2FailureReason);
2044 
2045                 if (wwFailureCode != -1) {
2046                     int timeSinceConnectedSeconds = (int) ((mPreviousSession != null ?
2047                             (mClock.getElapsedSinceBootMillis()
2048                                     - mPreviousSession.mSessionEndTimeMillis) :
2049                             mClock.getElapsedSinceBootMillis()) / 1000);
2050 
2051                     WifiStatsLog.write(WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED,
2052                             connectionSucceeded,
2053                             wwFailureCode, currentConnectionEvent.mConnectionEvent.signalStrength,
2054                             durationTakenToConnectMillis, band, currentConnectionEvent.mAuthType,
2055                             currentConnectionEvent.mTrigger,
2056                             currentConnectionEvent.mHasEverConnected,
2057                             timeSinceConnectedSeconds
2058                     );
2059                 }
2060 
2061                 // ConnectionEvent already added to ConnectionEvents List. Safe to remove here.
2062                 mCurrentConnectionEventPerIface.remove(ifaceName);
2063                 if (!connectionSucceeded) {
2064                     mScanResultRssiTimestampMillis = -1;
2065                 }
2066                 mWifiStatusBuilder.setConnected(connectionSucceeded);
2067             }
2068         }
2069     }
2070 
2071     /**
2072      * Report that an active Wifi network connection was dropped.
2073      *
2074      * @param disconnectReason Error code for the disconnect.
2075      * @param rssi Last seen RSSI.
2076      * @param linkSpeed Last seen link speed.
2077      */
reportNetworkDisconnect(String ifaceName, int disconnectReason, int rssi, int linkSpeed)2078     public void reportNetworkDisconnect(String ifaceName, int disconnectReason, int rssi,
2079             int linkSpeed) {
2080         synchronized (mLock) {
2081             if (!isPrimary(ifaceName)) {
2082                 return;
2083             }
2084             WifiStatsLog.write(WifiStatsLog.WIFI_CONNECTION_STATE_CHANGED,
2085                     false,
2086                     mCurrentSession != null ? mCurrentSession.mBand : 0,
2087                     mCurrentSession != null ? mCurrentSession.mAuthType : 0);
2088 
2089             if (mCurrentSession != null) {
2090                 mCurrentSession.mSessionEndTimeMillis = mClock.getElapsedSinceBootMillis();
2091                 int durationSeconds = (int) (mCurrentSession.mSessionEndTimeMillis
2092                         - mCurrentSession.mSessionStartTimeMillis) / 1000;
2093 
2094                 WifiStatsLog.write(WifiStatsLog.WIFI_DISCONNECT_REPORTED,
2095                         durationSeconds,
2096                         disconnectReason,
2097                         mCurrentSession.mBand,
2098                         mCurrentSession.mAuthType,
2099                         rssi,
2100                         linkSpeed);
2101 
2102                 mPreviousSession = mCurrentSession;
2103                 mCurrentSession = null;
2104             }
2105         }
2106     }
2107 
getConnectionResultFailureCode(int level2FailureCode, int level2FailureReason)2108     private int getConnectionResultFailureCode(int level2FailureCode, int level2FailureReason) {
2109         switch (level2FailureCode) {
2110             case ConnectionEvent.FAILURE_NONE:
2111                 return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_UNKNOWN;
2112             case ConnectionEvent.FAILURE_ASSOCIATION_TIMED_OUT:
2113                 return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_ASSOCIATION_TIMEOUT;
2114             case ConnectionEvent.FAILURE_ASSOCIATION_REJECTION:
2115                 return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_ASSOCIATION_REJECTION;
2116             case ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE:
2117                 switch (level2FailureReason) {
2118                     case WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_EAP_FAILURE:
2119                         return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_AUTHENTICATION_EAP;
2120                     case WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_WRONG_PSWD:
2121                         return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_WRONG_PASSWORD;
2122                     default:
2123                         return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_AUTHENTICATION_GENERAL;
2124                 }
2125             case ConnectionEvent.FAILURE_DHCP:
2126                 return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_DHCP;
2127             case ConnectionEvent.FAILURE_NETWORK_DISCONNECTION:
2128                 return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_NETWORK_DISCONNECTION;
2129             case ConnectionEvent.FAILURE_ROAM_TIMEOUT:
2130                 return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_ROAM_TIMEOUT;
2131             case ConnectionEvent.FAILURE_NEW_CONNECTION_ATTEMPT:
2132             case ConnectionEvent.FAILURE_REDUNDANT_CONNECTION_ATTEMPT:
2133                 return -1;
2134             default:
2135                 return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_UNKNOWN;
2136         }
2137     }
2138 
2139     /**
2140      * Set ConnectionEvent DTIM Interval (if set), and 802.11 Connection mode, from NetworkDetail
2141      */
updateMetricsFromNetworkDetail( ConnectionEvent currentConnectionEvent, NetworkDetail networkDetail)2142     private void updateMetricsFromNetworkDetail(
2143             ConnectionEvent currentConnectionEvent, NetworkDetail networkDetail) {
2144         int dtimInterval = networkDetail.getDtimInterval();
2145         if (dtimInterval > 0) {
2146             currentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.dtim =
2147                     dtimInterval;
2148         }
2149         final int connectionWifiMode;
2150         switch (networkDetail.getWifiMode()) {
2151             case InformationElementUtil.WifiMode.MODE_UNDEFINED:
2152                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_UNKNOWN;
2153                 break;
2154             case InformationElementUtil.WifiMode.MODE_11A:
2155                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_A;
2156                 break;
2157             case InformationElementUtil.WifiMode.MODE_11B:
2158                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_B;
2159                 break;
2160             case InformationElementUtil.WifiMode.MODE_11G:
2161                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_G;
2162                 break;
2163             case InformationElementUtil.WifiMode.MODE_11N:
2164                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_N;
2165                 break;
2166             case InformationElementUtil.WifiMode.MODE_11AC  :
2167                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_AC;
2168                 break;
2169             case InformationElementUtil.WifiMode.MODE_11AX  :
2170                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_AX;
2171                 break;
2172             default:
2173                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_OTHER;
2174                 break;
2175         }
2176         currentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.routerTechnology =
2177                 connectionWifiMode;
2178 
2179         if (networkDetail.isMboSupported()) {
2180             mWifiLogProto.numConnectToNetworkSupportingMbo++;
2181             if (networkDetail.isOceSupported()) {
2182                 mWifiLogProto.numConnectToNetworkSupportingOce++;
2183             }
2184         }
2185     }
2186 
2187     /**
2188      * Set ConnectionEvent RSSI and authentication type from ScanResult
2189      */
updateMetricsFromScanResult( ConnectionEvent currentConnectionEvent, ScanResult scanResult)2190     private void updateMetricsFromScanResult(
2191             ConnectionEvent currentConnectionEvent, ScanResult scanResult) {
2192         currentConnectionEvent.mConnectionEvent.signalStrength = scanResult.level;
2193         currentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
2194                 WifiMetricsProto.RouterFingerPrint.AUTH_OPEN;
2195         currentConnectionEvent.mConfigBssid = scanResult.BSSID;
2196         if (scanResult.capabilities != null) {
2197             if (ScanResultUtil.isScanResultForWepNetwork(scanResult)) {
2198                 currentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
2199                         WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL;
2200             } else if (ScanResultUtil.isScanResultForPskNetwork(scanResult)
2201                     || ScanResultUtil.isScanResultForSaeNetwork(scanResult)) {
2202                 currentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
2203                         WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL;
2204             } else if (ScanResultUtil.isScanResultForWpa3EnterpriseTransitionNetwork(scanResult)
2205                     || ScanResultUtil.isScanResultForWpa3EnterpriseOnlyNetwork(scanResult)
2206                     || ScanResultUtil.isScanResultForEapNetwork(scanResult)
2207                     || ScanResultUtil.isScanResultForEapSuiteBNetwork(scanResult)) {
2208                 currentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
2209                         WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE;
2210             }
2211         }
2212         currentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.channelInfo =
2213                 scanResult.frequency;
2214     }
2215 
setIsLocationEnabled(boolean enabled)2216     void setIsLocationEnabled(boolean enabled) {
2217         synchronized (mLock) {
2218             mWifiLogProto.isLocationEnabled = enabled;
2219         }
2220     }
2221 
setIsScanningAlwaysEnabled(boolean enabled)2222     void setIsScanningAlwaysEnabled(boolean enabled) {
2223         synchronized (mLock) {
2224             mWifiLogProto.isScanningAlwaysEnabled = enabled;
2225         }
2226     }
2227 
2228     /**
2229      * Developer options toggle value for verbose logging.
2230      */
setVerboseLoggingEnabled(boolean enabled)2231     public void setVerboseLoggingEnabled(boolean enabled) {
2232         synchronized (mLock) {
2233             mWifiLogProto.isVerboseLoggingEnabled = enabled;
2234         }
2235     }
2236 
2237     /**
2238      * Developer options toggle value for non-persistent MAC randomization.
2239      */
setNonPersistentMacRandomizationForceEnabled(boolean enabled)2240     public void setNonPersistentMacRandomizationForceEnabled(boolean enabled) {
2241         synchronized (mLock) {
2242             mWifiLogProto.isEnhancedMacRandomizationForceEnabled = enabled;
2243         }
2244     }
2245 
2246     /**
2247      * Wifi wake feature toggle.
2248      */
setWifiWakeEnabled(boolean enabled)2249     public void setWifiWakeEnabled(boolean enabled) {
2250         synchronized (mLock) {
2251             mWifiLogProto.isWifiWakeEnabled = enabled;
2252         }
2253     }
2254 
2255     /**
2256      * Increment Non Empty Scan Results count
2257      */
incrementNonEmptyScanResultCount()2258     public void incrementNonEmptyScanResultCount() {
2259         if (DBG) Log.v(TAG, "incrementNonEmptyScanResultCount");
2260         synchronized (mLock) {
2261             mWifiLogProto.numNonEmptyScanResults++;
2262         }
2263     }
2264 
2265     /**
2266      * Increment Empty Scan Results count
2267      */
incrementEmptyScanResultCount()2268     public void incrementEmptyScanResultCount() {
2269         if (DBG) Log.v(TAG, "incrementEmptyScanResultCount");
2270         synchronized (mLock) {
2271             mWifiLogProto.numEmptyScanResults++;
2272         }
2273     }
2274 
2275     /**
2276      * Increment background scan count
2277      */
incrementBackgroundScanCount()2278     public void incrementBackgroundScanCount() {
2279         if (DBG) Log.v(TAG, "incrementBackgroundScanCount");
2280         synchronized (mLock) {
2281             mWifiLogProto.numBackgroundScans++;
2282         }
2283     }
2284 
2285     /**
2286      * Get Background scan count
2287      */
getBackgroundScanCount()2288     public int getBackgroundScanCount() {
2289         synchronized (mLock) {
2290             return mWifiLogProto.numBackgroundScans;
2291         }
2292     }
2293 
2294     /**
2295      * Increment oneshot scan count, and the associated WifiSystemScanStateCount entry
2296      */
incrementOneshotScanCount()2297     public void incrementOneshotScanCount() {
2298         synchronized (mLock) {
2299             mWifiLogProto.numOneshotScans++;
2300         }
2301         incrementWifiSystemScanStateCount(mWifiState, mScreenOn);
2302     }
2303 
2304     /**
2305      * Increment the count of oneshot scans that include DFS channels.
2306      */
incrementOneshotScanWithDfsCount()2307     public void incrementOneshotScanWithDfsCount() {
2308         synchronized (mLock) {
2309             mWifiLogProto.numOneshotHasDfsChannelScans++;
2310         }
2311     }
2312 
2313     /**
2314      * Increment connectivity oneshot scan count.
2315      */
incrementConnectivityOneshotScanCount()2316     public void incrementConnectivityOneshotScanCount() {
2317         synchronized (mLock) {
2318             mWifiLogProto.numConnectivityOneshotScans++;
2319         }
2320     }
2321 
2322     /**
2323      * Get oneshot scan count
2324      */
getOneshotScanCount()2325     public int getOneshotScanCount() {
2326         synchronized (mLock) {
2327             return mWifiLogProto.numOneshotScans;
2328         }
2329     }
2330 
2331     /**
2332      * Get connectivity oneshot scan count
2333      */
getConnectivityOneshotScanCount()2334     public int getConnectivityOneshotScanCount() {
2335         synchronized (mLock) {
2336             return mWifiLogProto.numConnectivityOneshotScans;
2337         }
2338     }
2339 
2340     /**
2341      * Get the count of oneshot scan requests that included DFS channels.
2342      */
getOneshotScanWithDfsCount()2343     public int getOneshotScanWithDfsCount() {
2344         synchronized (mLock) {
2345             return mWifiLogProto.numOneshotHasDfsChannelScans;
2346         }
2347     }
2348 
2349     /**
2350      * Increment oneshot scan count for external apps.
2351      */
incrementExternalAppOneshotScanRequestsCount()2352     public void incrementExternalAppOneshotScanRequestsCount() {
2353         synchronized (mLock) {
2354             mWifiLogProto.numExternalAppOneshotScanRequests++;
2355         }
2356     }
2357     /**
2358      * Increment oneshot scan throttle count for external foreground apps.
2359      */
incrementExternalForegroundAppOneshotScanRequestsThrottledCount()2360     public void incrementExternalForegroundAppOneshotScanRequestsThrottledCount() {
2361         synchronized (mLock) {
2362             mWifiLogProto.numExternalForegroundAppOneshotScanRequestsThrottled++;
2363         }
2364     }
2365 
2366     /**
2367      * Increment oneshot scan throttle count for external background apps.
2368      */
incrementExternalBackgroundAppOneshotScanRequestsThrottledCount()2369     public void incrementExternalBackgroundAppOneshotScanRequestsThrottledCount() {
2370         synchronized (mLock) {
2371             mWifiLogProto.numExternalBackgroundAppOneshotScanRequestsThrottled++;
2372         }
2373     }
2374 
returnCodeToString(int scanReturnCode)2375     private String returnCodeToString(int scanReturnCode) {
2376         switch(scanReturnCode){
2377             case WifiMetricsProto.WifiLog.SCAN_UNKNOWN:
2378                 return "SCAN_UNKNOWN";
2379             case WifiMetricsProto.WifiLog.SCAN_SUCCESS:
2380                 return "SCAN_SUCCESS";
2381             case WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED:
2382                 return "SCAN_FAILURE_INTERRUPTED";
2383             case WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION:
2384                 return "SCAN_FAILURE_INVALID_CONFIGURATION";
2385             case WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED:
2386                 return "FAILURE_WIFI_DISABLED";
2387             default:
2388                 return "<UNKNOWN>";
2389         }
2390     }
2391 
2392     /**
2393      * Increment count of scan return code occurrence
2394      *
2395      * @param scanReturnCode Return code from scan attempt WifiMetricsProto.WifiLog.SCAN_X
2396      */
incrementScanReturnEntry(int scanReturnCode, int countToAdd)2397     public void incrementScanReturnEntry(int scanReturnCode, int countToAdd) {
2398         synchronized (mLock) {
2399             if (DBG) Log.v(TAG, "incrementScanReturnEntry " + returnCodeToString(scanReturnCode));
2400             int entry = mScanReturnEntries.get(scanReturnCode);
2401             entry += countToAdd;
2402             mScanReturnEntries.put(scanReturnCode, entry);
2403         }
2404     }
2405     /**
2406      * Get the count of this scanReturnCode
2407      * @param scanReturnCode that we are getting the count for
2408      */
getScanReturnEntry(int scanReturnCode)2409     public int getScanReturnEntry(int scanReturnCode) {
2410         synchronized (mLock) {
2411             return mScanReturnEntries.get(scanReturnCode);
2412         }
2413     }
2414 
wifiSystemStateToString(int state)2415     private String wifiSystemStateToString(int state) {
2416         switch(state){
2417             case WifiMetricsProto.WifiLog.WIFI_UNKNOWN:
2418                 return "WIFI_UNKNOWN";
2419             case WifiMetricsProto.WifiLog.WIFI_DISABLED:
2420                 return "WIFI_DISABLED";
2421             case WifiMetricsProto.WifiLog.WIFI_DISCONNECTED:
2422                 return "WIFI_DISCONNECTED";
2423             case WifiMetricsProto.WifiLog.WIFI_ASSOCIATED:
2424                 return "WIFI_ASSOCIATED";
2425             default:
2426                 return "default";
2427         }
2428     }
2429 
2430     /**
2431      * Increments the count of scans initiated by each wifi state, accounts for screenOn/Off
2432      *
2433      * @param state State of the system when scan was initiated, see WifiMetricsProto.WifiLog.WIFI_X
2434      * @param screenOn Is the screen on
2435      */
incrementWifiSystemScanStateCount(int state, boolean screenOn)2436     public void incrementWifiSystemScanStateCount(int state, boolean screenOn) {
2437         synchronized (mLock) {
2438             if (DBG) {
2439                 Log.v(TAG, "incrementWifiSystemScanStateCount " + wifiSystemStateToString(state)
2440                         + " " + screenOn);
2441             }
2442             int index = (state * 2) + (screenOn ? SCREEN_ON : SCREEN_OFF);
2443             int entry = mWifiSystemStateEntries.get(index);
2444             entry++;
2445             mWifiSystemStateEntries.put(index, entry);
2446         }
2447     }
2448 
2449     /**
2450      * Get the count of this system State Entry
2451      */
getSystemStateCount(int state, boolean screenOn)2452     public int getSystemStateCount(int state, boolean screenOn) {
2453         synchronized (mLock) {
2454             int index = state * 2 + (screenOn ? SCREEN_ON : SCREEN_OFF);
2455             return mWifiSystemStateEntries.get(index);
2456         }
2457     }
2458 
2459     /**
2460      * Increment number of times the Watchdog of Last Resort triggered, resetting the wifi stack
2461      */
incrementNumLastResortWatchdogTriggers()2462     public void incrementNumLastResortWatchdogTriggers() {
2463         synchronized (mLock) {
2464             mWifiLogProto.numLastResortWatchdogTriggers++;
2465         }
2466     }
2467     /**
2468      * @param count number of networks over bad association threshold when watchdog triggered
2469      */
addCountToNumLastResortWatchdogBadAssociationNetworksTotal(int count)2470     public void addCountToNumLastResortWatchdogBadAssociationNetworksTotal(int count) {
2471         synchronized (mLock) {
2472             mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal += count;
2473         }
2474     }
2475     /**
2476      * @param count number of networks over bad authentication threshold when watchdog triggered
2477      */
addCountToNumLastResortWatchdogBadAuthenticationNetworksTotal(int count)2478     public void addCountToNumLastResortWatchdogBadAuthenticationNetworksTotal(int count) {
2479         synchronized (mLock) {
2480             mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal += count;
2481         }
2482     }
2483     /**
2484      * @param count number of networks over bad dhcp threshold when watchdog triggered
2485      */
addCountToNumLastResortWatchdogBadDhcpNetworksTotal(int count)2486     public void addCountToNumLastResortWatchdogBadDhcpNetworksTotal(int count) {
2487         synchronized (mLock) {
2488             mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal += count;
2489         }
2490     }
2491     /**
2492      * @param count number of networks over bad other threshold when watchdog triggered
2493      */
addCountToNumLastResortWatchdogBadOtherNetworksTotal(int count)2494     public void addCountToNumLastResortWatchdogBadOtherNetworksTotal(int count) {
2495         synchronized (mLock) {
2496             mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal += count;
2497         }
2498     }
2499     /**
2500      * @param count number of networks seen when watchdog triggered
2501      */
addCountToNumLastResortWatchdogAvailableNetworksTotal(int count)2502     public void addCountToNumLastResortWatchdogAvailableNetworksTotal(int count) {
2503         synchronized (mLock) {
2504             mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal += count;
2505         }
2506     }
2507     /**
2508      * Increment count of triggers with atleast one bad association network
2509      */
incrementNumLastResortWatchdogTriggersWithBadAssociation()2510     public void incrementNumLastResortWatchdogTriggersWithBadAssociation() {
2511         synchronized (mLock) {
2512             mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation++;
2513         }
2514     }
2515     /**
2516      * Increment count of triggers with atleast one bad authentication network
2517      */
incrementNumLastResortWatchdogTriggersWithBadAuthentication()2518     public void incrementNumLastResortWatchdogTriggersWithBadAuthentication() {
2519         synchronized (mLock) {
2520             mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication++;
2521         }
2522     }
2523     /**
2524      * Increment count of triggers with atleast one bad dhcp network
2525      */
incrementNumLastResortWatchdogTriggersWithBadDhcp()2526     public void incrementNumLastResortWatchdogTriggersWithBadDhcp() {
2527         synchronized (mLock) {
2528             mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp++;
2529         }
2530     }
2531     /**
2532      * Increment count of triggers with atleast one bad other network
2533      */
incrementNumLastResortWatchdogTriggersWithBadOther()2534     public void incrementNumLastResortWatchdogTriggersWithBadOther() {
2535         synchronized (mLock) {
2536             mWifiLogProto.numLastResortWatchdogTriggersWithBadOther++;
2537         }
2538     }
2539 
2540     /**
2541      * Increment number of times connectivity watchdog confirmed pno is working
2542      */
incrementNumConnectivityWatchdogPnoGood()2543     public void incrementNumConnectivityWatchdogPnoGood() {
2544         synchronized (mLock) {
2545             mWifiLogProto.numConnectivityWatchdogPnoGood++;
2546         }
2547     }
2548     /**
2549      * Increment number of times connectivity watchdog found pno not working
2550      */
incrementNumConnectivityWatchdogPnoBad()2551     public void incrementNumConnectivityWatchdogPnoBad() {
2552         synchronized (mLock) {
2553             mWifiLogProto.numConnectivityWatchdogPnoBad++;
2554         }
2555     }
2556     /**
2557      * Increment number of times connectivity watchdog confirmed background scan is working
2558      */
incrementNumConnectivityWatchdogBackgroundGood()2559     public void incrementNumConnectivityWatchdogBackgroundGood() {
2560         synchronized (mLock) {
2561             mWifiLogProto.numConnectivityWatchdogBackgroundGood++;
2562         }
2563     }
2564     /**
2565      * Increment number of times connectivity watchdog found background scan not working
2566      */
incrementNumConnectivityWatchdogBackgroundBad()2567     public void incrementNumConnectivityWatchdogBackgroundBad() {
2568         synchronized (mLock) {
2569             mWifiLogProto.numConnectivityWatchdogBackgroundBad++;
2570         }
2571     }
2572 
2573     /**
2574      * Increment various poll related metrics, and cache performance data for StaEvent logging
2575      */
handlePollResult(String ifaceName, WifiInfo wifiInfo)2576     public void handlePollResult(String ifaceName, WifiInfo wifiInfo) {
2577         if (!isPrimary(ifaceName)) {
2578             return;
2579         }
2580         mLastPollRssi = wifiInfo.getRssi();
2581         mLastPollLinkSpeed = wifiInfo.getLinkSpeed();
2582         mLastPollFreq = wifiInfo.getFrequency();
2583         incrementRssiPollRssiCount(mLastPollFreq, mLastPollRssi);
2584         incrementLinkSpeedCount(mLastPollLinkSpeed, mLastPollRssi);
2585         mLastPollRxLinkSpeed = wifiInfo.getRxLinkSpeedMbps();
2586         incrementTxLinkSpeedBandCount(mLastPollLinkSpeed, mLastPollFreq);
2587         incrementRxLinkSpeedBandCount(mLastPollRxLinkSpeed, mLastPollFreq);
2588         mWifiStatusBuilder.setRssi(mLastPollRssi);
2589         mWifiStatusBuilder.setNetworkId(wifiInfo.getNetworkId());
2590     }
2591 
2592     /**
2593      * Increment occurence count of RSSI level from RSSI poll for the given frequency.
2594      * @param frequency (MHz)
2595      * @param rssi
2596      */
2597     @VisibleForTesting
incrementRssiPollRssiCount(int frequency, int rssi)2598     public void incrementRssiPollRssiCount(int frequency, int rssi) {
2599         if (!(rssi >= MIN_RSSI_POLL && rssi <= MAX_RSSI_POLL)) {
2600             return;
2601         }
2602         synchronized (mLock) {
2603             if (!mRssiPollCountsMap.containsKey(frequency)) {
2604                 mRssiPollCountsMap.put(frequency, new SparseIntArray());
2605             }
2606             SparseIntArray sparseIntArray = mRssiPollCountsMap.get(frequency);
2607             int count = sparseIntArray.get(rssi);
2608             sparseIntArray.put(rssi, count + 1);
2609             maybeIncrementRssiDeltaCount(rssi - mScanResultRssi);
2610         }
2611     }
2612 
2613     /**
2614      * Increment occurence count of difference between scan result RSSI and the first RSSI poll.
2615      * Ignores rssi values outside the bounds of [MIN_RSSI_DELTA, MAX_RSSI_DELTA]
2616      * mLock must be held when calling this method.
2617      */
maybeIncrementRssiDeltaCount(int rssi)2618     private void maybeIncrementRssiDeltaCount(int rssi) {
2619         // Check if this RSSI poll is close enough to a scan result RSSI to log a delta value
2620         if (mScanResultRssiTimestampMillis >= 0) {
2621             long timeDelta = mClock.getElapsedSinceBootMillis() - mScanResultRssiTimestampMillis;
2622             if (timeDelta <= TIMEOUT_RSSI_DELTA_MILLIS) {
2623                 if (rssi >= MIN_RSSI_DELTA && rssi <= MAX_RSSI_DELTA) {
2624                     int count = mRssiDeltaCounts.get(rssi);
2625                     mRssiDeltaCounts.put(rssi, count + 1);
2626                 }
2627             }
2628             mScanResultRssiTimestampMillis = -1;
2629         }
2630     }
2631 
2632     /**
2633      * Increment occurrence count of link speed.
2634      * Ignores link speed values that are lower than MIN_LINK_SPEED_MBPS
2635      * and rssi values outside the bounds of [MIN_RSSI_POLL, MAX_RSSI_POLL]
2636      */
2637     @VisibleForTesting
incrementLinkSpeedCount(int linkSpeed, int rssi)2638     public void incrementLinkSpeedCount(int linkSpeed, int rssi) {
2639         if (!(mContext.getResources().getBoolean(R.bool.config_wifiLinkSpeedMetricsEnabled)
2640                 && linkSpeed >= MIN_LINK_SPEED_MBPS
2641                 && rssi >= MIN_RSSI_POLL
2642                 && rssi <= MAX_RSSI_POLL)) {
2643             return;
2644         }
2645         synchronized (mLock) {
2646             LinkSpeedCount linkSpeedCount = mLinkSpeedCounts.get(linkSpeed);
2647             if (linkSpeedCount == null) {
2648                 linkSpeedCount = new LinkSpeedCount();
2649                 linkSpeedCount.linkSpeedMbps = linkSpeed;
2650                 mLinkSpeedCounts.put(linkSpeed, linkSpeedCount);
2651             }
2652             linkSpeedCount.count++;
2653             linkSpeedCount.rssiSumDbm += Math.abs(rssi);
2654             linkSpeedCount.rssiSumOfSquaresDbmSq += rssi * rssi;
2655         }
2656     }
2657 
2658     /**
2659      * Increment occurrence count of Tx link speed for operating sub-band
2660      * Ignores link speed values that are lower than MIN_LINK_SPEED_MBPS
2661      * @param txLinkSpeed PHY layer Tx link speed in Mbps
2662      * @param frequency Channel frequency of beacon frames in MHz
2663      */
2664     @VisibleForTesting
incrementTxLinkSpeedBandCount(int txLinkSpeed, int frequency)2665     public void incrementTxLinkSpeedBandCount(int txLinkSpeed, int frequency) {
2666         if (!(mContext.getResources().getBoolean(R.bool.config_wifiLinkSpeedMetricsEnabled)
2667                 && txLinkSpeed >= MIN_LINK_SPEED_MBPS)) {
2668             return;
2669         }
2670         synchronized (mLock) {
2671             if (ScanResult.is24GHz(frequency)) {
2672                 mTxLinkSpeedCount2g.increment(txLinkSpeed);
2673             } else if (frequency <= KnownBandsChannelHelper.BAND_5_GHZ_LOW_END_FREQ) {
2674                 mTxLinkSpeedCount5gLow.increment(txLinkSpeed);
2675             } else if (frequency <= KnownBandsChannelHelper.BAND_5_GHZ_MID_END_FREQ) {
2676                 mTxLinkSpeedCount5gMid.increment(txLinkSpeed);
2677             } else if (frequency <= KnownBandsChannelHelper.BAND_5_GHZ_HIGH_END_FREQ) {
2678                 mTxLinkSpeedCount5gHigh.increment(txLinkSpeed);
2679             } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_LOW_END_FREQ) {
2680                 mTxLinkSpeedCount6gLow.increment(txLinkSpeed);
2681             } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_MID_END_FREQ) {
2682                 mTxLinkSpeedCount6gMid.increment(txLinkSpeed);
2683             } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_HIGH_END_FREQ) {
2684                 mTxLinkSpeedCount6gHigh.increment(txLinkSpeed);
2685             }
2686         }
2687     }
2688 
2689     /**
2690      * Increment occurrence count of Rx link speed for operating sub-band
2691      * Ignores link speed values that are lower than MIN_LINK_SPEED_MBPS
2692      * @param rxLinkSpeed PHY layer Tx link speed in Mbps
2693      * @param frequency Channel frequency of beacon frames in MHz
2694      */
2695     @VisibleForTesting
incrementRxLinkSpeedBandCount(int rxLinkSpeed, int frequency)2696     public void incrementRxLinkSpeedBandCount(int rxLinkSpeed, int frequency) {
2697         if (!(mContext.getResources().getBoolean(R.bool.config_wifiLinkSpeedMetricsEnabled)
2698                 && rxLinkSpeed >= MIN_LINK_SPEED_MBPS)) {
2699             return;
2700         }
2701         synchronized (mLock) {
2702             if (ScanResult.is24GHz(frequency)) {
2703                 mRxLinkSpeedCount2g.increment(rxLinkSpeed);
2704             } else if (frequency <= KnownBandsChannelHelper.BAND_5_GHZ_LOW_END_FREQ) {
2705                 mRxLinkSpeedCount5gLow.increment(rxLinkSpeed);
2706             } else if (frequency <= KnownBandsChannelHelper.BAND_5_GHZ_MID_END_FREQ) {
2707                 mRxLinkSpeedCount5gMid.increment(rxLinkSpeed);
2708             } else if (frequency <= KnownBandsChannelHelper.BAND_5_GHZ_HIGH_END_FREQ) {
2709                 mRxLinkSpeedCount5gHigh.increment(rxLinkSpeed);
2710             } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_LOW_END_FREQ) {
2711                 mRxLinkSpeedCount6gLow.increment(rxLinkSpeed);
2712             } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_MID_END_FREQ) {
2713                 mRxLinkSpeedCount6gMid.increment(rxLinkSpeed);
2714             } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_HIGH_END_FREQ) {
2715                 mRxLinkSpeedCount6gHigh.increment(rxLinkSpeed);
2716             }
2717         }
2718     }
2719 
2720     /**
2721      * Increment occurrence count of channel utilization
2722      * @param channelUtilization Channel utilization of current network
2723      * @param frequency Channel frequency of current network
2724      */
2725     @VisibleForTesting
incrementChannelUtilizationCount(int channelUtilization, int frequency)2726     public void incrementChannelUtilizationCount(int channelUtilization, int frequency) {
2727         if (channelUtilization < InformationElementUtil.BssLoad.MIN_CHANNEL_UTILIZATION
2728                 || channelUtilization > InformationElementUtil.BssLoad.MAX_CHANNEL_UTILIZATION) {
2729             return;
2730         }
2731         synchronized (mLock) {
2732             if (ScanResult.is24GHz(frequency)) {
2733                 mChannelUtilizationHistogram2G.increment(channelUtilization);
2734             } else {
2735                 mChannelUtilizationHistogramAbove2G.increment(channelUtilization);
2736             }
2737         }
2738     }
2739 
2740     /**
2741      * Increment occurrence count of Tx and Rx throughput
2742      * @param txThroughputKbps Tx throughput of current network in Kbps
2743      * @param rxThroughputKbps Rx throughput of current network in Kbps
2744      * @param frequency Channel frequency of current network in MHz
2745      */
2746     @VisibleForTesting
incrementThroughputKbpsCount(int txThroughputKbps, int rxThroughputKbps, int frequency)2747     public void incrementThroughputKbpsCount(int txThroughputKbps, int rxThroughputKbps,
2748             int frequency) {
2749         synchronized (mLock) {
2750             if (ScanResult.is24GHz(frequency)) {
2751                 if (txThroughputKbps >= 0) {
2752                     mTxThroughputMbpsHistogram2G.increment(txThroughputKbps / 1000);
2753                 }
2754                 if (rxThroughputKbps >= 0) {
2755                     mRxThroughputMbpsHistogram2G.increment(rxThroughputKbps / 1000);
2756                 }
2757             } else {
2758                 if (txThroughputKbps >= 0) {
2759                     mTxThroughputMbpsHistogramAbove2G.increment(txThroughputKbps / 1000);
2760                 }
2761                 if (rxThroughputKbps >= 0) {
2762                     mRxThroughputMbpsHistogramAbove2G.increment(rxThroughputKbps / 1000);
2763                 }
2764             }
2765             mWifiStatusBuilder.setEstimatedTxKbps(txThroughputKbps);
2766             mWifiStatusBuilder.setEstimatedRxKbps(rxThroughputKbps);
2767         }
2768     }
2769 
2770     /**
2771      * Increment count of Watchdog successes.
2772      */
incrementNumLastResortWatchdogSuccesses()2773     public void incrementNumLastResortWatchdogSuccesses() {
2774         synchronized (mLock) {
2775             mWifiLogProto.numLastResortWatchdogSuccesses++;
2776         }
2777     }
2778 
2779     /**
2780      * Increment the count of network connection failures that happened after watchdog has been
2781      * triggered.
2782      */
incrementWatchdogTotalConnectionFailureCountAfterTrigger()2783     public void incrementWatchdogTotalConnectionFailureCountAfterTrigger() {
2784         synchronized (mLock) {
2785             mWifiLogProto.watchdogTotalConnectionFailureCountAfterTrigger++;
2786         }
2787     }
2788 
2789     /**
2790      * Sets the time taken for wifi to connect after a watchdog triggers a restart.
2791      * @param milliseconds
2792      */
setWatchdogSuccessTimeDurationMs(long ms)2793     public void setWatchdogSuccessTimeDurationMs(long ms) {
2794         synchronized (mLock) {
2795             mWifiLogProto.watchdogTriggerToConnectionSuccessDurationMs = ms;
2796         }
2797     }
2798 
2799     /**
2800      * Increments the count of alerts by alert reason.
2801      *
2802      * @param reason The cause of the alert. The reason values are driver-specific.
2803      */
incrementAlertReasonCount(int reason)2804     private void incrementAlertReasonCount(int reason) {
2805         if (reason > WifiLoggerHal.WIFI_ALERT_REASON_MAX
2806                 || reason < WifiLoggerHal.WIFI_ALERT_REASON_MIN) {
2807             reason = WifiLoggerHal.WIFI_ALERT_REASON_RESERVED;
2808         }
2809         synchronized (mLock) {
2810             int alertCount = mWifiAlertReasonCounts.get(reason);
2811             mWifiAlertReasonCounts.put(reason, alertCount + 1);
2812         }
2813     }
2814 
2815     /**
2816      * Counts all the different types of networks seen in a set of scan results
2817      */
countScanResults(List<ScanDetail> scanDetails)2818     public void countScanResults(List<ScanDetail> scanDetails) {
2819         if (scanDetails == null) {
2820             return;
2821         }
2822         int totalResults = 0;
2823         int openNetworks = 0;
2824         int personalNetworks = 0;
2825         int enterpriseNetworks = 0;
2826         int hiddenNetworks = 0;
2827         int hotspot2r1Networks = 0;
2828         int hotspot2r2Networks = 0;
2829         int hotspot2r3Networks = 0;
2830         int enhacedOpenNetworks = 0;
2831         int wpa3PersonalNetworks = 0;
2832         int wpa3EnterpriseNetworks = 0;
2833         int wapiPersonalNetworks = 0;
2834         int wapiEnterpriseNetworks = 0;
2835         int mboSupportedNetworks = 0;
2836         int mboCellularDataAwareNetworks = 0;
2837         int oceSupportedNetworks = 0;
2838         int filsSupportedNetworks = 0;
2839         int band6gNetworks = 0;
2840         int band6gPscNetworks = 0;
2841         int standard11axNetworks = 0;
2842 
2843         for (ScanDetail scanDetail : scanDetails) {
2844             NetworkDetail networkDetail = scanDetail.getNetworkDetail();
2845             ScanResult scanResult = scanDetail.getScanResult();
2846             totalResults++;
2847             if (networkDetail != null) {
2848                 if (networkDetail.isHiddenBeaconFrame()) {
2849                     hiddenNetworks++;
2850                 }
2851                 if (networkDetail.getHSRelease() != null) {
2852                     if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) {
2853                         hotspot2r1Networks++;
2854                     } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) {
2855                         hotspot2r2Networks++;
2856                     } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R3) {
2857                         hotspot2r3Networks++;
2858                     }
2859                 }
2860                 if (networkDetail.isMboSupported()) {
2861                     mboSupportedNetworks++;
2862                     if (networkDetail.isMboCellularDataAware()) {
2863                         mboCellularDataAwareNetworks++;
2864                     }
2865                     if (networkDetail.isOceSupported()) {
2866                         oceSupportedNetworks++;
2867                     }
2868                 }
2869                 if (networkDetail.getWifiMode() == InformationElementUtil.WifiMode.MODE_11AX) {
2870                     standard11axNetworks++;
2871                 }
2872             }
2873             if (scanResult != null && scanResult.capabilities != null) {
2874                 if (ScanResultUtil.isScanResultForFilsSha256Network(scanResult)
2875                         || ScanResultUtil.isScanResultForFilsSha384Network(scanResult)) {
2876                     filsSupportedNetworks++;
2877                 }
2878                 if (scanResult.is6GHz()) {
2879                     band6gNetworks++;
2880                     if (scanResult.is6GhzPsc()) {
2881                         band6gPscNetworks++;
2882                     }
2883                 }
2884                 if (ScanResultUtil.isScanResultForEapSuiteBNetwork(scanResult)
2885                         || ScanResultUtil.isScanResultForWpa3EnterpriseTransitionNetwork(scanResult)
2886                         || ScanResultUtil.isScanResultForWpa3EnterpriseOnlyNetwork(scanResult)) {
2887                     wpa3EnterpriseNetworks++;
2888                 } else if (ScanResultUtil.isScanResultForWapiPskNetwork(scanResult)) {
2889                     wapiPersonalNetworks++;
2890                 } else if (ScanResultUtil.isScanResultForWapiCertNetwork(scanResult)) {
2891                     wapiEnterpriseNetworks++;
2892                 } else if (ScanResultUtil.isScanResultForEapNetwork(scanResult)) {
2893                     enterpriseNetworks++;
2894                 } else if (ScanResultUtil.isScanResultForSaeNetwork(scanResult)) {
2895                     wpa3PersonalNetworks++;
2896                 } else if (ScanResultUtil.isScanResultForPskNetwork(scanResult)
2897                         || ScanResultUtil.isScanResultForWepNetwork(scanResult)) {
2898                     personalNetworks++;
2899                 } else if (ScanResultUtil.isScanResultForOweNetwork(scanResult)) {
2900                     enhacedOpenNetworks++;
2901                 } else {
2902                     openNetworks++;
2903                 }
2904             }
2905         }
2906         synchronized (mLock) {
2907             mWifiLogProto.numTotalScanResults += totalResults;
2908             mWifiLogProto.numOpenNetworkScanResults += openNetworks;
2909             mWifiLogProto.numLegacyPersonalNetworkScanResults += personalNetworks;
2910             mWifiLogProto.numLegacyEnterpriseNetworkScanResults += enterpriseNetworks;
2911             mWifiLogProto.numEnhancedOpenNetworkScanResults += enhacedOpenNetworks;
2912             mWifiLogProto.numWpa3PersonalNetworkScanResults += wpa3PersonalNetworks;
2913             mWifiLogProto.numWpa3EnterpriseNetworkScanResults += wpa3EnterpriseNetworks;
2914             mWifiLogProto.numWapiPersonalNetworkScanResults += wapiPersonalNetworks;
2915             mWifiLogProto.numWapiEnterpriseNetworkScanResults += wapiEnterpriseNetworks;
2916             mWifiLogProto.numHiddenNetworkScanResults += hiddenNetworks;
2917             mWifiLogProto.numHotspot2R1NetworkScanResults += hotspot2r1Networks;
2918             mWifiLogProto.numHotspot2R2NetworkScanResults += hotspot2r2Networks;
2919             mWifiLogProto.numHotspot2R3NetworkScanResults += hotspot2r3Networks;
2920             mWifiLogProto.numMboSupportedNetworkScanResults += mboSupportedNetworks;
2921             mWifiLogProto.numMboCellularDataAwareNetworkScanResults += mboCellularDataAwareNetworks;
2922             mWifiLogProto.numOceSupportedNetworkScanResults += oceSupportedNetworks;
2923             mWifiLogProto.numFilsSupportedNetworkScanResults += filsSupportedNetworks;
2924             mWifiLogProto.num11AxNetworkScanResults += standard11axNetworks;
2925             mWifiLogProto.num6GNetworkScanResults += band6gNetworks;
2926             mWifiLogProto.num6GPscNetworkScanResults += band6gPscNetworks;
2927             mWifiLogProto.numScans++;
2928         }
2929     }
2930 
2931     private boolean mWifiWins = false; // Based on scores, use wifi instead of mobile data?
2932     // Based on Wifi usability scores. use wifi instead of mobile data?
2933     private boolean mWifiWinsUsabilityScore = false;
2934 
2935     /**
2936      * Increments occurence of a particular wifi score calculated
2937      * in WifiScoreReport by current connected network. Scores are bounded
2938      * within  [MIN_WIFI_SCORE, MAX_WIFI_SCORE] to limit size of SparseArray.
2939      *
2940      * Also records events when the current score breaches significant thresholds.
2941      */
incrementWifiScoreCount(String ifaceName, int score)2942     public void incrementWifiScoreCount(String ifaceName, int score) {
2943         if (score < MIN_WIFI_SCORE || score > MAX_WIFI_SCORE) {
2944             return;
2945         }
2946         synchronized (mLock) {
2947             int count = mWifiScoreCounts.get(score);
2948             mWifiScoreCounts.put(score, count + 1);
2949 
2950             boolean wifiWins = mWifiWins;
2951             if (mWifiWins && score < LOW_WIFI_SCORE) {
2952                 wifiWins = false;
2953             } else if (!mWifiWins && score > LOW_WIFI_SCORE) {
2954                 wifiWins = true;
2955             }
2956             mLastScore = score;
2957             mLastScoreNoReset = score;
2958             if (wifiWins != mWifiWins) {
2959                 mWifiWins = wifiWins;
2960                 StaEvent event = new StaEvent();
2961                 event.type = StaEvent.TYPE_SCORE_BREACH;
2962                 addStaEvent(ifaceName, event);
2963                 // Only record the first score breach by checking whether mScoreBreachLowTimeMillis
2964                 // has been set to -1
2965                 if (!wifiWins && mScoreBreachLowTimeMillis == -1) {
2966                     mScoreBreachLowTimeMillis = mClock.getElapsedSinceBootMillis();
2967                 }
2968             }
2969         }
2970     }
2971 
2972     /**
2973      * Increments occurence of the results from attempting to start SoftAp.
2974      * Maps the |result| and WifiManager |failureCode| constant to proto defined SoftApStartResult
2975      * codes.
2976      */
incrementSoftApStartResult(boolean result, int failureCode)2977     public void incrementSoftApStartResult(boolean result, int failureCode) {
2978         synchronized (mLock) {
2979             if (result) {
2980                 int count = mSoftApManagerReturnCodeCounts.get(
2981                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY);
2982                 mSoftApManagerReturnCodeCounts.put(
2983                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY,
2984                         count + 1);
2985                 return;
2986             }
2987 
2988             // now increment failure modes - if not explicitly handled, dump into the general
2989             // error bucket.
2990             if (failureCode == WifiManager.SAP_START_FAILURE_NO_CHANNEL) {
2991                 int count = mSoftApManagerReturnCodeCounts.get(
2992                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL);
2993                 mSoftApManagerReturnCodeCounts.put(
2994                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL,
2995                         count + 1);
2996             } else if (failureCode == WifiManager.SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION) {
2997                 int count = mSoftApManagerReturnCodeCounts.get(
2998                         WifiMetricsProto.SoftApReturnCodeCount
2999                         .SOFT_AP_FAILED_UNSUPPORTED_CONFIGURATION);
3000                 mSoftApManagerReturnCodeCounts.put(
3001                         WifiMetricsProto.SoftApReturnCodeCount
3002                         .SOFT_AP_FAILED_UNSUPPORTED_CONFIGURATION,
3003                         count + 1);
3004             } else {
3005                 // failure mode not tracked at this time...  count as a general error for now.
3006                 int count = mSoftApManagerReturnCodeCounts.get(
3007                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR);
3008                 mSoftApManagerReturnCodeCounts.put(
3009                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR,
3010                         count + 1);
3011             }
3012         }
3013     }
3014 
3015     /**
3016      * Adds a record indicating the current up state of soft AP
3017      */
addSoftApUpChangedEvent(boolean isUp, int mode, long defaultShutdownTimeoutMillis, boolean isBridged)3018     public void addSoftApUpChangedEvent(boolean isUp, int mode, long defaultShutdownTimeoutMillis,
3019             boolean isBridged) {
3020         int numOfEventNeedToAdd = isBridged && isUp ? 2 : 1;
3021         for (int i = 0; i < numOfEventNeedToAdd; i++) {
3022             SoftApConnectedClientsEvent event = new SoftApConnectedClientsEvent();
3023             if (isUp) {
3024                 event.eventType = isBridged ? SoftApConnectedClientsEvent.DUAL_AP_BOTH_INSTANCES_UP
3025                         : SoftApConnectedClientsEvent.SOFT_AP_UP;
3026             } else {
3027                 event.eventType = SoftApConnectedClientsEvent.SOFT_AP_DOWN;
3028             }
3029             event.numConnectedClients = 0;
3030             event.defaultShutdownTimeoutSetting = defaultShutdownTimeoutMillis;
3031             addSoftApConnectedClientsEvent(event, mode);
3032         }
3033     }
3034 
3035     /**
3036      * Adds a record indicating the one of the dual AP instances is down.
3037      */
addSoftApInstanceDownEventInDualMode(int mode, @NonNull SoftApInfo info)3038     public void addSoftApInstanceDownEventInDualMode(int mode, @NonNull SoftApInfo info) {
3039         SoftApConnectedClientsEvent event = new SoftApConnectedClientsEvent();
3040         event.eventType = SoftApConnectedClientsEvent.DUAL_AP_ONE_INSTANCE_DOWN;
3041         event.channelFrequency = info.getFrequency();
3042         event.channelBandwidth = info.getBandwidth();
3043         event.generation = info.getWifiStandardInternal();
3044         addSoftApConnectedClientsEvent(event, mode);
3045     }
3046 
3047     /**
3048      * Adds a record for current number of associated stations to soft AP
3049      */
addSoftApNumAssociatedStationsChangedEvent(int numTotalStations, int numStationsOnCurrentFrequency, int mode, @Nullable SoftApInfo info)3050     public void addSoftApNumAssociatedStationsChangedEvent(int numTotalStations,
3051             int numStationsOnCurrentFrequency, int mode, @Nullable SoftApInfo info) {
3052         SoftApConnectedClientsEvent event = new SoftApConnectedClientsEvent();
3053         event.eventType = SoftApConnectedClientsEvent.NUM_CLIENTS_CHANGED;
3054         if (info != null) {
3055             event.channelFrequency = info.getFrequency();
3056             event.channelBandwidth = info.getBandwidth();
3057             event.generation = info.getWifiStandardInternal();
3058         }
3059         event.numConnectedClients = numTotalStations;
3060         event.numConnectedClientsOnCurrentFrequency = numStationsOnCurrentFrequency;
3061         addSoftApConnectedClientsEvent(event, mode);
3062     }
3063 
3064     /**
3065      * Adds a record to the corresponding event list based on mode param
3066      */
addSoftApConnectedClientsEvent(SoftApConnectedClientsEvent event, int mode)3067     private void addSoftApConnectedClientsEvent(SoftApConnectedClientsEvent event, int mode) {
3068         synchronized (mLock) {
3069             List<SoftApConnectedClientsEvent> softApEventList;
3070             switch (mode) {
3071                 case WifiManager.IFACE_IP_MODE_TETHERED:
3072                     softApEventList = mSoftApEventListTethered;
3073                     break;
3074                 case WifiManager.IFACE_IP_MODE_LOCAL_ONLY:
3075                     softApEventList = mSoftApEventListLocalOnly;
3076                     break;
3077                 default:
3078                     return;
3079             }
3080 
3081             if (softApEventList.size() > MAX_NUM_SOFT_AP_EVENTS) {
3082                 return;
3083             }
3084 
3085             event.timeStampMillis = mClock.getElapsedSinceBootMillis();
3086             softApEventList.add(event);
3087         }
3088     }
3089 
3090     /**
3091      * Updates current soft AP events with channel info
3092      */
addSoftApChannelSwitchedEvent(List<SoftApInfo> infos, int mode, boolean isBridged)3093     public void addSoftApChannelSwitchedEvent(List<SoftApInfo> infos, int mode, boolean isBridged) {
3094         synchronized (mLock) {
3095             int numOfEventNeededToUpdate = infos.size();
3096             if (isBridged && numOfEventNeededToUpdate == 1) {
3097                 // Ignore the channel info update when only 1 info in bridged mode because it means
3098                 // that one of the instance was been shutdown.
3099                 return;
3100             }
3101             int apUpEvent = isBridged ? SoftApConnectedClientsEvent.DUAL_AP_BOTH_INSTANCES_UP
3102                     : SoftApConnectedClientsEvent.SOFT_AP_UP;
3103             List<SoftApConnectedClientsEvent> softApEventList;
3104             switch (mode) {
3105                 case WifiManager.IFACE_IP_MODE_TETHERED:
3106                     softApEventList = mSoftApEventListTethered;
3107                     break;
3108                 case WifiManager.IFACE_IP_MODE_LOCAL_ONLY:
3109                     softApEventList = mSoftApEventListLocalOnly;
3110                     break;
3111                 default:
3112                     return;
3113             }
3114 
3115             for (int index = softApEventList.size() - 1;
3116                     index >= 0 && numOfEventNeededToUpdate != 0; index--) {
3117                 SoftApConnectedClientsEvent event = softApEventList.get(index);
3118                 if (event != null && event.eventType == apUpEvent) {
3119                     int infoIndex = numOfEventNeededToUpdate - 1;
3120                     event.channelFrequency = infos.get(infoIndex).getFrequency();
3121                     event.channelBandwidth = infos.get(infoIndex).getBandwidth();
3122                     event.generation = infos.get(infoIndex).getWifiStandardInternal();
3123                     numOfEventNeededToUpdate--;
3124                 }
3125             }
3126         }
3127     }
3128 
3129     /**
3130      * Updates current soft AP events with softap configuration
3131      */
updateSoftApConfiguration(SoftApConfiguration config, int mode, boolean isBridged)3132     public void updateSoftApConfiguration(SoftApConfiguration config, int mode, boolean isBridged) {
3133         synchronized (mLock) {
3134             List<SoftApConnectedClientsEvent> softApEventList;
3135             switch (mode) {
3136                 case WifiManager.IFACE_IP_MODE_TETHERED:
3137                     softApEventList = mSoftApEventListTethered;
3138                     break;
3139                 case WifiManager.IFACE_IP_MODE_LOCAL_ONLY:
3140                     softApEventList = mSoftApEventListLocalOnly;
3141                     break;
3142                 default:
3143                     return;
3144             }
3145 
3146             int numOfEventNeededToUpdate = isBridged ? 2 : 1;
3147             int apUpEvent = isBridged ? SoftApConnectedClientsEvent.DUAL_AP_BOTH_INSTANCES_UP
3148                     : SoftApConnectedClientsEvent.SOFT_AP_UP;
3149 
3150             for (int index = softApEventList.size() - 1;
3151                     index >= 0 && numOfEventNeededToUpdate != 0; index--) {
3152                 SoftApConnectedClientsEvent event = softApEventList.get(index);
3153                 if (event != null && event.eventType == apUpEvent) {
3154                     event.maxNumClientsSettingInSoftapConfiguration =
3155                             config.getMaxNumberOfClients();
3156                     event.shutdownTimeoutSettingInSoftapConfiguration =
3157                             config.getShutdownTimeoutMillis();
3158                     event.clientControlIsEnabled = config.isClientControlByUserEnabled();
3159                     numOfEventNeededToUpdate--;
3160                 }
3161             }
3162         }
3163     }
3164 
3165     /**
3166      * Updates current soft AP events with softap capability
3167      */
updateSoftApCapability(SoftApCapability capability, int mode, boolean isBridged)3168     public void updateSoftApCapability(SoftApCapability capability, int mode, boolean isBridged) {
3169         synchronized (mLock) {
3170             List<SoftApConnectedClientsEvent> softApEventList;
3171             switch (mode) {
3172                 case WifiManager.IFACE_IP_MODE_TETHERED:
3173                     softApEventList = mSoftApEventListTethered;
3174                     break;
3175                 case WifiManager.IFACE_IP_MODE_LOCAL_ONLY:
3176                     softApEventList = mSoftApEventListLocalOnly;
3177                     break;
3178                 default:
3179                     return;
3180             }
3181 
3182             int numOfEventNeededToUpdate = isBridged ? 2 : 1;
3183             int apUpEvent = isBridged ? SoftApConnectedClientsEvent.DUAL_AP_BOTH_INSTANCES_UP
3184                     : SoftApConnectedClientsEvent.SOFT_AP_UP;
3185 
3186             for (int index = softApEventList.size() - 1;
3187                     index >= 0 && numOfEventNeededToUpdate != 0; index--) {
3188                 SoftApConnectedClientsEvent event = softApEventList.get(index);
3189                 if (event != null && event.eventType == apUpEvent) {
3190                     event.maxNumClientsSettingInSoftapCapability =
3191                             capability.getMaxSupportedClients();
3192                     numOfEventNeededToUpdate--;
3193                 }
3194             }
3195         }
3196     }
3197 
3198     /**
3199      * Increment number of times the HAL crashed.
3200      */
incrementNumHalCrashes()3201     public synchronized void incrementNumHalCrashes() {
3202         mWifiLogProto.numHalCrashes++;
3203         WifiStatsLog.write(WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED,
3204                 WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED__TYPE__HAL_CRASH);
3205     }
3206 
3207     /**
3208      * Increment number of times the Wificond crashed.
3209      */
incrementNumWificondCrashes()3210     public synchronized void incrementNumWificondCrashes() {
3211         mWifiLogProto.numWificondCrashes++;
3212         WifiStatsLog.write(WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED,
3213                 WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED__TYPE__WIFICOND_CRASH);
3214     }
3215 
3216     /**
3217      * Increment number of times the supplicant crashed.
3218      */
incrementNumSupplicantCrashes()3219     public synchronized void incrementNumSupplicantCrashes() {
3220         mWifiLogProto.numSupplicantCrashes++;
3221         WifiStatsLog.write(WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED,
3222                 WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED__TYPE__SUPPLICANT_CRASH);
3223     }
3224 
3225     /**
3226      * Increment number of times the hostapd crashed.
3227      */
incrementNumHostapdCrashes()3228     public synchronized void incrementNumHostapdCrashes() {
3229         mWifiLogProto.numHostapdCrashes++;
3230         WifiStatsLog.write(WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED,
3231                 WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED__TYPE__HOSTAPD_CRASH);
3232     }
3233 
3234     /**
3235      * Increment number of times the wifi on failed due to an error in HAL.
3236      */
incrementNumSetupClientInterfaceFailureDueToHal()3237     public synchronized void incrementNumSetupClientInterfaceFailureDueToHal() {
3238         mWifiLogProto.numSetupClientInterfaceFailureDueToHal++;
3239         WifiStatsLog.write(WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED,
3240                 WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED__TYPE__CLIENT_FAILURE_HAL);
3241     }
3242 
3243     /**
3244      * Increment number of times the wifi on failed due to an error in wificond.
3245      */
incrementNumSetupClientInterfaceFailureDueToWificond()3246     public synchronized void incrementNumSetupClientInterfaceFailureDueToWificond() {
3247         mWifiLogProto.numSetupClientInterfaceFailureDueToWificond++;
3248         WifiStatsLog.write(WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED,
3249                 WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED__TYPE__CLIENT_FAILURE_WIFICOND);
3250     }
3251 
3252     /**
3253      * Increment number of times the wifi on failed due to an error in supplicant.
3254      */
incrementNumSetupClientInterfaceFailureDueToSupplicant()3255     public synchronized void incrementNumSetupClientInterfaceFailureDueToSupplicant() {
3256         mWifiLogProto.numSetupClientInterfaceFailureDueToSupplicant++;
3257         WifiStatsLog.write(WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED,
3258                 WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED__TYPE__CLIENT_FAILURE_SUPPLICANT);
3259     }
3260 
3261     /**
3262      * Increment number of times the SoftAp on failed due to an error in HAL.
3263      */
incrementNumSetupSoftApInterfaceFailureDueToHal()3264     public synchronized void incrementNumSetupSoftApInterfaceFailureDueToHal() {
3265         mWifiLogProto.numSetupSoftApInterfaceFailureDueToHal++;
3266         WifiStatsLog.write(WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED,
3267                 WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED__TYPE__SOFT_AP_FAILURE_HAL);
3268     }
3269 
3270     /**
3271      * Increment number of times the SoftAp on failed due to an error in wificond.
3272      */
incrementNumSetupSoftApInterfaceFailureDueToWificond()3273     public synchronized void incrementNumSetupSoftApInterfaceFailureDueToWificond() {
3274         mWifiLogProto.numSetupSoftApInterfaceFailureDueToWificond++;
3275         WifiStatsLog.write(WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED,
3276                 WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED__TYPE__SOFT_AP_FAILURE_WIFICOND);
3277     }
3278 
3279     /**
3280      * Increment number of times the SoftAp on failed due to an error in hostapd.
3281      */
incrementNumSetupSoftApInterfaceFailureDueToHostapd()3282     public synchronized void incrementNumSetupSoftApInterfaceFailureDueToHostapd() {
3283         mWifiLogProto.numSetupSoftApInterfaceFailureDueToHostapd++;
3284         WifiStatsLog.write(WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED,
3285                 WifiStatsLog.WIFI_SETUP_FAILURE_CRASH_REPORTED__TYPE__SOFT_AP_FAILURE_HOSTAPD);
3286     }
3287 
3288     /**
3289      * Increment number of times we got client interface down.
3290      */
incrementNumClientInterfaceDown()3291     public void incrementNumClientInterfaceDown() {
3292         synchronized (mLock) {
3293             mWifiLogProto.numClientInterfaceDown++;
3294         }
3295     }
3296 
3297     /**
3298      * Increment number of times we got client interface down.
3299      */
incrementNumSoftApInterfaceDown()3300     public void incrementNumSoftApInterfaceDown() {
3301         synchronized (mLock) {
3302             mWifiLogProto.numSoftApInterfaceDown++;
3303         }
3304     }
3305 
3306     /**
3307      * Increment number of times Passpoint provider being installed.
3308      */
incrementNumPasspointProviderInstallation()3309     public void incrementNumPasspointProviderInstallation() {
3310         synchronized (mLock) {
3311             mWifiLogProto.numPasspointProviderInstallation++;
3312         }
3313     }
3314 
3315     /**
3316      * Increment number of times Passpoint provider is installed successfully.
3317      */
incrementNumPasspointProviderInstallSuccess()3318     public void incrementNumPasspointProviderInstallSuccess() {
3319         synchronized (mLock) {
3320             mWifiLogProto.numPasspointProviderInstallSuccess++;
3321         }
3322     }
3323 
3324     /**
3325      * Increment number of times Passpoint provider being uninstalled.
3326      */
incrementNumPasspointProviderUninstallation()3327     public void incrementNumPasspointProviderUninstallation() {
3328         synchronized (mLock) {
3329             mWifiLogProto.numPasspointProviderUninstallation++;
3330         }
3331     }
3332 
3333     /**
3334      * Increment number of times Passpoint provider is uninstalled successfully.
3335      */
incrementNumPasspointProviderUninstallSuccess()3336     public void incrementNumPasspointProviderUninstallSuccess() {
3337         synchronized (mLock) {
3338             mWifiLogProto.numPasspointProviderUninstallSuccess++;
3339         }
3340     }
3341 
3342     /**
3343      * Increment number of Passpoint providers with no Root CA in their profile.
3344      */
incrementNumPasspointProviderWithNoRootCa()3345     public void incrementNumPasspointProviderWithNoRootCa() {
3346         synchronized (mLock) {
3347             mWifiLogProto.numPasspointProviderWithNoRootCa++;
3348         }
3349     }
3350 
3351     /**
3352      * Increment number of Passpoint providers with a self-signed Root CA in their profile.
3353      */
incrementNumPasspointProviderWithSelfSignedRootCa()3354     public void incrementNumPasspointProviderWithSelfSignedRootCa() {
3355         synchronized (mLock) {
3356             mWifiLogProto.numPasspointProviderWithSelfSignedRootCa++;
3357         }
3358     }
3359 
3360     /**
3361      * Increment number of Passpoint providers with subscription expiration date in their profile.
3362      */
incrementNumPasspointProviderWithSubscriptionExpiration()3363     public void incrementNumPasspointProviderWithSubscriptionExpiration() {
3364         synchronized (mLock) {
3365             mWifiLogProto.numPasspointProviderWithSubscriptionExpiration++;
3366         }
3367     }
3368 
3369     /**
3370      * Increment number of times we detected a radio mode change to MCC.
3371      */
incrementNumRadioModeChangeToMcc()3372     public void incrementNumRadioModeChangeToMcc() {
3373         synchronized (mLock) {
3374             mWifiLogProto.numRadioModeChangeToMcc++;
3375         }
3376     }
3377 
3378     /**
3379      * Increment number of times we detected a radio mode change to SCC.
3380      */
incrementNumRadioModeChangeToScc()3381     public void incrementNumRadioModeChangeToScc() {
3382         synchronized (mLock) {
3383             mWifiLogProto.numRadioModeChangeToScc++;
3384         }
3385     }
3386 
3387     /**
3388      * Increment number of times we detected a radio mode change to SBS.
3389      */
incrementNumRadioModeChangeToSbs()3390     public void incrementNumRadioModeChangeToSbs() {
3391         synchronized (mLock) {
3392             mWifiLogProto.numRadioModeChangeToSbs++;
3393         }
3394     }
3395 
3396     /**
3397      * Increment number of times we detected a radio mode change to DBS.
3398      */
incrementNumRadioModeChangeToDbs()3399     public void incrementNumRadioModeChangeToDbs() {
3400         synchronized (mLock) {
3401             mWifiLogProto.numRadioModeChangeToDbs++;
3402         }
3403     }
3404 
3405     /**
3406      * Increment number of times we detected a channel did not satisfy user band preference.
3407      */
incrementNumSoftApUserBandPreferenceUnsatisfied()3408     public void incrementNumSoftApUserBandPreferenceUnsatisfied() {
3409         synchronized (mLock) {
3410             mWifiLogProto.numSoftApUserBandPreferenceUnsatisfied++;
3411         }
3412     }
3413 
3414     /**
3415      * Increment N-Way network selection decision histograms:
3416      * Counts the size of various sets of scanDetails within a scan, and increment the occurrence
3417      * of that size for the associated histogram. There are ten histograms generated for each
3418      * combination of: {SSID, BSSID} *{Total, Saved, Open, Saved_or_Open, Passpoint}
3419      * Only performs this count if isFullBand is true, otherwise, increments the partial scan count
3420      */
incrementAvailableNetworksHistograms(List<ScanDetail> scanDetails, boolean isFullBand)3421     public void incrementAvailableNetworksHistograms(List<ScanDetail> scanDetails,
3422             boolean isFullBand) {
3423         synchronized (mLock) {
3424             if (mWifiConfigManager == null || mWifiNetworkSelector == null
3425                     || mPasspointManager == null) {
3426                 return;
3427             }
3428             if (!isFullBand) {
3429                 mWifiLogProto.partialAllSingleScanListenerResults++;
3430                 return;
3431             }
3432             updateCountryCodeScanStats(scanDetails);
3433 
3434             Set<ScanResultMatchInfo> ssids = new HashSet<ScanResultMatchInfo>();
3435             int bssids = 0;
3436             Set<ScanResultMatchInfo> openSsids = new HashSet<ScanResultMatchInfo>();
3437             int openBssids = 0;
3438             Set<ScanResultMatchInfo> savedSsids = new HashSet<ScanResultMatchInfo>();
3439             int savedBssids = 0;
3440             // openOrSavedSsids calculated from union of savedSsids & openSsids
3441             int openOrSavedBssids = 0;
3442             Set<PasspointProvider> savedPasspointProviderProfiles =
3443                     new HashSet<PasspointProvider>();
3444             int savedPasspointProviderBssids = 0;
3445             int passpointR1Aps = 0;
3446             int passpointR2Aps = 0;
3447             int passpointR3Aps = 0;
3448             Map<ANQPNetworkKey, Integer> passpointR1UniqueEss = new HashMap<>();
3449             Map<ANQPNetworkKey, Integer> passpointR2UniqueEss = new HashMap<>();
3450             Map<ANQPNetworkKey, Integer> passpointR3UniqueEss = new HashMap<>();
3451             int supporting80211mcAps = 0;
3452             for (ScanDetail scanDetail : scanDetails) {
3453                 NetworkDetail networkDetail = scanDetail.getNetworkDetail();
3454                 ScanResult scanResult = scanDetail.getScanResult();
3455 
3456                 // statistics to be collected for ALL APs (irrespective of signal power)
3457                 if (networkDetail.is80211McResponderSupport()) {
3458                     supporting80211mcAps++;
3459                 }
3460 
3461                 ScanResultMatchInfo matchInfo = ScanResultMatchInfo.fromScanResult(scanResult);
3462                 List<Pair<PasspointProvider, PasspointMatch>> matchedProviders = null;
3463                 if (networkDetail.isInterworking()) {
3464                     // Try to match provider, but do not allow new ANQP messages. Use cached data.
3465                     matchedProviders = mPasspointManager.matchProvider(scanResult, false);
3466                     if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) {
3467                         passpointR1Aps++;
3468                     } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) {
3469                         passpointR2Aps++;
3470                     } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R3) {
3471                         passpointR3Aps++;
3472                     }
3473 
3474                     long bssid = 0;
3475                     boolean validBssid = false;
3476                     try {
3477                         bssid = Utils.parseMac(scanResult.BSSID);
3478                         validBssid = true;
3479                     } catch (IllegalArgumentException e) {
3480                         Log.e(TAG,
3481                                 "Invalid BSSID provided in the scan result: " + scanResult.BSSID);
3482                     }
3483                     if (validBssid) {
3484                         ANQPNetworkKey uniqueEss = ANQPNetworkKey.buildKey(scanResult.SSID, bssid,
3485                                 scanResult.hessid, networkDetail.getAnqpDomainID());
3486                         if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) {
3487                             Integer countObj = passpointR1UniqueEss.get(uniqueEss);
3488                             int count = countObj == null ? 0 : countObj;
3489                             passpointR1UniqueEss.put(uniqueEss, count + 1);
3490                         } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) {
3491                             Integer countObj = passpointR2UniqueEss.get(uniqueEss);
3492                             int count = countObj == null ? 0 : countObj;
3493                             passpointR2UniqueEss.put(uniqueEss, count + 1);
3494                         } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R3) {
3495                             Integer countObj = passpointR3UniqueEss.get(uniqueEss);
3496                             int count = countObj == null ? 0 : countObj;
3497                             passpointR3UniqueEss.put(uniqueEss, count + 1);
3498                         }
3499                     }
3500                 }
3501 
3502                 if (mWifiNetworkSelector.isSignalTooWeak(scanResult)) {
3503                     continue;
3504                 }
3505 
3506                 // statistics to be collected ONLY for those APs with sufficient signal power
3507 
3508                 ssids.add(matchInfo);
3509                 bssids++;
3510                 boolean isOpen = ScanResultUtil.isScanResultForOpenNetwork(scanResult)
3511                         || ScanResultUtil.isScanResultForOweNetwork(scanResult);
3512                 WifiConfiguration config =
3513                         mWifiConfigManager.getSavedNetworkForScanDetail(scanDetail);
3514                 boolean isSaved = (config != null) && !config.isEphemeral()
3515                         && !config.isPasspoint();
3516                 if (isOpen) {
3517                     openSsids.add(matchInfo);
3518                     openBssids++;
3519                 }
3520                 if (isSaved) {
3521                     savedSsids.add(matchInfo);
3522                     savedBssids++;
3523                 }
3524                 if (isOpen || isSaved) {
3525                     openOrSavedBssids++;
3526                     // Calculate openOrSavedSsids union later
3527                 }
3528                 if (matchedProviders != null && !matchedProviders.isEmpty()) {
3529                     for (Pair<PasspointProvider, PasspointMatch> passpointProvider :
3530                             matchedProviders) {
3531                         savedPasspointProviderProfiles.add(passpointProvider.first);
3532                     }
3533                     savedPasspointProviderBssids++;
3534                 }
3535             }
3536             mWifiLogProto.fullBandAllSingleScanListenerResults++;
3537             incrementTotalScanSsids(mTotalSsidsInScanHistogram, ssids.size());
3538             incrementTotalScanResults(mTotalBssidsInScanHistogram, bssids);
3539             incrementSsid(mAvailableOpenSsidsInScanHistogram, openSsids.size());
3540             incrementBssid(mAvailableOpenBssidsInScanHistogram, openBssids);
3541             incrementSsid(mAvailableSavedSsidsInScanHistogram, savedSsids.size());
3542             incrementBssid(mAvailableSavedBssidsInScanHistogram, savedBssids);
3543             openSsids.addAll(savedSsids); // openSsids = Union(openSsids, savedSsids)
3544             incrementSsid(mAvailableOpenOrSavedSsidsInScanHistogram, openSsids.size());
3545             incrementBssid(mAvailableOpenOrSavedBssidsInScanHistogram, openOrSavedBssids);
3546             incrementSsid(mAvailableSavedPasspointProviderProfilesInScanHistogram,
3547                     savedPasspointProviderProfiles.size());
3548             incrementBssid(mAvailableSavedPasspointProviderBssidsInScanHistogram,
3549                     savedPasspointProviderBssids);
3550             incrementTotalPasspointAps(mObservedHotspotR1ApInScanHistogram, passpointR1Aps);
3551             incrementTotalPasspointAps(mObservedHotspotR2ApInScanHistogram, passpointR2Aps);
3552             incrementTotalPasspointAps(mObservedHotspotR3ApInScanHistogram, passpointR3Aps);
3553             incrementTotalUniquePasspointEss(mObservedHotspotR1EssInScanHistogram,
3554                     passpointR1UniqueEss.size());
3555             incrementTotalUniquePasspointEss(mObservedHotspotR2EssInScanHistogram,
3556                     passpointR2UniqueEss.size());
3557             incrementTotalUniquePasspointEss(mObservedHotspotR3EssInScanHistogram,
3558                     passpointR3UniqueEss.size());
3559             for (Integer count : passpointR1UniqueEss.values()) {
3560                 incrementPasspointPerUniqueEss(mObservedHotspotR1ApsPerEssInScanHistogram, count);
3561             }
3562             for (Integer count : passpointR2UniqueEss.values()) {
3563                 incrementPasspointPerUniqueEss(mObservedHotspotR2ApsPerEssInScanHistogram, count);
3564             }
3565             for (Integer count : passpointR3UniqueEss.values()) {
3566                 incrementPasspointPerUniqueEss(mObservedHotspotR3ApsPerEssInScanHistogram, count);
3567             }
3568             increment80211mcAps(mObserved80211mcApInScanHistogram, supporting80211mcAps);
3569         }
3570     }
3571 
updateCountryCodeScanStats(List<ScanDetail> scanDetails)3572     private void updateCountryCodeScanStats(List<ScanDetail> scanDetails) {
3573         String countryCode = null;
3574         int countryCodeCount = 0;
3575         for (ScanDetail scanDetail : scanDetails) {
3576             NetworkDetail networkDetail = scanDetail.getNetworkDetail();
3577             String countryCodeCurr = networkDetail.getCountryCode();
3578             if (countryCodeCurr == null) {
3579                 continue;
3580             }
3581             if (countryCode == null) {
3582                 countryCode = countryCodeCurr;
3583                 countryCodeCount = 1;
3584                 continue;
3585             }
3586             if (!countryCodeCurr.equalsIgnoreCase(countryCode)) {
3587                 mCountryCodeScanHistogram.increment(COUNTRY_CODE_CONFLICT_WIFI_SCAN);
3588                 return;
3589             }
3590             countryCodeCount++;
3591         }
3592         String countryCodeTelephony = mTelephonyManager.getNetworkCountryIso();
3593         if (countryCodeCount > 0 && !TextUtils.isEmpty(countryCodeTelephony)
3594                 && !countryCodeTelephony.equalsIgnoreCase(countryCode)) {
3595             mCountryCodeScanHistogram.increment(COUNTRY_CODE_CONFLICT_WIFI_SCAN_TELEPHONY);
3596             return;
3597         }
3598         mCountryCodeScanHistogram.increment(Math.min(countryCodeCount, MAX_COUNTRY_CODE_COUNT));
3599     }
3600 
3601     /** Increments the occurence of a "Connect to Network" notification. */
incrementConnectToNetworkNotification(String notifierTag, int notificationType)3602     public void incrementConnectToNetworkNotification(String notifierTag, int notificationType) {
3603         synchronized (mLock) {
3604             int count = mConnectToNetworkNotificationCount.get(notificationType);
3605             mConnectToNetworkNotificationCount.put(notificationType, count + 1);
3606         }
3607     }
3608 
3609     /** Increments the occurence of an "Connect to Network" notification user action. */
incrementConnectToNetworkNotificationAction(String notifierTag, int notificationType, int actionType)3610     public void incrementConnectToNetworkNotificationAction(String notifierTag,
3611             int notificationType, int actionType) {
3612         synchronized (mLock) {
3613             int key = notificationType * CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER
3614                     + actionType;
3615             int count = mConnectToNetworkNotificationActionCount.get(key);
3616             mConnectToNetworkNotificationActionCount.put(key, count + 1);
3617         }
3618     }
3619 
3620     /**
3621      * Sets the number of SSIDs blocklisted from recommendation by the open network notification
3622      * recommender.
3623      */
setNetworkRecommenderBlocklistSize(String notifierTag, int size)3624     public void setNetworkRecommenderBlocklistSize(String notifierTag, int size) {
3625         synchronized (mLock) {
3626             mOpenNetworkRecommenderBlocklistSize = size;
3627         }
3628     }
3629 
3630     /** Sets if the available network notification feature is enabled. */
setIsWifiNetworksAvailableNotificationEnabled(String notifierTag, boolean enabled)3631     public void setIsWifiNetworksAvailableNotificationEnabled(String notifierTag, boolean enabled) {
3632         synchronized (mLock) {
3633             mIsWifiNetworksAvailableNotificationOn = enabled;
3634         }
3635     }
3636 
3637     /** Increments the occurence of connection attempts that were initiated unsuccessfully */
incrementNumNetworkRecommendationUpdates(String notifierTag)3638     public void incrementNumNetworkRecommendationUpdates(String notifierTag) {
3639         synchronized (mLock) {
3640             mNumOpenNetworkRecommendationUpdates++;
3641         }
3642     }
3643 
3644     /** Increments the occurence of connection attempts that were initiated unsuccessfully */
incrementNumNetworkConnectMessageFailedToSend(String notifierTag)3645     public void incrementNumNetworkConnectMessageFailedToSend(String notifierTag) {
3646         synchronized (mLock) {
3647             mNumOpenNetworkConnectMessageFailedToSend++;
3648         }
3649     }
3650 
3651     /** Log firmware alert related metrics */
logFirmwareAlert(String ifaceName, int errorCode)3652     public void logFirmwareAlert(String ifaceName, int errorCode) {
3653         incrementAlertReasonCount(errorCode);
3654         logWifiIsUnusableEvent(ifaceName, WifiIsUnusableEvent.TYPE_FIRMWARE_ALERT, errorCode);
3655         addToWifiUsabilityStatsList(ifaceName, WifiUsabilityStats.LABEL_BAD,
3656                 WifiUsabilityStats.TYPE_FIRMWARE_ALERT, errorCode);
3657     }
3658 
3659     public static final String PROTO_DUMP_ARG = "wifiMetricsProto";
3660     public static final String CLEAN_DUMP_ARG = "clean";
3661 
3662     /**
3663      * Dump all WifiMetrics. Collects some metrics from ConfigStore, Settings and WifiManager
3664      * at this time.
3665      *
3666      * @param fd unused
3667      * @param pw PrintWriter for writing dump to
3668      * @param args [wifiMetricsProto [clean]]
3669      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)3670     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3671         synchronized (mLock) {
3672             consolidateScoringParams();
3673             if (args != null && args.length > 0 && PROTO_DUMP_ARG.equals(args[0])) {
3674                 // Dump serialized WifiLog proto
3675                 consolidateProto();
3676                 byte[] wifiMetricsProto = WifiMetricsProto.WifiLog.toByteArray(mWifiLogProto);
3677                 String metricsProtoDump = Base64.encodeToString(wifiMetricsProto, Base64.DEFAULT);
3678                 if (args.length > 1 && CLEAN_DUMP_ARG.equals(args[1])) {
3679                     // Output metrics proto bytes (base64) and nothing else
3680                     pw.print(metricsProtoDump);
3681                 } else {
3682                     // Tag the start and end of the metrics proto bytes
3683                     pw.println("WifiMetrics:");
3684                     pw.println(metricsProtoDump);
3685                     pw.println("EndWifiMetrics");
3686                 }
3687                 clear();
3688             } else {
3689                 pw.println("WifiMetrics:");
3690                 pw.println("mConnectionEvents:");
3691                 for (ConnectionEvent event : mConnectionEventList) {
3692                     String eventLine = event.toString();
3693                     if (mCurrentConnectionEventPerIface.containsValue(event)) {
3694                         eventLine += " CURRENTLY OPEN EVENT";
3695                     }
3696                     pw.println(eventLine);
3697                 }
3698                 pw.println("mWifiLogProto.numSavedNetworks=" + mWifiLogProto.numSavedNetworks);
3699                 pw.println("mWifiLogProto.numSavedNetworksWithMacRandomization="
3700                         + mWifiLogProto.numSavedNetworksWithMacRandomization);
3701                 pw.println("mWifiLogProto.numOpenNetworks=" + mWifiLogProto.numOpenNetworks);
3702                 pw.println("mWifiLogProto.numLegacyPersonalNetworks="
3703                         + mWifiLogProto.numLegacyPersonalNetworks);
3704                 pw.println("mWifiLogProto.numLegacyEnterpriseNetworks="
3705                         + mWifiLogProto.numLegacyEnterpriseNetworks);
3706                 pw.println("mWifiLogProto.numEnhancedOpenNetworks="
3707                         + mWifiLogProto.numEnhancedOpenNetworks);
3708                 pw.println("mWifiLogProto.numWpa3PersonalNetworks="
3709                         + mWifiLogProto.numWpa3PersonalNetworks);
3710                 pw.println("mWifiLogProto.numWpa3EnterpriseNetworks="
3711                         + mWifiLogProto.numWpa3EnterpriseNetworks);
3712                 pw.println("mWifiLogProto.numWapiPersonalNetworks="
3713                         + mWifiLogProto.numWapiPersonalNetworks);
3714                 pw.println("mWifiLogProto.numWapiEnterpriseNetworks="
3715                         + mWifiLogProto.numWapiEnterpriseNetworks);
3716                 pw.println("mWifiLogProto.numHiddenNetworks=" + mWifiLogProto.numHiddenNetworks);
3717                 pw.println("mWifiLogProto.numPasspointNetworks="
3718                         + mWifiLogProto.numPasspointNetworks);
3719                 pw.println("mWifiLogProto.isLocationEnabled=" + mWifiLogProto.isLocationEnabled);
3720                 pw.println("mWifiLogProto.isScanningAlwaysEnabled="
3721                         + mWifiLogProto.isScanningAlwaysEnabled);
3722                 pw.println("mWifiLogProto.isVerboseLoggingEnabled="
3723                         + mWifiLogProto.isVerboseLoggingEnabled);
3724                 pw.println("mWifiLogProto.isEnhancedMacRandomizationForceEnabled="
3725                         + mWifiLogProto.isEnhancedMacRandomizationForceEnabled);
3726                 pw.println("mWifiLogProto.isWifiWakeEnabled=" + mWifiLogProto.isWifiWakeEnabled);
3727                 pw.println("mWifiLogProto.numNetworksAddedByUser="
3728                         + mWifiLogProto.numNetworksAddedByUser);
3729                 pw.println("mWifiLogProto.numNetworksAddedByApps="
3730                         + mWifiLogProto.numNetworksAddedByApps);
3731                 pw.println("mWifiLogProto.numNonEmptyScanResults="
3732                         + mWifiLogProto.numNonEmptyScanResults);
3733                 pw.println("mWifiLogProto.numEmptyScanResults="
3734                         + mWifiLogProto.numEmptyScanResults);
3735                 pw.println("mWifiLogProto.numConnecitvityOneshotScans="
3736                         + mWifiLogProto.numConnectivityOneshotScans);
3737                 pw.println("mWifiLogProto.numOneshotScans="
3738                         + mWifiLogProto.numOneshotScans);
3739                 pw.println("mWifiLogProto.numOneshotHasDfsChannelScans="
3740                         + mWifiLogProto.numOneshotHasDfsChannelScans);
3741                 pw.println("mWifiLogProto.numBackgroundScans="
3742                         + mWifiLogProto.numBackgroundScans);
3743                 pw.println("mWifiLogProto.numExternalAppOneshotScanRequests="
3744                         + mWifiLogProto.numExternalAppOneshotScanRequests);
3745                 pw.println("mWifiLogProto.numExternalForegroundAppOneshotScanRequestsThrottled="
3746                         + mWifiLogProto.numExternalForegroundAppOneshotScanRequestsThrottled);
3747                 pw.println("mWifiLogProto.numExternalBackgroundAppOneshotScanRequestsThrottled="
3748                         + mWifiLogProto.numExternalBackgroundAppOneshotScanRequestsThrottled);
3749                 pw.println("mWifiLogProto.meteredNetworkStatsSaved=");
3750                 pw.println(mMeteredNetworkStatsBuilder.toProto(false));
3751                 pw.println("mWifiLogProto.meteredNetworkStatsSuggestion=");
3752                 pw.println(mMeteredNetworkStatsBuilder.toProto(true));
3753                 pw.println("mScanReturnEntries:");
3754                 pw.println("  SCAN_UNKNOWN: " + getScanReturnEntry(
3755                         WifiMetricsProto.WifiLog.SCAN_UNKNOWN));
3756                 pw.println("  SCAN_SUCCESS: " + getScanReturnEntry(
3757                         WifiMetricsProto.WifiLog.SCAN_SUCCESS));
3758                 pw.println("  SCAN_FAILURE_INTERRUPTED: " + getScanReturnEntry(
3759                         WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED));
3760                 pw.println("  SCAN_FAILURE_INVALID_CONFIGURATION: " + getScanReturnEntry(
3761                         WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION));
3762                 pw.println("  FAILURE_WIFI_DISABLED: " + getScanReturnEntry(
3763                         WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED));
3764 
3765                 pw.println("mSystemStateEntries: <state><screenOn> : <scansInitiated>");
3766                 pw.println("  WIFI_UNKNOWN       ON: "
3767                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, true));
3768                 pw.println("  WIFI_DISABLED      ON: "
3769                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, true));
3770                 pw.println("  WIFI_DISCONNECTED  ON: "
3771                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, true));
3772                 pw.println("  WIFI_ASSOCIATED    ON: "
3773                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, true));
3774                 pw.println("  WIFI_UNKNOWN      OFF: "
3775                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, false));
3776                 pw.println("  WIFI_DISABLED     OFF: "
3777                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, false));
3778                 pw.println("  WIFI_DISCONNECTED OFF: "
3779                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, false));
3780                 pw.println("  WIFI_ASSOCIATED   OFF: "
3781                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, false));
3782                 pw.println("mWifiLogProto.numConnectivityWatchdogPnoGood="
3783                         + mWifiLogProto.numConnectivityWatchdogPnoGood);
3784                 pw.println("mWifiLogProto.numConnectivityWatchdogPnoBad="
3785                         + mWifiLogProto.numConnectivityWatchdogPnoBad);
3786                 pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundGood="
3787                         + mWifiLogProto.numConnectivityWatchdogBackgroundGood);
3788                 pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundBad="
3789                         + mWifiLogProto.numConnectivityWatchdogBackgroundBad);
3790                 pw.println("mWifiLogProto.numLastResortWatchdogTriggers="
3791                         + mWifiLogProto.numLastResortWatchdogTriggers);
3792                 pw.println("mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal="
3793                         + mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal);
3794                 pw.println("mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal="
3795                         + mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal);
3796                 pw.println("mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal="
3797                         + mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal);
3798                 pw.println("mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal="
3799                         + mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal);
3800                 pw.println("mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal="
3801                         + mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal);
3802                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation="
3803                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation);
3804                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication="
3805                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication);
3806                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp="
3807                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp);
3808                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadOther="
3809                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadOther);
3810                 pw.println("mWifiLogProto.numLastResortWatchdogSuccesses="
3811                         + mWifiLogProto.numLastResortWatchdogSuccesses);
3812                 pw.println("mWifiLogProto.watchdogTotalConnectionFailureCountAfterTrigger="
3813                         + mWifiLogProto.watchdogTotalConnectionFailureCountAfterTrigger);
3814                 pw.println("mWifiLogProto.watchdogTriggerToConnectionSuccessDurationMs="
3815                         + mWifiLogProto.watchdogTriggerToConnectionSuccessDurationMs);
3816                 pw.println("mWifiLogProto.recordDurationSec="
3817                         + ((mClock.getElapsedSinceBootMillis() / 1000) - mRecordStartTimeSec));
3818 
3819                 try {
3820                     JSONObject rssiMap = new JSONObject();
3821                     for (Map.Entry<Integer, SparseIntArray> entry : mRssiPollCountsMap.entrySet()) {
3822                         int frequency = entry.getKey();
3823                         final SparseIntArray histogram = entry.getValue();
3824                         JSONArray histogramElements = new JSONArray();
3825                         for (int i = MIN_RSSI_POLL; i <= MAX_RSSI_POLL; i++) {
3826                             int count = histogram.get(i);
3827                             if (count == 0) {
3828                                 continue;
3829                             }
3830                             JSONObject histogramElement = new JSONObject();
3831                             histogramElement.put(Integer.toString(i), count);
3832                             histogramElements.put(histogramElement);
3833                         }
3834                         rssiMap.put(Integer.toString(frequency), histogramElements);
3835                     }
3836                     pw.println("mWifiLogProto.rssiPollCount: " + rssiMap.toString());
3837                 } catch (JSONException e) {
3838                     pw.println("JSONException occurred: " + e.getMessage());
3839                 }
3840 
3841                 pw.println("mWifiLogProto.rssiPollDeltaCount: Printing counts for ["
3842                         + MIN_RSSI_DELTA + ", " + MAX_RSSI_DELTA + "]");
3843                 StringBuilder sb = new StringBuilder();
3844                 for (int i = MIN_RSSI_DELTA; i <= MAX_RSSI_DELTA; i++) {
3845                     sb.append(mRssiDeltaCounts.get(i) + " ");
3846                 }
3847                 pw.println("  " + sb.toString());
3848                 pw.println("mWifiLogProto.linkSpeedCounts: ");
3849                 sb.setLength(0);
3850                 for (int i = 0; i < mLinkSpeedCounts.size(); i++) {
3851                     LinkSpeedCount linkSpeedCount = mLinkSpeedCounts.valueAt(i);
3852                     sb.append(linkSpeedCount.linkSpeedMbps).append(":{")
3853                             .append(linkSpeedCount.count).append(", ")
3854                             .append(linkSpeedCount.rssiSumDbm).append(", ")
3855                             .append(linkSpeedCount.rssiSumOfSquaresDbmSq).append("} ");
3856                 }
3857                 if (sb.length() > 0) {
3858                     pw.println(sb.toString());
3859                 }
3860                 pw.print("mWifiLogProto.alertReasonCounts=");
3861                 sb.setLength(0);
3862                 for (int i = WifiLoggerHal.WIFI_ALERT_REASON_MIN;
3863                         i <= WifiLoggerHal.WIFI_ALERT_REASON_MAX; i++) {
3864                     int count = mWifiAlertReasonCounts.get(i);
3865                     if (count > 0) {
3866                         sb.append("(" + i + "," + count + "),");
3867                     }
3868                 }
3869                 if (sb.length() > 1) {
3870                     sb.setLength(sb.length() - 1);  // strip trailing comma
3871                     pw.println(sb.toString());
3872                 } else {
3873                     pw.println("()");
3874                 }
3875                 pw.println("mWifiLogProto.numTotalScanResults="
3876                         + mWifiLogProto.numTotalScanResults);
3877                 pw.println("mWifiLogProto.numOpenNetworkScanResults="
3878                         + mWifiLogProto.numOpenNetworkScanResults);
3879                 pw.println("mWifiLogProto.numLegacyPersonalNetworkScanResults="
3880                         + mWifiLogProto.numLegacyPersonalNetworkScanResults);
3881                 pw.println("mWifiLogProto.numLegacyEnterpriseNetworkScanResults="
3882                         + mWifiLogProto.numLegacyEnterpriseNetworkScanResults);
3883                 pw.println("mWifiLogProto.numEnhancedOpenNetworkScanResults="
3884                         + mWifiLogProto.numEnhancedOpenNetworkScanResults);
3885                 pw.println("mWifiLogProto.numWpa3PersonalNetworkScanResults="
3886                         + mWifiLogProto.numWpa3PersonalNetworkScanResults);
3887                 pw.println("mWifiLogProto.numWpa3EnterpriseNetworkScanResults="
3888                         + mWifiLogProto.numWpa3EnterpriseNetworkScanResults);
3889                 pw.println("mWifiLogProto.numWapiPersonalNetworkScanResults="
3890                         + mWifiLogProto.numWapiPersonalNetworkScanResults);
3891                 pw.println("mWifiLogProto.numWapiEnterpriseNetworkScanResults="
3892                         + mWifiLogProto.numWapiEnterpriseNetworkScanResults);
3893                 pw.println("mWifiLogProto.numHiddenNetworkScanResults="
3894                         + mWifiLogProto.numHiddenNetworkScanResults);
3895                 pw.println("mWifiLogProto.numHotspot2R1NetworkScanResults="
3896                         + mWifiLogProto.numHotspot2R1NetworkScanResults);
3897                 pw.println("mWifiLogProto.numHotspot2R2NetworkScanResults="
3898                         + mWifiLogProto.numHotspot2R2NetworkScanResults);
3899                 pw.println("mWifiLogProto.numHotspot2R3NetworkScanResults="
3900                         + mWifiLogProto.numHotspot2R3NetworkScanResults);
3901                 pw.println("mWifiLogProto.numMboSupportedNetworkScanResults="
3902                         + mWifiLogProto.numMboSupportedNetworkScanResults);
3903                 pw.println("mWifiLogProto.numMboCellularDataAwareNetworkScanResults="
3904                         + mWifiLogProto.numMboCellularDataAwareNetworkScanResults);
3905                 pw.println("mWifiLogProto.numOceSupportedNetworkScanResults="
3906                         + mWifiLogProto.numOceSupportedNetworkScanResults);
3907                 pw.println("mWifiLogProto.numFilsSupportedNetworkScanResults="
3908                         + mWifiLogProto.numFilsSupportedNetworkScanResults);
3909                 pw.println("mWifiLogProto.num11AxNetworkScanResults="
3910                         + mWifiLogProto.num11AxNetworkScanResults);
3911                 pw.println("mWifiLogProto.num6GNetworkScanResults"
3912                         + mWifiLogProto.num6GNetworkScanResults);
3913                 pw.println("mWifiLogProto.num6GPscNetworkScanResults"
3914                         + mWifiLogProto.num6GPscNetworkScanResults);
3915                 pw.println("mWifiLogProto.numBssidFilteredDueToMboAssocDisallowInd="
3916                         + mWifiLogProto.numBssidFilteredDueToMboAssocDisallowInd);
3917                 pw.println("mWifiLogProto.numConnectToNetworkSupportingMbo="
3918                         + mWifiLogProto.numConnectToNetworkSupportingMbo);
3919                 pw.println("mWifiLogProto.numConnectToNetworkSupportingOce="
3920                         + mWifiLogProto.numConnectToNetworkSupportingOce);
3921                 pw.println("mWifiLogProto.numSteeringRequest="
3922                         + mWifiLogProto.numSteeringRequest);
3923                 pw.println("mWifiLogProto.numForceScanDueToSteeringRequest="
3924                         + mWifiLogProto.numForceScanDueToSteeringRequest);
3925                 pw.println("mWifiLogProto.numMboCellularSwitchRequest="
3926                         + mWifiLogProto.numMboCellularSwitchRequest);
3927                 pw.println("mWifiLogProto.numSteeringRequestIncludingMboAssocRetryDelay="
3928                         + mWifiLogProto.numSteeringRequestIncludingMboAssocRetryDelay);
3929                 pw.println("mWifiLogProto.numConnectRequestWithFilsAkm="
3930                         + mWifiLogProto.numConnectRequestWithFilsAkm);
3931                 pw.println("mWifiLogProto.numL2ConnectionThroughFilsAuthentication="
3932                         + mWifiLogProto.numL2ConnectionThroughFilsAuthentication);
3933                 pw.println("mWifiLogProto.recentFailureAssociationStatus="
3934                         + mRecentFailureAssociationStatus.toString());
3935 
3936                 pw.println("mWifiLogProto.numScans=" + mWifiLogProto.numScans);
3937                 pw.println("mWifiLogProto.WifiScoreCount: [" + MIN_WIFI_SCORE + ", "
3938                         + MAX_WIFI_SCORE + "]");
3939                 for (int i = 0; i <= MAX_WIFI_SCORE; i++) {
3940                     pw.print(mWifiScoreCounts.get(i) + " ");
3941                 }
3942                 pw.println(); // add a line after wifi scores
3943                 pw.println("mWifiLogProto.WifiUsabilityScoreCount: [" + MIN_WIFI_USABILITY_SCORE
3944                         + ", " + MAX_WIFI_USABILITY_SCORE + "]");
3945                 for (int i = MIN_WIFI_USABILITY_SCORE; i <= MAX_WIFI_USABILITY_SCORE; i++) {
3946                     pw.print(mWifiUsabilityScoreCounts.get(i) + " ");
3947                 }
3948                 pw.println(); // add a line after wifi usability scores
3949                 pw.println("mWifiLogProto.SoftApManagerReturnCodeCounts:");
3950                 pw.println("  SUCCESS: " + mSoftApManagerReturnCodeCounts.get(
3951                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY));
3952                 pw.println("  FAILED_GENERAL_ERROR: " + mSoftApManagerReturnCodeCounts.get(
3953                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR));
3954                 pw.println("  FAILED_NO_CHANNEL: " + mSoftApManagerReturnCodeCounts.get(
3955                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL));
3956                 pw.println("  FAILED_UNSUPPORTED_CONFIGURATION: "
3957                         + mSoftApManagerReturnCodeCounts.get(
3958                         WifiMetricsProto.SoftApReturnCodeCount
3959                         .SOFT_AP_FAILED_UNSUPPORTED_CONFIGURATION));
3960                 pw.print("\n");
3961                 pw.println("mWifiLogProto.numHalCrashes="
3962                         + mWifiLogProto.numHalCrashes);
3963                 pw.println("mWifiLogProto.numWificondCrashes="
3964                         + mWifiLogProto.numWificondCrashes);
3965                 pw.println("mWifiLogProto.numSupplicantCrashes="
3966                         + mWifiLogProto.numSupplicantCrashes);
3967                 pw.println("mWifiLogProto.numHostapdCrashes="
3968                         + mWifiLogProto.numHostapdCrashes);
3969                 pw.println("mWifiLogProto.numSetupClientInterfaceFailureDueToHal="
3970                         + mWifiLogProto.numSetupClientInterfaceFailureDueToHal);
3971                 pw.println("mWifiLogProto.numSetupClientInterfaceFailureDueToWificond="
3972                         + mWifiLogProto.numSetupClientInterfaceFailureDueToWificond);
3973                 pw.println("mWifiLogProto.numSetupClientInterfaceFailureDueToSupplicant="
3974                         + mWifiLogProto.numSetupClientInterfaceFailureDueToSupplicant);
3975                 pw.println("mWifiLogProto.numSetupSoftApInterfaceFailureDueToHal="
3976                         + mWifiLogProto.numSetupSoftApInterfaceFailureDueToHal);
3977                 pw.println("mWifiLogProto.numSetupSoftApInterfaceFailureDueToWificond="
3978                         + mWifiLogProto.numSetupSoftApInterfaceFailureDueToWificond);
3979                 pw.println("mWifiLogProto.numSetupSoftApInterfaceFailureDueToHostapd="
3980                         + mWifiLogProto.numSetupSoftApInterfaceFailureDueToHostapd);
3981                 pw.println("StaEventList:");
3982                 for (StaEventWithTime event : mStaEventList) {
3983                     pw.println(event);
3984                 }
3985                 pw.println("UserActionEvents:");
3986                 for (UserActionEventWithTime event : mUserActionEventList) {
3987                     pw.println(event);
3988                 }
3989 
3990                 pw.println("mWifiLogProto.numPasspointProviders="
3991                         + mWifiLogProto.numPasspointProviders);
3992                 pw.println("mWifiLogProto.numPasspointProviderInstallation="
3993                         + mWifiLogProto.numPasspointProviderInstallation);
3994                 pw.println("mWifiLogProto.numPasspointProviderInstallSuccess="
3995                         + mWifiLogProto.numPasspointProviderInstallSuccess);
3996                 pw.println("mWifiLogProto.numPasspointProviderUninstallation="
3997                         + mWifiLogProto.numPasspointProviderUninstallation);
3998                 pw.println("mWifiLogProto.numPasspointProviderUninstallSuccess="
3999                         + mWifiLogProto.numPasspointProviderUninstallSuccess);
4000                 pw.println("mWifiLogProto.numPasspointProvidersSuccessfullyConnected="
4001                         + mWifiLogProto.numPasspointProvidersSuccessfullyConnected);
4002 
4003                 pw.println("mWifiLogProto.installedPasspointProfileTypeForR1:"
4004                         + mInstalledPasspointProfileTypeForR1);
4005                 pw.println("mWifiLogProto.installedPasspointProfileTypeForR2:"
4006                         + mInstalledPasspointProfileTypeForR2);
4007 
4008                 pw.println("mWifiLogProto.passpointProvisionStats.numProvisionSuccess="
4009                         + mNumProvisionSuccess);
4010                 pw.println("mWifiLogProto.passpointProvisionStats.provisionFailureCount:"
4011                         + mPasspointProvisionFailureCounts);
4012                 pw.println("mWifiLogProto.totalNumberOfPasspointConnectionsWithVenueUrl="
4013                         + mWifiLogProto.totalNumberOfPasspointConnectionsWithVenueUrl);
4014                 pw.println(
4015                         "mWifiLogProto.totalNumberOfPasspointConnectionsWithTermsAndConditionsUrl="
4016                                 + mWifiLogProto
4017                                 .totalNumberOfPasspointConnectionsWithTermsAndConditionsUrl);
4018                 pw.println(
4019                         "mWifiLogProto"
4020                                 + ".totalNumberOfPasspointAcceptanceOfTermsAndConditions="
4021                                 + mWifiLogProto
4022                                 .totalNumberOfPasspointAcceptanceOfTermsAndConditions);
4023                 pw.println("mWifiLogProto.totalNumberOfPasspointProfilesWithDecoratedIdentity="
4024                         + mWifiLogProto.totalNumberOfPasspointProfilesWithDecoratedIdentity);
4025                 pw.println("mWifiLogProto.passpointDeauthImminentScope="
4026                         + mPasspointDeauthImminentScope.toString());
4027 
4028                 pw.println("mWifiLogProto.numRadioModeChangeToMcc="
4029                         + mWifiLogProto.numRadioModeChangeToMcc);
4030                 pw.println("mWifiLogProto.numRadioModeChangeToScc="
4031                         + mWifiLogProto.numRadioModeChangeToScc);
4032                 pw.println("mWifiLogProto.numRadioModeChangeToSbs="
4033                         + mWifiLogProto.numRadioModeChangeToSbs);
4034                 pw.println("mWifiLogProto.numRadioModeChangeToDbs="
4035                         + mWifiLogProto.numRadioModeChangeToDbs);
4036                 pw.println("mWifiLogProto.numSoftApUserBandPreferenceUnsatisfied="
4037                         + mWifiLogProto.numSoftApUserBandPreferenceUnsatisfied);
4038                 pw.println("mTotalSsidsInScanHistogram:"
4039                         + mTotalSsidsInScanHistogram.toString());
4040                 pw.println("mTotalBssidsInScanHistogram:"
4041                         + mTotalBssidsInScanHistogram.toString());
4042                 pw.println("mAvailableOpenSsidsInScanHistogram:"
4043                         + mAvailableOpenSsidsInScanHistogram.toString());
4044                 pw.println("mAvailableOpenBssidsInScanHistogram:"
4045                         + mAvailableOpenBssidsInScanHistogram.toString());
4046                 pw.println("mAvailableSavedSsidsInScanHistogram:"
4047                         + mAvailableSavedSsidsInScanHistogram.toString());
4048                 pw.println("mAvailableSavedBssidsInScanHistogram:"
4049                         + mAvailableSavedBssidsInScanHistogram.toString());
4050                 pw.println("mAvailableOpenOrSavedSsidsInScanHistogram:"
4051                         + mAvailableOpenOrSavedSsidsInScanHistogram.toString());
4052                 pw.println("mAvailableOpenOrSavedBssidsInScanHistogram:"
4053                         + mAvailableOpenOrSavedBssidsInScanHistogram.toString());
4054                 pw.println("mAvailableSavedPasspointProviderProfilesInScanHistogram:"
4055                         + mAvailableSavedPasspointProviderProfilesInScanHistogram.toString());
4056                 pw.println("mAvailableSavedPasspointProviderBssidsInScanHistogram:"
4057                         + mAvailableSavedPasspointProviderBssidsInScanHistogram.toString());
4058                 pw.println("mWifiLogProto.partialAllSingleScanListenerResults="
4059                         + mWifiLogProto.partialAllSingleScanListenerResults);
4060                 pw.println("mWifiLogProto.fullBandAllSingleScanListenerResults="
4061                         + mWifiLogProto.fullBandAllSingleScanListenerResults);
4062                 pw.println("mWifiAwareMetrics:");
4063                 mWifiAwareMetrics.dump(fd, pw, args);
4064                 pw.println("mRttMetrics:");
4065                 mRttMetrics.dump(fd, pw, args);
4066 
4067                 pw.println("mPnoScanMetrics.numPnoScanAttempts="
4068                         + mPnoScanMetrics.numPnoScanAttempts);
4069                 pw.println("mPnoScanMetrics.numPnoScanFailed="
4070                         + mPnoScanMetrics.numPnoScanFailed);
4071                 pw.println("mPnoScanMetrics.numPnoScanStartedOverOffload="
4072                         + mPnoScanMetrics.numPnoScanStartedOverOffload);
4073                 pw.println("mPnoScanMetrics.numPnoScanFailedOverOffload="
4074                         + mPnoScanMetrics.numPnoScanFailedOverOffload);
4075                 pw.println("mPnoScanMetrics.numPnoFoundNetworkEvents="
4076                         + mPnoScanMetrics.numPnoFoundNetworkEvents);
4077 
4078                 pw.println("mWifiLinkLayerUsageStats.loggingDurationMs="
4079                         + mWifiLinkLayerUsageStats.loggingDurationMs);
4080                 pw.println("mWifiLinkLayerUsageStats.radioOnTimeMs="
4081                         + mWifiLinkLayerUsageStats.radioOnTimeMs);
4082                 pw.println("mWifiLinkLayerUsageStats.radioTxTimeMs="
4083                         + mWifiLinkLayerUsageStats.radioTxTimeMs);
4084                 pw.println("mWifiLinkLayerUsageStats.radioRxTimeMs="
4085                         + mWifiLinkLayerUsageStats.radioRxTimeMs);
4086                 pw.println("mWifiLinkLayerUsageStats.radioScanTimeMs="
4087                         + mWifiLinkLayerUsageStats.radioScanTimeMs);
4088                 pw.println("mWifiLinkLayerUsageStats.radioNanScanTimeMs="
4089                         + mWifiLinkLayerUsageStats.radioNanScanTimeMs);
4090                 pw.println("mWifiLinkLayerUsageStats.radioBackgroundScanTimeMs="
4091                         + mWifiLinkLayerUsageStats.radioBackgroundScanTimeMs);
4092                 pw.println("mWifiLinkLayerUsageStats.radioRoamScanTimeMs="
4093                         + mWifiLinkLayerUsageStats.radioRoamScanTimeMs);
4094                 pw.println("mWifiLinkLayerUsageStats.radioPnoScanTimeMs="
4095                         + mWifiLinkLayerUsageStats.radioPnoScanTimeMs);
4096                 pw.println("mWifiLinkLayerUsageStats.radioHs20ScanTimeMs="
4097                         + mWifiLinkLayerUsageStats.radioHs20ScanTimeMs);
4098                 pw.println("mWifiLinkLayerUsageStats per Radio Stats: ");
4099                 for (int i = 0; i < mRadioStats.size(); i++) {
4100                     RadioStats radioStat = mRadioStats.valueAt(i);
4101                     pw.println("radioId=" + radioStat.radioId);
4102                     pw.println("totalRadioOnTimeMs=" + radioStat.totalRadioOnTimeMs);
4103                     pw.println("totalRadioTxTimeMs=" + radioStat.totalRadioTxTimeMs);
4104                     pw.println("totalRadioRxTimeMs=" + radioStat.totalRadioRxTimeMs);
4105                     pw.println("totalScanTimeMs=" + radioStat.totalScanTimeMs);
4106                     pw.println("totalNanScanTimeMs=" + radioStat.totalNanScanTimeMs);
4107                     pw.println("totalBackgroundScanTimeMs=" + radioStat.totalBackgroundScanTimeMs);
4108                     pw.println("totalRoamScanTimeMs=" + radioStat.totalRoamScanTimeMs);
4109                     pw.println("totalPnoScanTimeMs=" + radioStat.totalPnoScanTimeMs);
4110                     pw.println("totalHotspot2ScanTimeMs=" + radioStat.totalHotspot2ScanTimeMs);
4111                 }
4112 
4113                 pw.println("mWifiLogProto.connectToNetworkNotificationCount="
4114                         + mConnectToNetworkNotificationCount.toString());
4115                 pw.println("mWifiLogProto.connectToNetworkNotificationActionCount="
4116                         + mConnectToNetworkNotificationActionCount.toString());
4117                 pw.println("mWifiLogProto.openNetworkRecommenderBlocklistSize="
4118                         + mOpenNetworkRecommenderBlocklistSize);
4119                 pw.println("mWifiLogProto.isWifiNetworksAvailableNotificationOn="
4120                         + mIsWifiNetworksAvailableNotificationOn);
4121                 pw.println("mWifiLogProto.numOpenNetworkRecommendationUpdates="
4122                         + mNumOpenNetworkRecommendationUpdates);
4123                 pw.println("mWifiLogProto.numOpenNetworkConnectMessageFailedToSend="
4124                         + mNumOpenNetworkConnectMessageFailedToSend);
4125 
4126                 pw.println("mWifiLogProto.observedHotspotR1ApInScanHistogram="
4127                         + mObservedHotspotR1ApInScanHistogram);
4128                 pw.println("mWifiLogProto.observedHotspotR2ApInScanHistogram="
4129                         + mObservedHotspotR2ApInScanHistogram);
4130                 pw.println("mWifiLogProto.observedHotspotR3ApInScanHistogram="
4131                         + mObservedHotspotR3ApInScanHistogram);
4132                 pw.println("mWifiLogProto.observedHotspotR1EssInScanHistogram="
4133                         + mObservedHotspotR1EssInScanHistogram);
4134                 pw.println("mWifiLogProto.observedHotspotR2EssInScanHistogram="
4135                         + mObservedHotspotR2EssInScanHistogram);
4136                 pw.println("mWifiLogProto.observedHotspotR3EssInScanHistogram="
4137                         + mObservedHotspotR3EssInScanHistogram);
4138                 pw.println("mWifiLogProto.observedHotspotR1ApsPerEssInScanHistogram="
4139                         + mObservedHotspotR1ApsPerEssInScanHistogram);
4140                 pw.println("mWifiLogProto.observedHotspotR2ApsPerEssInScanHistogram="
4141                         + mObservedHotspotR2ApsPerEssInScanHistogram);
4142                 pw.println("mWifiLogProto.observedHotspotR3ApsPerEssInScanHistogram="
4143                         + mObservedHotspotR3ApsPerEssInScanHistogram);
4144 
4145                 pw.println("mWifiLogProto.observed80211mcSupportingApsInScanHistogram"
4146                         + mObserved80211mcApInScanHistogram);
4147                 pw.println("mWifiLogProto.CountryCodeScanHistogram="
4148                         + mCountryCodeScanHistogram.toString());
4149                 pw.println("mWifiLogProto.bssidBlocklistStats:");
4150                 pw.println(mBssidBlocklistStats.toString());
4151 
4152                 pw.println("mSoftApTetheredEvents:");
4153                 for (SoftApConnectedClientsEvent event : mSoftApEventListTethered) {
4154                     StringBuilder eventLine = new StringBuilder();
4155                     eventLine.append("event_type=" + event.eventType);
4156                     eventLine.append(",time_stamp_millis=" + event.timeStampMillis);
4157                     eventLine.append(",num_connected_clients=" + event.numConnectedClients);
4158                     eventLine.append(",num_connected_clients_on_current_frequency="
4159                             + event.numConnectedClientsOnCurrentFrequency);
4160                     eventLine.append(",channel_frequency=" + event.channelFrequency);
4161                     eventLine.append(",channel_bandwidth=" + event.channelBandwidth);
4162                     eventLine.append(",generation=" + event.generation);
4163                     eventLine.append(",max_num_clients_setting_in_softap_configuration="
4164                             + event.maxNumClientsSettingInSoftapConfiguration);
4165                     eventLine.append(",max_num_clients_setting_in_softap_capability="
4166                             + event.maxNumClientsSettingInSoftapCapability);
4167                     eventLine.append(",shutdown_timeout_setting_in_softap_configuration="
4168                             + event.shutdownTimeoutSettingInSoftapConfiguration);
4169                     eventLine.append(",default_shutdown_timeout_setting="
4170                             + event.defaultShutdownTimeoutSetting);
4171                     eventLine.append(",client_control_is_enabled=" + event.clientControlIsEnabled);
4172                     pw.println(eventLine.toString());
4173                 }
4174                 pw.println("mSoftApLocalOnlyEvents:");
4175                 for (SoftApConnectedClientsEvent event : mSoftApEventListLocalOnly) {
4176                     StringBuilder eventLine = new StringBuilder();
4177                     eventLine.append("event_type=" + event.eventType);
4178                     eventLine.append(",time_stamp_millis=" + event.timeStampMillis);
4179                     eventLine.append(",num_connected_clients=" + event.numConnectedClients);
4180                     eventLine.append(",num_connected_clients_on_current_frequency="
4181                             + event.numConnectedClientsOnCurrentFrequency);
4182                     eventLine.append(",channel_frequency=" + event.channelFrequency);
4183                     eventLine.append(",channel_bandwidth=" + event.channelBandwidth);
4184                     eventLine.append(",generation=" + event.generation);
4185                     eventLine.append(",max_num_clients_setting_in_softap_configuration="
4186                             + event.maxNumClientsSettingInSoftapConfiguration);
4187                     eventLine.append(",max_num_clients_setting_in_softap_capability="
4188                             + event.maxNumClientsSettingInSoftapCapability);
4189                     eventLine.append(",shutdown_timeout_setting_in_softap_configuration="
4190                             + event.shutdownTimeoutSettingInSoftapConfiguration);
4191                     eventLine.append(",default_shutdown_timeout_setting="
4192                             + event.defaultShutdownTimeoutSetting);
4193                     eventLine.append(",client_control_is_enabled=" + event.clientControlIsEnabled);
4194                     pw.println(eventLine.toString());
4195                 }
4196 
4197                 mWifiPowerMetrics.dump(pw);
4198                 mWifiWakeMetrics.dump(pw);
4199 
4200                 pw.println("mWifiLogProto.isMacRandomizationOn="
4201                         + mContext.getResources().getBoolean(
4202                                 R.bool.config_wifi_connected_mac_randomization_supported));
4203                 pw.println("mWifiLogProto.scoreExperimentId=" + mWifiLogProto.scoreExperimentId);
4204                 pw.println("mExperimentValues.wifiIsUnusableLoggingEnabled="
4205                         + mContext.getResources().getBoolean(
4206                                 R.bool.config_wifiIsUnusableEventMetricsEnabled));
4207                 pw.println("mExperimentValues.wifiDataStallMinTxBad="
4208                         + mContext.getResources().getInteger(
4209                                 R.integer.config_wifiDataStallMinTxBad));
4210                 pw.println("mExperimentValues.wifiDataStallMinTxSuccessWithoutRx="
4211                         + mContext.getResources().getInteger(
4212                                 R.integer.config_wifiDataStallMinTxSuccessWithoutRx));
4213                 pw.println("mExperimentValues.linkSpeedCountsLoggingEnabled="
4214                         + mContext.getResources().getBoolean(
4215                                 R.bool.config_wifiLinkSpeedMetricsEnabled));
4216                 pw.println("mExperimentValues.dataStallDurationMs="
4217                         + mExperimentValues.dataStallDurationMs);
4218                 pw.println("mExperimentValues.dataStallTxTputThrKbps="
4219                         + mExperimentValues.dataStallTxTputThrKbps);
4220                 pw.println("mExperimentValues.dataStallRxTputThrKbps="
4221                         + mExperimentValues.dataStallRxTputThrKbps);
4222                 pw.println("mExperimentValues.dataStallTxPerThr="
4223                         + mExperimentValues.dataStallTxPerThr);
4224                 pw.println("mExperimentValues.dataStallCcaLevelThr="
4225                         + mExperimentValues.dataStallCcaLevelThr);
4226                 pw.println("WifiIsUnusableEventList: ");
4227                 for (WifiIsUnusableWithTime event : mWifiIsUnusableList) {
4228                     pw.println(event);
4229                 }
4230                 pw.println("Hardware Version: " + SystemProperties.get("ro.boot.revision", ""));
4231 
4232                 pw.println("mWifiUsabilityStatsEntriesList:");
4233                 for (WifiUsabilityStatsEntry stats : mWifiUsabilityStatsEntriesList) {
4234                     printWifiUsabilityStatsEntry(pw, stats);
4235                 }
4236                 pw.println("mWifiUsabilityStatsList:");
4237                 for (WifiUsabilityStats stats : mWifiUsabilityStatsListGood) {
4238                     pw.println("\nlabel=" + stats.label);
4239                     pw.println("\ntrigger_type=" + stats.triggerType);
4240                     pw.println("\ntime_stamp_ms=" + stats.timeStampMs);
4241                     for (WifiUsabilityStatsEntry entry : stats.stats) {
4242                         printWifiUsabilityStatsEntry(pw, entry);
4243                     }
4244                 }
4245                 for (WifiUsabilityStats stats : mWifiUsabilityStatsListBad) {
4246                     pw.println("\nlabel=" + stats.label);
4247                     pw.println("\ntrigger_type=" + stats.triggerType);
4248                     pw.println("\ntime_stamp_ms=" + stats.timeStampMs);
4249                     for (WifiUsabilityStatsEntry entry : stats.stats) {
4250                         printWifiUsabilityStatsEntry(pw, entry);
4251                     }
4252                 }
4253 
4254                 pw.println("mMobilityStatePnoStatsMap:");
4255                 for (int i = 0; i < mMobilityStatePnoStatsMap.size(); i++) {
4256                     printDeviceMobilityStatePnoScanStats(pw, mMobilityStatePnoStatsMap.valueAt(i));
4257                 }
4258 
4259                 mWifiP2pMetrics.dump(pw);
4260                 pw.println("mDppMetrics:");
4261                 mDppMetrics.dump(pw);
4262 
4263                 pw.println("mWifiConfigStoreReadDurationHistogram:"
4264                         + mWifiConfigStoreReadDurationHistogram.toString());
4265                 pw.println("mWifiConfigStoreWriteDurationHistogram:"
4266                         + mWifiConfigStoreWriteDurationHistogram.toString());
4267 
4268                 pw.println("mLinkProbeSuccessRssiCounts:" + mLinkProbeSuccessRssiCounts);
4269                 pw.println("mLinkProbeFailureRssiCounts:" + mLinkProbeFailureRssiCounts);
4270                 pw.println("mLinkProbeSuccessLinkSpeedCounts:" + mLinkProbeSuccessLinkSpeedCounts);
4271                 pw.println("mLinkProbeFailureLinkSpeedCounts:" + mLinkProbeFailureLinkSpeedCounts);
4272                 pw.println("mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram:"
4273                         + mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram);
4274                 pw.println("mLinkProbeFailureSecondsSinceLastTxSuccessHistogram:"
4275                         + mLinkProbeFailureSecondsSinceLastTxSuccessHistogram);
4276                 pw.println("mLinkProbeSuccessElapsedTimeMsHistogram:"
4277                         + mLinkProbeSuccessElapsedTimeMsHistogram);
4278                 pw.println("mLinkProbeFailureReasonCounts:" + mLinkProbeFailureReasonCounts);
4279                 pw.println("mLinkProbeExperimentProbeCounts:" + mLinkProbeExperimentProbeCounts);
4280 
4281                 pw.println("mNetworkSelectionExperimentPairNumChoicesCounts:"
4282                         + mNetworkSelectionExperimentPairNumChoicesCounts);
4283                 pw.println("mLinkProbeStaEventCount:" + mLinkProbeStaEventCount);
4284 
4285                 pw.println("mWifiNetworkRequestApiLog:\n" + mWifiNetworkRequestApiLog);
4286                 pw.println("mWifiNetworkRequestApiMatchSizeHistogram:\n"
4287                         + mWifiNetworkRequestApiMatchSizeHistogram);
4288                 pw.println("mWifiNetworkRequestApiConnectionDurationSecOnPrimaryIfaceHistogram:\n"
4289                         + mWifiNetworkRequestApiConnectionDurationSecOnPrimaryIfaceHistogram);
4290                 pw.println("mWifiNetworkRequestApiConnectionDurationSecOnSecondaryIfaceHistogram:\n"
4291                         + mWifiNetworkRequestApiConnectionDurationSecOnSecondaryIfaceHistogram);
4292                 pw.println("mWifiNetworkRequestApiConcurrentConnectionDurationSecHistogram:\n"
4293                         + mWifiNetworkRequestApiConcurrentConnectionDurationSecHistogram);
4294                 pw.println("mWifiNetworkSuggestionApiLog:\n" + mWifiNetworkSuggestionApiLog);
4295                 pw.println("mWifiNetworkSuggestionApiMatchSizeHistogram:\n"
4296                         + mWifiNetworkSuggestionApiListSizeHistogram);
4297                 pw.println("mWifiNetworkSuggestionApiAppTypeCounter:\n"
4298                         + mWifiNetworkSuggestionApiAppTypeCounter);
4299                 pw.println("mWifiNetworkSuggestionPriorityGroups:\n"
4300                         + mWifiNetworkSuggestionPriorityGroups.toString());
4301                 pw.println("mWifiNetworkSuggestionCoexistSavedNetworks:\n"
4302                         + mWifiNetworkSuggestionCoexistSavedNetworks.toString());
4303                 printUserApprovalSuggestionAppReaction(pw);
4304                 printUserApprovalCarrierReaction(pw);
4305                 pw.println("mNetworkIdToNominatorId:\n" + mNetworkIdToNominatorId);
4306                 pw.println("mWifiLockStats:\n" + mWifiLockStats);
4307                 pw.println("mWifiLockHighPerfAcqDurationSecHistogram:\n"
4308                         + mWifiLockHighPerfAcqDurationSecHistogram);
4309                 pw.println("mWifiLockLowLatencyAcqDurationSecHistogram:\n"
4310                         + mWifiLockLowLatencyAcqDurationSecHistogram);
4311                 pw.println("mWifiLockHighPerfActiveSessionDurationSecHistogram:\n"
4312                         + mWifiLockHighPerfActiveSessionDurationSecHistogram);
4313                 pw.println("mWifiLockLowLatencyActiveSessionDurationSecHistogram:\n"
4314                         + mWifiLockLowLatencyActiveSessionDurationSecHistogram);
4315                 pw.println("mWifiToggleStats:\n" + mWifiToggleStats);
4316                 pw.println("mWifiLogProto.numAddOrUpdateNetworkCalls="
4317                         + mWifiLogProto.numAddOrUpdateNetworkCalls);
4318                 pw.println("mWifiLogProto.numEnableNetworkCalls="
4319                         + mWifiLogProto.numEnableNetworkCalls);
4320 
4321                 pw.println("mWifiLogProto.txLinkSpeedCount2g=" + mTxLinkSpeedCount2g);
4322                 pw.println("mWifiLogProto.txLinkSpeedCount5gLow=" + mTxLinkSpeedCount5gLow);
4323                 pw.println("mWifiLogProto.txLinkSpeedCount5gMid=" + mTxLinkSpeedCount5gMid);
4324                 pw.println("mWifiLogProto.txLinkSpeedCount5gHigh=" + mTxLinkSpeedCount5gHigh);
4325                 pw.println("mWifiLogProto.txLinkSpeedCount6gLow=" + mTxLinkSpeedCount6gLow);
4326                 pw.println("mWifiLogProto.txLinkSpeedCount6gMid=" + mTxLinkSpeedCount6gMid);
4327                 pw.println("mWifiLogProto.txLinkSpeedCount6gHigh=" + mTxLinkSpeedCount6gHigh);
4328 
4329                 pw.println("mWifiLogProto.rxLinkSpeedCount2g=" + mRxLinkSpeedCount2g);
4330                 pw.println("mWifiLogProto.rxLinkSpeedCount5gLow=" + mRxLinkSpeedCount5gLow);
4331                 pw.println("mWifiLogProto.rxLinkSpeedCount5gMid=" + mRxLinkSpeedCount5gMid);
4332                 pw.println("mWifiLogProto.rxLinkSpeedCount5gHigh=" + mRxLinkSpeedCount5gHigh);
4333                 pw.println("mWifiLogProto.rxLinkSpeedCount6gLow=" + mRxLinkSpeedCount6gLow);
4334                 pw.println("mWifiLogProto.rxLinkSpeedCount6gMid=" + mRxLinkSpeedCount6gMid);
4335                 pw.println("mWifiLogProto.rxLinkSpeedCount6gHigh=" + mRxLinkSpeedCount6gHigh);
4336 
4337                 pw.println("mWifiLogProto.numIpRenewalFailure="
4338                         + mWifiLogProto.numIpRenewalFailure);
4339                 pw.println("mWifiLogProto.connectionDurationStats="
4340                         + mConnectionDurationStats.toString());
4341                 pw.println("mWifiLogProto.isExternalWifiScorerOn="
4342                         + mWifiLogProto.isExternalWifiScorerOn);
4343                 pw.println("mWifiLogProto.wifiOffMetrics="
4344                         + mWifiOffMetrics.toString());
4345                 pw.println("mWifiLogProto.softApConfigLimitationMetrics="
4346                         + mSoftApConfigLimitationMetrics.toString());
4347                 pw.println("mChannelUtilizationHistogram2G:\n"
4348                         + mChannelUtilizationHistogram2G);
4349                 pw.println("mChannelUtilizationHistogramAbove2G:\n"
4350                         + mChannelUtilizationHistogramAbove2G);
4351                 pw.println("mTxThroughputMbpsHistogram2G:\n"
4352                         + mTxThroughputMbpsHistogram2G);
4353                 pw.println("mRxThroughputMbpsHistogram2G:\n"
4354                         + mRxThroughputMbpsHistogram2G);
4355                 pw.println("mTxThroughputMbpsHistogramAbove2G:\n"
4356                         + mTxThroughputMbpsHistogramAbove2G);
4357                 pw.println("mRxThroughputMbpsHistogramAbove2G:\n"
4358                         + mRxThroughputMbpsHistogramAbove2G);
4359                 pw.println("mCarrierWifiMetrics:\n"
4360                         + mCarrierWifiMetrics);
4361                 pw.println(firstConnectAfterBootStatsToString(mFirstConnectAfterBootStats));
4362                 pw.println(wifiToWifiSwitchStatsToString(mWifiToWifiSwitchStats));
4363 
4364                 dumpInitPartialScanMetrics(pw);
4365             }
4366         }
4367     }
4368 
dumpInitPartialScanMetrics(PrintWriter pw)4369     private void dumpInitPartialScanMetrics(PrintWriter pw) {
4370         pw.println("mInitPartialScanTotalCount:\n" + mInitPartialScanTotalCount);
4371         pw.println("mInitPartialScanSuccessCount:\n" + mInitPartialScanSuccessCount);
4372         pw.println("mInitPartialScanFailureCount:\n" + mInitPartialScanFailureCount);
4373         pw.println("mInitPartialScanSuccessHistogram:\n" + mInitPartialScanSuccessHistogram);
4374         pw.println("mInitPartialScanFailureHistogram:\n" + mInitPartialScanFailureHistogram);
4375     }
4376 
printWifiUsabilityStatsEntry(PrintWriter pw, WifiUsabilityStatsEntry entry)4377     private void printWifiUsabilityStatsEntry(PrintWriter pw, WifiUsabilityStatsEntry entry) {
4378         StringBuilder line = new StringBuilder();
4379         line.append("timestamp_ms=" + entry.timeStampMs);
4380         line.append(",rssi=" + entry.rssi);
4381         line.append(",link_speed_mbps=" + entry.linkSpeedMbps);
4382         line.append(",total_tx_success=" + entry.totalTxSuccess);
4383         line.append(",total_tx_retries=" + entry.totalTxRetries);
4384         line.append(",total_tx_bad=" + entry.totalTxBad);
4385         line.append(",total_rx_success=" + entry.totalRxSuccess);
4386         if (entry.radioStats != null) {
4387             for (RadioStats radioStat : entry.radioStats) {
4388                 line.append(",Radio Stats from radio_id=" + radioStat.radioId);
4389                 line.append(",radio_on_time_ms=" + radioStat.totalRadioOnTimeMs);
4390                 line.append(",radio_tx_time_ms=" + radioStat.totalRadioTxTimeMs);
4391                 line.append(",radio_rx_time_ms=" + radioStat.totalRadioRxTimeMs);
4392                 line.append(",scan_time_ms=" + radioStat.totalScanTimeMs);
4393                 line.append(",nan_scan_time_ms=" + radioStat.totalNanScanTimeMs);
4394                 line.append(",background_scan_time_ms=" + radioStat.totalBackgroundScanTimeMs);
4395                 line.append(",roam_scan_time_ms=" + radioStat.totalRoamScanTimeMs);
4396                 line.append(",pno_scan_time_ms=" + radioStat.totalPnoScanTimeMs);
4397                 line.append(",hotspot_2_scan_time_ms=" + radioStat.totalHotspot2ScanTimeMs);
4398             }
4399         }
4400         line.append(",total_radio_on_time_ms=" + entry.totalRadioOnTimeMs);
4401         line.append(",total_radio_tx_time_ms=" + entry.totalRadioTxTimeMs);
4402         line.append(",total_radio_rx_time_ms=" + entry.totalRadioRxTimeMs);
4403         line.append(",total_scan_time_ms=" + entry.totalScanTimeMs);
4404         line.append(",total_nan_scan_time_ms=" + entry.totalNanScanTimeMs);
4405         line.append(",total_background_scan_time_ms=" + entry.totalBackgroundScanTimeMs);
4406         line.append(",total_roam_scan_time_ms=" + entry.totalRoamScanTimeMs);
4407         line.append(",total_pno_scan_time_ms=" + entry.totalPnoScanTimeMs);
4408         line.append(",total_hotspot_2_scan_time_ms=" + entry.totalHotspot2ScanTimeMs);
4409         line.append(",wifi_score=" + entry.wifiScore);
4410         line.append(",wifi_usability_score=" + entry.wifiUsabilityScore);
4411         line.append(",seq_num_to_framework=" + entry.seqNumToFramework);
4412         line.append(",prediction_horizon_sec=" + entry.predictionHorizonSec);
4413         line.append(",total_cca_busy_freq_time_ms=" + entry.totalCcaBusyFreqTimeMs);
4414         line.append(",total_radio_on_freq_time_ms=" + entry.totalRadioOnFreqTimeMs);
4415         line.append(",total_beacon_rx=" + entry.totalBeaconRx);
4416         line.append(",probe_status_since_last_update=" + entry.probeStatusSinceLastUpdate);
4417         line.append(",probe_elapsed_time_ms_since_last_update="
4418                 + entry.probeElapsedTimeSinceLastUpdateMs);
4419         line.append(",probe_mcs_rate_since_last_update=" + entry.probeMcsRateSinceLastUpdate);
4420         line.append(",rx_link_speed_mbps=" + entry.rxLinkSpeedMbps);
4421         line.append(",seq_num_inside_framework=" + entry.seqNumInsideFramework);
4422         line.append(",is_same_bssid_and_freq=" + entry.isSameBssidAndFreq);
4423         line.append(",device_mobility_state=" + entry.deviceMobilityState);
4424         line.append(",time_slice_duty_cycle_in_percent=" + entry.timeSliceDutyCycleInPercent);
4425         if (entry.contentionTimeStats != null) {
4426             for (ContentionTimeStats stat : entry.contentionTimeStats) {
4427                 line.append(",access_category=" + stat.accessCategory);
4428                 line.append(",contention_time_min_micros=" + stat.contentionTimeMinMicros);
4429                 line.append(",contention_time_max_micros=" + stat.contentionTimeMaxMicros);
4430                 line.append(",contention_time_avg_micros=" + stat.contentionTimeAvgMicros);
4431                 line.append(",contention_num_samples=" + stat.contentionNumSamples);
4432             }
4433         }
4434         line.append(",channel_utilization_ratio=" + entry.channelUtilizationRatio);
4435         line.append(",is_throughput_sufficient=" + entry.isThroughputSufficient);
4436         line.append(",is_wifi_scoring_enabled=" + entry.isWifiScoringEnabled);
4437         line.append(",is_cellular_data_available=" + entry.isCellularDataAvailable);
4438         line.append(",sta_count=" + entry.staCount);
4439         line.append(",channel_utilization=" + entry.channelUtilization);
4440         if (entry.rateStats != null) {
4441             for (RateStats rateStat : entry.rateStats) {
4442                 line.append(",preamble=" + rateStat.preamble);
4443                 line.append(",nss=" + rateStat.nss);
4444                 line.append(",bw=" + rateStat.bw);
4445                 line.append(",rate_mcs_idx=" + rateStat.rateMcsIdx);
4446                 line.append(",bit_rate_in_kbps=" + rateStat.bitRateInKbps);
4447                 line.append(",tx_mpdu=" + rateStat.txMpdu);
4448                 line.append(",rx_mpdu=" + rateStat.rxMpdu);
4449                 line.append(",mpdu_lost=" + rateStat.mpduLost);
4450                 line.append(",retries=" + rateStat.retries);
4451             }
4452         }
4453         pw.println(line.toString());
4454     }
4455 
printDeviceMobilityStatePnoScanStats(PrintWriter pw, DeviceMobilityStatePnoScanStats stats)4456     private void printDeviceMobilityStatePnoScanStats(PrintWriter pw,
4457             DeviceMobilityStatePnoScanStats stats) {
4458         StringBuilder line = new StringBuilder();
4459         line.append("device_mobility_state=" + stats.deviceMobilityState);
4460         line.append(",num_times_entered_state=" + stats.numTimesEnteredState);
4461         line.append(",total_duration_ms=" + stats.totalDurationMs);
4462         line.append(",pno_duration_ms=" + stats.pnoDurationMs);
4463         pw.println(line.toString());
4464     }
4465 
printUserApprovalSuggestionAppReaction(PrintWriter pw)4466     private void printUserApprovalSuggestionAppReaction(PrintWriter pw) {
4467         pw.println("mUserApprovalSuggestionAppUiUserReaction:");
4468         for (UserReaction event : mUserApprovalSuggestionAppUiReactionList) {
4469             pw.println(event);
4470         }
4471     }
4472 
printUserApprovalCarrierReaction(PrintWriter pw)4473     private void printUserApprovalCarrierReaction(PrintWriter pw) {
4474         pw.println("mUserApprovalCarrierUiUserReaction:");
4475         for (UserReaction event : mUserApprovalCarrierUiReactionList) {
4476             pw.println(event);
4477         }
4478     }
4479 
4480     /**
4481      * Update various counts of saved network types
4482      * @param networks List of WifiConfigurations representing all saved networks, must not be null
4483      */
updateSavedNetworks(List<WifiConfiguration> networks)4484     public void updateSavedNetworks(List<WifiConfiguration> networks) {
4485         synchronized (mLock) {
4486             mWifiLogProto.numSavedNetworks = networks.size();
4487             mWifiLogProto.numSavedNetworksWithMacRandomization = 0;
4488             mWifiLogProto.numOpenNetworks = 0;
4489             mWifiLogProto.numLegacyPersonalNetworks = 0;
4490             mWifiLogProto.numLegacyEnterpriseNetworks = 0;
4491             mWifiLogProto.numEnhancedOpenNetworks = 0;
4492             mWifiLogProto.numWpa3PersonalNetworks = 0;
4493             mWifiLogProto.numWpa3EnterpriseNetworks = 0;
4494             mWifiLogProto.numWapiPersonalNetworks = 0;
4495             mWifiLogProto.numWapiEnterpriseNetworks = 0;
4496             mWifiLogProto.numNetworksAddedByUser = 0;
4497             mWifiLogProto.numNetworksAddedByApps = 0;
4498             mWifiLogProto.numHiddenNetworks = 0;
4499             mWifiLogProto.numPasspointNetworks = 0;
4500 
4501             for (WifiConfiguration config : networks) {
4502                 if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_OPEN)) {
4503                     mWifiLogProto.numOpenNetworks++;
4504                 } else if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_OWE)) {
4505                     mWifiLogProto.numEnhancedOpenNetworks++;
4506                 } else if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_WAPI_PSK)) {
4507                     mWifiLogProto.numWapiPersonalNetworks++;
4508                 } else if (config.isEnterprise()) {
4509                     if (config.isSecurityType(
4510                             WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT)) {
4511                         mWifiLogProto.numWpa3EnterpriseNetworks++;
4512                     } else if (config.isSecurityType(
4513                             WifiConfiguration.SECURITY_TYPE_WAPI_CERT)) {
4514                         mWifiLogProto.numWapiEnterpriseNetworks++;
4515                     } else {
4516                         mWifiLogProto.numLegacyEnterpriseNetworks++;
4517                     }
4518                 } else {
4519                     if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_PSK)) {
4520                         mWifiLogProto.numLegacyPersonalNetworks++;
4521                     }
4522                     else if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_SAE)) {
4523                         mWifiLogProto.numWpa3PersonalNetworks++;
4524                     }
4525                 }
4526                 mWifiLogProto.numNetworksAddedByApps++;
4527                 if (config.hiddenSSID) {
4528                     mWifiLogProto.numHiddenNetworks++;
4529                 }
4530                 if (config.isPasspoint()) {
4531                     mWifiLogProto.numPasspointNetworks++;
4532                 }
4533                 if (config.macRandomizationSetting != WifiConfiguration.RANDOMIZATION_NONE) {
4534                     mWifiLogProto.numSavedNetworksWithMacRandomization++;
4535                 }
4536             }
4537         }
4538     }
4539 
4540     /**
4541      * Update metrics for saved Passpoint profiles.
4542      *
4543      * @param numSavedProfiles The number of saved Passpoint profiles
4544      * @param numConnectedProfiles The number of saved Passpoint profiles that have ever resulted
4545      *                             in a successful network connection
4546      */
updateSavedPasspointProfiles(int numSavedProfiles, int numConnectedProfiles)4547     public void updateSavedPasspointProfiles(int numSavedProfiles, int numConnectedProfiles) {
4548         synchronized (mLock) {
4549             mWifiLogProto.numPasspointProviders = numSavedProfiles;
4550             mWifiLogProto.numPasspointProvidersSuccessfullyConnected = numConnectedProfiles;
4551         }
4552     }
4553 
4554     /**
4555      * Update number of times for type of saved Passpoint profile.
4556      *
4557      * @param providers Passpoint providers installed on the device.
4558      */
updateSavedPasspointProfilesInfo( Map<String, PasspointProvider> providers)4559     public void updateSavedPasspointProfilesInfo(
4560             Map<String, PasspointProvider> providers) {
4561         int passpointType;
4562         int eapType;
4563         PasspointConfiguration config;
4564         synchronized (mLock) {
4565             mInstalledPasspointProfileTypeForR1.clear();
4566             mInstalledPasspointProfileTypeForR2.clear();
4567             for (Map.Entry<String, PasspointProvider> entry : providers.entrySet()) {
4568                 config = entry.getValue().getConfig();
4569                 if (config.getCredential().getUserCredential() != null) {
4570                     eapType = EAPConstants.EAP_TTLS;
4571                 } else if (config.getCredential().getCertCredential() != null) {
4572                     eapType = EAPConstants.EAP_TLS;
4573                 } else if (config.getCredential().getSimCredential() != null) {
4574                     eapType = config.getCredential().getSimCredential().getEapType();
4575                 } else {
4576                     eapType = -1;
4577                 }
4578                 switch (eapType) {
4579                     case EAPConstants.EAP_TLS:
4580                         passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_TLS;
4581                         break;
4582                     case EAPConstants.EAP_TTLS:
4583                         passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_TTLS;
4584                         break;
4585                     case EAPConstants.EAP_SIM:
4586                         passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_SIM;
4587                         break;
4588                     case EAPConstants.EAP_AKA:
4589                         passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_AKA;
4590                         break;
4591                     case EAPConstants.EAP_AKA_PRIME:
4592                         passpointType =
4593                                 WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_AKA_PRIME;
4594                         break;
4595                     default:
4596                         passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_UNKNOWN;
4597 
4598                 }
4599                 if (config.validateForR2()) {
4600                     mInstalledPasspointProfileTypeForR2.increment(passpointType);
4601                 } else {
4602                     mInstalledPasspointProfileTypeForR1.increment(passpointType);
4603                 }
4604             }
4605         }
4606     }
4607 
4608     /**
4609      * Increment initial partial scan count
4610      */
incrementInitialPartialScanCount()4611     public void incrementInitialPartialScanCount() {
4612         synchronized (mLock) {
4613             mInitPartialScanTotalCount++;
4614         }
4615     }
4616 
4617     /**
4618      * Report of initial partial scan
4619      * @param channelCount number of channels used in this scan
4620      * @param status true if scan resulted in a network connection attempt, false otherwise
4621      */
reportInitialPartialScan(int channelCount, boolean status)4622     public void reportInitialPartialScan(int channelCount, boolean status) {
4623         synchronized (mLock) {
4624             if (status) {
4625                 mInitPartialScanSuccessCount++;
4626                 mInitPartialScanSuccessHistogram.increment(channelCount);
4627             } else {
4628                 mInitPartialScanFailureCount++;
4629                 mInitPartialScanFailureHistogram.increment(channelCount);
4630             }
4631         }
4632     }
4633 
4634     /**
4635      * Put all metrics that were being tracked separately into mWifiLogProto
4636      */
consolidateProto()4637     private void consolidateProto() {
4638         List<WifiMetricsProto.RssiPollCount> rssis = new ArrayList<>();
4639         synchronized (mLock) {
4640             mWifiLogProto.connectionEvent = mConnectionEventList
4641                     .stream()
4642                     // Exclude active un-ended connection events
4643                     .filter(connectionEvent ->
4644                             !mCurrentConnectionEventPerIface.containsValue(connectionEvent))
4645                     // unwrap WifiMetrics.ConnectionEvent to get WifiMetricsProto.ConnectionEvent
4646                     .map(connectionEvent -> connectionEvent.mConnectionEvent)
4647                     .toArray(WifiMetricsProto.ConnectionEvent[]::new);
4648 
4649             //Convert the SparseIntArray of scanReturnEntry integers into ScanReturnEntry proto list
4650             mWifiLogProto.scanReturnEntries =
4651                     new WifiMetricsProto.WifiLog.ScanReturnEntry[mScanReturnEntries.size()];
4652             for (int i = 0; i < mScanReturnEntries.size(); i++) {
4653                 mWifiLogProto.scanReturnEntries[i] = new WifiMetricsProto.WifiLog.ScanReturnEntry();
4654                 mWifiLogProto.scanReturnEntries[i].scanReturnCode = mScanReturnEntries.keyAt(i);
4655                 mWifiLogProto.scanReturnEntries[i].scanResultsCount = mScanReturnEntries.valueAt(i);
4656             }
4657 
4658             // Convert the SparseIntArray of systemStateEntry into WifiSystemStateEntry proto list
4659             // This one is slightly more complex, as the Sparse are indexed with:
4660             //     key: wifiState * 2 + isScreenOn, value: wifiStateCount
4661             mWifiLogProto.wifiSystemStateEntries =
4662                     new WifiMetricsProto.WifiLog
4663                     .WifiSystemStateEntry[mWifiSystemStateEntries.size()];
4664             for (int i = 0; i < mWifiSystemStateEntries.size(); i++) {
4665                 mWifiLogProto.wifiSystemStateEntries[i] =
4666                         new WifiMetricsProto.WifiLog.WifiSystemStateEntry();
4667                 mWifiLogProto.wifiSystemStateEntries[i].wifiState =
4668                         mWifiSystemStateEntries.keyAt(i) / 2;
4669                 mWifiLogProto.wifiSystemStateEntries[i].wifiStateCount =
4670                         mWifiSystemStateEntries.valueAt(i);
4671                 mWifiLogProto.wifiSystemStateEntries[i].isScreenOn =
4672                         (mWifiSystemStateEntries.keyAt(i) % 2) > 0;
4673             }
4674             mWifiLogProto.recordDurationSec = (int) ((mClock.getElapsedSinceBootMillis() / 1000)
4675                     - mRecordStartTimeSec);
4676 
4677             /**
4678              * Convert the SparseIntArrays of RSSI poll rssi, counts, and frequency to the
4679              * proto's repeated IntKeyVal array.
4680              */
4681             for (Map.Entry<Integer, SparseIntArray> entry : mRssiPollCountsMap.entrySet()) {
4682                 int frequency = entry.getKey();
4683                 SparseIntArray histogram = entry.getValue();
4684                 for (int i = 0; i < histogram.size(); i++) {
4685                     WifiMetricsProto.RssiPollCount keyVal = new WifiMetricsProto.RssiPollCount();
4686                     keyVal.rssi = histogram.keyAt(i);
4687                     keyVal.count = histogram.valueAt(i);
4688                     keyVal.frequency = frequency;
4689                     rssis.add(keyVal);
4690                 }
4691             }
4692             mWifiLogProto.rssiPollRssiCount = rssis.toArray(mWifiLogProto.rssiPollRssiCount);
4693 
4694             /**
4695              * Convert the SparseIntArray of RSSI delta rssi's and counts to the proto's repeated
4696              * IntKeyVal array.
4697              */
4698             mWifiLogProto.rssiPollDeltaCount =
4699                     new WifiMetricsProto.RssiPollCount[mRssiDeltaCounts.size()];
4700             for (int i = 0; i < mRssiDeltaCounts.size(); i++) {
4701                 mWifiLogProto.rssiPollDeltaCount[i] = new WifiMetricsProto.RssiPollCount();
4702                 mWifiLogProto.rssiPollDeltaCount[i].rssi = mRssiDeltaCounts.keyAt(i);
4703                 mWifiLogProto.rssiPollDeltaCount[i].count = mRssiDeltaCounts.valueAt(i);
4704             }
4705 
4706             /**
4707              * Add LinkSpeedCount objects from mLinkSpeedCounts to proto.
4708              */
4709             mWifiLogProto.linkSpeedCounts =
4710                     new WifiMetricsProto.LinkSpeedCount[mLinkSpeedCounts.size()];
4711             for (int i = 0; i < mLinkSpeedCounts.size(); i++) {
4712                 mWifiLogProto.linkSpeedCounts[i] = mLinkSpeedCounts.valueAt(i);
4713             }
4714 
4715             /**
4716              * Convert the SparseIntArray of alert reasons and counts to the proto's repeated
4717              * IntKeyVal array.
4718              */
4719             mWifiLogProto.alertReasonCount =
4720                     new WifiMetricsProto.AlertReasonCount[mWifiAlertReasonCounts.size()];
4721             for (int i = 0; i < mWifiAlertReasonCounts.size(); i++) {
4722                 mWifiLogProto.alertReasonCount[i] = new WifiMetricsProto.AlertReasonCount();
4723                 mWifiLogProto.alertReasonCount[i].reason = mWifiAlertReasonCounts.keyAt(i);
4724                 mWifiLogProto.alertReasonCount[i].count = mWifiAlertReasonCounts.valueAt(i);
4725             }
4726 
4727             /**
4728             *  Convert the SparseIntArray of Wifi Score and counts to proto's repeated
4729             * IntKeyVal array.
4730             */
4731             mWifiLogProto.wifiScoreCount =
4732                     new WifiMetricsProto.WifiScoreCount[mWifiScoreCounts.size()];
4733             for (int score = 0; score < mWifiScoreCounts.size(); score++) {
4734                 mWifiLogProto.wifiScoreCount[score] = new WifiMetricsProto.WifiScoreCount();
4735                 mWifiLogProto.wifiScoreCount[score].score = mWifiScoreCounts.keyAt(score);
4736                 mWifiLogProto.wifiScoreCount[score].count = mWifiScoreCounts.valueAt(score);
4737             }
4738 
4739             /**
4740              * Convert the SparseIntArray of Wifi Usability Score and counts to proto's repeated
4741              * IntKeyVal array.
4742              */
4743             mWifiLogProto.wifiUsabilityScoreCount =
4744                 new WifiMetricsProto.WifiUsabilityScoreCount[mWifiUsabilityScoreCounts.size()];
4745             for (int scoreIdx = 0; scoreIdx < mWifiUsabilityScoreCounts.size(); scoreIdx++) {
4746                 mWifiLogProto.wifiUsabilityScoreCount[scoreIdx] =
4747                     new WifiMetricsProto.WifiUsabilityScoreCount();
4748                 mWifiLogProto.wifiUsabilityScoreCount[scoreIdx].score =
4749                     mWifiUsabilityScoreCounts.keyAt(scoreIdx);
4750                 mWifiLogProto.wifiUsabilityScoreCount[scoreIdx].count =
4751                     mWifiUsabilityScoreCounts.valueAt(scoreIdx);
4752             }
4753 
4754             /**
4755              * Convert the SparseIntArray of SoftAp Return codes and counts to proto's repeated
4756              * IntKeyVal array.
4757              */
4758             int codeCounts = mSoftApManagerReturnCodeCounts.size();
4759             mWifiLogProto.softApReturnCode = new WifiMetricsProto.SoftApReturnCodeCount[codeCounts];
4760             for (int sapCode = 0; sapCode < codeCounts; sapCode++) {
4761                 mWifiLogProto.softApReturnCode[sapCode] =
4762                         new WifiMetricsProto.SoftApReturnCodeCount();
4763                 mWifiLogProto.softApReturnCode[sapCode].startResult =
4764                         mSoftApManagerReturnCodeCounts.keyAt(sapCode);
4765                 mWifiLogProto.softApReturnCode[sapCode].count =
4766                         mSoftApManagerReturnCodeCounts.valueAt(sapCode);
4767             }
4768 
4769             /**
4770              * Convert StaEventList to array of StaEvents
4771              */
4772             mWifiLogProto.staEventList = new StaEvent[mStaEventList.size()];
4773             for (int i = 0; i < mStaEventList.size(); i++) {
4774                 mWifiLogProto.staEventList[i] = mStaEventList.get(i).staEvent;
4775             }
4776             mWifiLogProto.userActionEvents = new UserActionEvent[mUserActionEventList.size()];
4777             for (int i = 0; i < mUserActionEventList.size(); i++) {
4778                 mWifiLogProto.userActionEvents[i] = mUserActionEventList.get(i).toProto();
4779             }
4780             mWifiLogProto.totalSsidsInScanHistogram =
4781                     makeNumConnectableNetworksBucketArray(mTotalSsidsInScanHistogram);
4782             mWifiLogProto.totalBssidsInScanHistogram =
4783                     makeNumConnectableNetworksBucketArray(mTotalBssidsInScanHistogram);
4784             mWifiLogProto.availableOpenSsidsInScanHistogram =
4785                     makeNumConnectableNetworksBucketArray(mAvailableOpenSsidsInScanHistogram);
4786             mWifiLogProto.availableOpenBssidsInScanHistogram =
4787                     makeNumConnectableNetworksBucketArray(mAvailableOpenBssidsInScanHistogram);
4788             mWifiLogProto.availableSavedSsidsInScanHistogram =
4789                     makeNumConnectableNetworksBucketArray(mAvailableSavedSsidsInScanHistogram);
4790             mWifiLogProto.availableSavedBssidsInScanHistogram =
4791                     makeNumConnectableNetworksBucketArray(mAvailableSavedBssidsInScanHistogram);
4792             mWifiLogProto.availableOpenOrSavedSsidsInScanHistogram =
4793                     makeNumConnectableNetworksBucketArray(
4794                     mAvailableOpenOrSavedSsidsInScanHistogram);
4795             mWifiLogProto.availableOpenOrSavedBssidsInScanHistogram =
4796                     makeNumConnectableNetworksBucketArray(
4797                     mAvailableOpenOrSavedBssidsInScanHistogram);
4798             mWifiLogProto.availableSavedPasspointProviderProfilesInScanHistogram =
4799                     makeNumConnectableNetworksBucketArray(
4800                     mAvailableSavedPasspointProviderProfilesInScanHistogram);
4801             mWifiLogProto.availableSavedPasspointProviderBssidsInScanHistogram =
4802                     makeNumConnectableNetworksBucketArray(
4803                     mAvailableSavedPasspointProviderBssidsInScanHistogram);
4804             mWifiLogProto.wifiAwareLog = mWifiAwareMetrics.consolidateProto();
4805             mWifiLogProto.wifiRttLog = mRttMetrics.consolidateProto();
4806 
4807             mWifiLogProto.pnoScanMetrics = mPnoScanMetrics;
4808             mWifiLogProto.wifiLinkLayerUsageStats = mWifiLinkLayerUsageStats;
4809             mWifiLogProto.wifiLinkLayerUsageStats.radioStats =
4810                     new WifiMetricsProto.RadioStats[mRadioStats.size()];
4811             for (int i = 0; i < mRadioStats.size(); i++) {
4812                 mWifiLogProto.wifiLinkLayerUsageStats.radioStats[i] = mRadioStats.valueAt(i);
4813             }
4814 
4815             /**
4816              * Convert the SparseIntArray of "Connect to Network" notification types and counts to
4817              * proto's repeated IntKeyVal array.
4818              */
4819             ConnectToNetworkNotificationAndActionCount[] notificationCountArray =
4820                     new ConnectToNetworkNotificationAndActionCount[
4821                             mConnectToNetworkNotificationCount.size()];
4822             for (int i = 0; i < mConnectToNetworkNotificationCount.size(); i++) {
4823                 ConnectToNetworkNotificationAndActionCount keyVal =
4824                         new ConnectToNetworkNotificationAndActionCount();
4825                 keyVal.notification = mConnectToNetworkNotificationCount.keyAt(i);
4826                 keyVal.recommender =
4827                         ConnectToNetworkNotificationAndActionCount.RECOMMENDER_OPEN;
4828                 keyVal.count = mConnectToNetworkNotificationCount.valueAt(i);
4829                 notificationCountArray[i] = keyVal;
4830             }
4831             mWifiLogProto.connectToNetworkNotificationCount = notificationCountArray;
4832 
4833             /**
4834              * Convert the SparseIntArray of "Connect to Network" notification types and counts to
4835              * proto's repeated IntKeyVal array.
4836              */
4837             ConnectToNetworkNotificationAndActionCount[] notificationActionCountArray =
4838                     new ConnectToNetworkNotificationAndActionCount[
4839                             mConnectToNetworkNotificationActionCount.size()];
4840             for (int i = 0; i < mConnectToNetworkNotificationActionCount.size(); i++) {
4841                 ConnectToNetworkNotificationAndActionCount keyVal =
4842                         new ConnectToNetworkNotificationAndActionCount();
4843                 int k = mConnectToNetworkNotificationActionCount.keyAt(i);
4844                 keyVal.notification =  k / CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER;
4845                 keyVal.action = k % CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER;
4846                 keyVal.recommender =
4847                         ConnectToNetworkNotificationAndActionCount.RECOMMENDER_OPEN;
4848                 keyVal.count = mConnectToNetworkNotificationActionCount.valueAt(i);
4849                 notificationActionCountArray[i] = keyVal;
4850             }
4851 
4852             mWifiLogProto.installedPasspointProfileTypeForR1 =
4853                     convertPasspointProfilesToProto(mInstalledPasspointProfileTypeForR1);
4854             mWifiLogProto.installedPasspointProfileTypeForR2 =
4855                     convertPasspointProfilesToProto(mInstalledPasspointProfileTypeForR2);
4856 
4857             mWifiLogProto.connectToNetworkNotificationActionCount = notificationActionCountArray;
4858 
4859             mWifiLogProto.openNetworkRecommenderBlocklistSize =
4860                     mOpenNetworkRecommenderBlocklistSize;
4861             mWifiLogProto.isWifiNetworksAvailableNotificationOn =
4862                     mIsWifiNetworksAvailableNotificationOn;
4863             mWifiLogProto.numOpenNetworkRecommendationUpdates =
4864                     mNumOpenNetworkRecommendationUpdates;
4865             mWifiLogProto.numOpenNetworkConnectMessageFailedToSend =
4866                     mNumOpenNetworkConnectMessageFailedToSend;
4867 
4868             mWifiLogProto.observedHotspotR1ApsInScanHistogram =
4869                     makeNumConnectableNetworksBucketArray(mObservedHotspotR1ApInScanHistogram);
4870             mWifiLogProto.observedHotspotR2ApsInScanHistogram =
4871                     makeNumConnectableNetworksBucketArray(mObservedHotspotR2ApInScanHistogram);
4872             mWifiLogProto.observedHotspotR3ApsInScanHistogram =
4873                 makeNumConnectableNetworksBucketArray(mObservedHotspotR3ApInScanHistogram);
4874             mWifiLogProto.observedHotspotR1EssInScanHistogram =
4875                     makeNumConnectableNetworksBucketArray(mObservedHotspotR1EssInScanHistogram);
4876             mWifiLogProto.observedHotspotR2EssInScanHistogram =
4877                     makeNumConnectableNetworksBucketArray(mObservedHotspotR2EssInScanHistogram);
4878             mWifiLogProto.observedHotspotR3EssInScanHistogram =
4879                     makeNumConnectableNetworksBucketArray(mObservedHotspotR3EssInScanHistogram);
4880             mWifiLogProto.observedHotspotR1ApsPerEssInScanHistogram =
4881                     makeNumConnectableNetworksBucketArray(
4882                             mObservedHotspotR1ApsPerEssInScanHistogram);
4883             mWifiLogProto.observedHotspotR2ApsPerEssInScanHistogram =
4884                     makeNumConnectableNetworksBucketArray(
4885                             mObservedHotspotR2ApsPerEssInScanHistogram);
4886             mWifiLogProto.observedHotspotR3ApsPerEssInScanHistogram =
4887                 makeNumConnectableNetworksBucketArray(
4888                     mObservedHotspotR3ApsPerEssInScanHistogram);
4889 
4890             mWifiLogProto.observed80211McSupportingApsInScanHistogram =
4891                     makeNumConnectableNetworksBucketArray(mObserved80211mcApInScanHistogram);
4892 
4893             if (mSoftApEventListTethered.size() > 0) {
4894                 mWifiLogProto.softApConnectedClientsEventsTethered =
4895                         mSoftApEventListTethered.toArray(
4896                         mWifiLogProto.softApConnectedClientsEventsTethered);
4897             }
4898             if (mSoftApEventListLocalOnly.size() > 0) {
4899                 mWifiLogProto.softApConnectedClientsEventsLocalOnly =
4900                         mSoftApEventListLocalOnly.toArray(
4901                         mWifiLogProto.softApConnectedClientsEventsLocalOnly);
4902             }
4903 
4904             mWifiLogProto.wifiPowerStats = mWifiPowerMetrics.buildProto();
4905             mWifiLogProto.wifiRadioUsage = mWifiPowerMetrics.buildWifiRadioUsageProto();
4906             mWifiLogProto.wifiWakeStats = mWifiWakeMetrics.buildProto();
4907             mWifiLogProto.isMacRandomizationOn = mContext.getResources().getBoolean(
4908                     R.bool.config_wifi_connected_mac_randomization_supported);
4909             mExperimentValues.wifiIsUnusableLoggingEnabled = mContext.getResources().getBoolean(
4910                     R.bool.config_wifiIsUnusableEventMetricsEnabled);
4911             mExperimentValues.linkSpeedCountsLoggingEnabled = mContext.getResources().getBoolean(
4912                     R.bool.config_wifiLinkSpeedMetricsEnabled);
4913             mExperimentValues.wifiDataStallMinTxBad = mContext.getResources().getInteger(
4914                     R.integer.config_wifiDataStallMinTxBad);
4915             mExperimentValues.wifiDataStallMinTxSuccessWithoutRx =
4916                     mContext.getResources().getInteger(
4917                             R.integer.config_wifiDataStallMinTxSuccessWithoutRx);
4918             mWifiLogProto.experimentValues = mExperimentValues;
4919             mWifiLogProto.wifiIsUnusableEventList =
4920                     new WifiIsUnusableEvent[mWifiIsUnusableList.size()];
4921             for (int i = 0; i < mWifiIsUnusableList.size(); i++) {
4922                 mWifiLogProto.wifiIsUnusableEventList[i] = mWifiIsUnusableList.get(i).event;
4923             }
4924             mWifiLogProto.hardwareRevision = SystemProperties.get("ro.boot.revision", "");
4925 
4926             // Postprocessing on WifiUsabilityStats to upload an equal number of LABEL_GOOD and
4927             // LABEL_BAD WifiUsabilityStats
4928             final int numUsabilityStats = Math.min(
4929                     Math.min(mWifiUsabilityStatsListBad.size(),
4930                             mWifiUsabilityStatsListGood.size()),
4931                     MAX_WIFI_USABILITY_STATS_PER_TYPE_TO_UPLOAD);
4932             LinkedList<WifiUsabilityStats> usabilityStatsGoodCopy =
4933                     new LinkedList<>(mWifiUsabilityStatsListGood);
4934             LinkedList<WifiUsabilityStats> usabilityStatsBadCopy =
4935                     new LinkedList<>(mWifiUsabilityStatsListBad);
4936             mWifiLogProto.wifiUsabilityStatsList = new WifiUsabilityStats[numUsabilityStats * 2];
4937             for (int i = 0; i < numUsabilityStats; i++) {
4938                 mWifiLogProto.wifiUsabilityStatsList[2 * i] = usabilityStatsGoodCopy.remove(
4939                         mRand.nextInt(usabilityStatsGoodCopy.size()));
4940                 mWifiLogProto.wifiUsabilityStatsList[2 * i + 1] = usabilityStatsBadCopy.remove(
4941                         mRand.nextInt(usabilityStatsBadCopy.size()));
4942             }
4943             mWifiLogProto.mobilityStatePnoStatsList =
4944                     new DeviceMobilityStatePnoScanStats[mMobilityStatePnoStatsMap.size()];
4945             for (int i = 0; i < mMobilityStatePnoStatsMap.size(); i++) {
4946                 mWifiLogProto.mobilityStatePnoStatsList[i] = mMobilityStatePnoStatsMap.valueAt(i);
4947             }
4948             mWifiLogProto.wifiP2PStats = mWifiP2pMetrics.consolidateProto();
4949             mWifiLogProto.wifiDppLog = mDppMetrics.consolidateProto();
4950             mWifiLogProto.wifiConfigStoreIo = new WifiMetricsProto.WifiConfigStoreIO();
4951             mWifiLogProto.wifiConfigStoreIo.readDurations =
4952                     makeWifiConfigStoreIODurationBucketArray(mWifiConfigStoreReadDurationHistogram);
4953             mWifiLogProto.wifiConfigStoreIo.writeDurations =
4954                     makeWifiConfigStoreIODurationBucketArray(
4955                             mWifiConfigStoreWriteDurationHistogram);
4956 
4957             LinkProbeStats linkProbeStats = new LinkProbeStats();
4958             linkProbeStats.successRssiCounts = mLinkProbeSuccessRssiCounts.toProto();
4959             linkProbeStats.failureRssiCounts = mLinkProbeFailureRssiCounts.toProto();
4960             linkProbeStats.successLinkSpeedCounts = mLinkProbeSuccessLinkSpeedCounts.toProto();
4961             linkProbeStats.failureLinkSpeedCounts = mLinkProbeFailureLinkSpeedCounts.toProto();
4962             linkProbeStats.successSecondsSinceLastTxSuccessHistogram =
4963                     mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram.toProto();
4964             linkProbeStats.failureSecondsSinceLastTxSuccessHistogram =
4965                     mLinkProbeFailureSecondsSinceLastTxSuccessHistogram.toProto();
4966             linkProbeStats.successElapsedTimeMsHistogram =
4967                     mLinkProbeSuccessElapsedTimeMsHistogram.toProto();
4968             linkProbeStats.failureReasonCounts = mLinkProbeFailureReasonCounts.toProto(
4969                     LinkProbeFailureReasonCount.class,
4970                     (reason, count) -> {
4971                         LinkProbeFailureReasonCount c = new LinkProbeFailureReasonCount();
4972                         c.failureReason = linkProbeFailureReasonToProto(reason);
4973                         c.count = count;
4974                         return c;
4975                     });
4976             linkProbeStats.experimentProbeCounts = mLinkProbeExperimentProbeCounts.toProto(
4977                     ExperimentProbeCounts.class,
4978                     (experimentId, probeCount) -> {
4979                         ExperimentProbeCounts c = new ExperimentProbeCounts();
4980                         c.experimentId = experimentId;
4981                         c.probeCount = probeCount;
4982                         return c;
4983                     });
4984             mWifiLogProto.linkProbeStats = linkProbeStats;
4985 
4986             mWifiLogProto.networkSelectionExperimentDecisionsList =
4987                     makeNetworkSelectionExperimentDecisionsList();
4988 
4989             mWifiNetworkRequestApiLog.networkMatchSizeHistogram =
4990                     mWifiNetworkRequestApiMatchSizeHistogram.toProto();
4991             mWifiNetworkRequestApiLog.connectionDurationSecOnPrimaryIfaceHistogram =
4992                     mWifiNetworkRequestApiConnectionDurationSecOnPrimaryIfaceHistogram.toProto();
4993             mWifiNetworkRequestApiLog.connectionDurationSecOnSecondaryIfaceHistogram =
4994                     mWifiNetworkRequestApiConnectionDurationSecOnSecondaryIfaceHistogram.toProto();
4995             mWifiNetworkRequestApiLog.concurrentConnectionDurationSecHistogram =
4996                     mWifiNetworkRequestApiConcurrentConnectionDurationSecHistogram.toProto();
4997             mWifiLogProto.wifiNetworkRequestApiLog = mWifiNetworkRequestApiLog;
4998 
4999             mWifiNetworkSuggestionApiLog.networkListSizeHistogram =
5000                     mWifiNetworkSuggestionApiListSizeHistogram.toProto();
5001             mWifiNetworkSuggestionApiLog.appCountPerType =
5002                     mWifiNetworkSuggestionApiAppTypeCounter.toProto(SuggestionAppCount.class,
5003                             (key, count) -> {
5004                                 SuggestionAppCount entry = new SuggestionAppCount();
5005                                 entry.appType = key;
5006                                 entry.count = count;
5007                                 return entry;
5008                             });
5009             mWifiNetworkSuggestionApiLog.numPriorityGroups =
5010                     mWifiNetworkSuggestionPriorityGroups.size();
5011             mWifiNetworkSuggestionApiLog.numSavedNetworksWithConfiguredSuggestion =
5012                     mWifiNetworkSuggestionCoexistSavedNetworks.size();
5013             mWifiLogProto.wifiNetworkSuggestionApiLog = mWifiNetworkSuggestionApiLog;
5014 
5015             UserReactionToApprovalUiEvent events = new UserReactionToApprovalUiEvent();
5016             events.userApprovalAppUiReaction = mUserApprovalSuggestionAppUiReactionList
5017                     .toArray(new UserReaction[0]);
5018             events.userApprovalCarrierUiReaction = mUserApprovalCarrierUiReactionList
5019                     .toArray(new UserReaction[0]);
5020             mWifiLogProto.userReactionToApprovalUiEvent = events;
5021 
5022             mWifiLockStats.highPerfLockAcqDurationSecHistogram =
5023                     mWifiLockHighPerfAcqDurationSecHistogram.toProto();
5024 
5025             mWifiLockStats.lowLatencyLockAcqDurationSecHistogram =
5026                     mWifiLockLowLatencyAcqDurationSecHistogram.toProto();
5027 
5028             mWifiLockStats.highPerfActiveSessionDurationSecHistogram =
5029                     mWifiLockHighPerfActiveSessionDurationSecHistogram.toProto();
5030 
5031             mWifiLockStats.lowLatencyActiveSessionDurationSecHistogram =
5032                     mWifiLockLowLatencyActiveSessionDurationSecHistogram.toProto();
5033 
5034             mWifiLogProto.wifiLockStats = mWifiLockStats;
5035             mWifiLogProto.wifiToggleStats = mWifiToggleStats;
5036 
5037             /**
5038              * Convert the SparseIntArray of passpoint provision failure code
5039              * and counts to the proto's repeated IntKeyVal array.
5040              */
5041             mWifiLogProto.passpointProvisionStats = new PasspointProvisionStats();
5042             mWifiLogProto.passpointProvisionStats.numProvisionSuccess = mNumProvisionSuccess;
5043             mWifiLogProto.passpointProvisionStats.provisionFailureCount =
5044                     mPasspointProvisionFailureCounts.toProto(ProvisionFailureCount.class,
5045                             (key, count) -> {
5046                                 ProvisionFailureCount entry = new ProvisionFailureCount();
5047                                 entry.failureCode = key;
5048                                 entry.count = count;
5049                                 return entry;
5050                             });
5051             // 'G' is due to that 1st Letter after _ becomes capital during protobuff compilation
5052             mWifiLogProto.txLinkSpeedCount2G = mTxLinkSpeedCount2g.toProto();
5053             mWifiLogProto.txLinkSpeedCount5GLow = mTxLinkSpeedCount5gLow.toProto();
5054             mWifiLogProto.txLinkSpeedCount5GMid = mTxLinkSpeedCount5gMid.toProto();
5055             mWifiLogProto.txLinkSpeedCount5GHigh = mTxLinkSpeedCount5gHigh.toProto();
5056             mWifiLogProto.txLinkSpeedCount6GLow = mTxLinkSpeedCount6gLow.toProto();
5057             mWifiLogProto.txLinkSpeedCount6GMid = mTxLinkSpeedCount6gMid.toProto();
5058             mWifiLogProto.txLinkSpeedCount6GHigh = mTxLinkSpeedCount6gHigh.toProto();
5059 
5060             mWifiLogProto.rxLinkSpeedCount2G = mRxLinkSpeedCount2g.toProto();
5061             mWifiLogProto.rxLinkSpeedCount5GLow = mRxLinkSpeedCount5gLow.toProto();
5062             mWifiLogProto.rxLinkSpeedCount5GMid = mRxLinkSpeedCount5gMid.toProto();
5063             mWifiLogProto.rxLinkSpeedCount5GHigh = mRxLinkSpeedCount5gHigh.toProto();
5064             mWifiLogProto.rxLinkSpeedCount6GLow = mRxLinkSpeedCount6gLow.toProto();
5065             mWifiLogProto.rxLinkSpeedCount6GMid = mRxLinkSpeedCount6gMid.toProto();
5066             mWifiLogProto.rxLinkSpeedCount6GHigh = mRxLinkSpeedCount6gHigh.toProto();
5067 
5068             HealthMonitorMetrics healthMonitorMetrics = mWifiHealthMonitor.buildProto();
5069             if (healthMonitorMetrics != null) {
5070                 mWifiLogProto.healthMonitorMetrics = healthMonitorMetrics;
5071             }
5072             mWifiLogProto.bssidBlocklistStats = mBssidBlocklistStats.toProto();
5073             mWifiLogProto.connectionDurationStats = mConnectionDurationStats.toProto();
5074             mWifiLogProto.wifiOffMetrics = mWifiOffMetrics.toProto();
5075             mWifiLogProto.softApConfigLimitationMetrics = mSoftApConfigLimitationMetrics.toProto();
5076             mWifiLogProto.channelUtilizationHistogram =
5077                     new WifiMetricsProto.ChannelUtilizationHistogram();
5078             mWifiLogProto.channelUtilizationHistogram.utilization2G =
5079                     mChannelUtilizationHistogram2G.toProto();
5080             mWifiLogProto.channelUtilizationHistogram.utilizationAbove2G =
5081                     mChannelUtilizationHistogramAbove2G.toProto();
5082             mWifiLogProto.throughputMbpsHistogram =
5083                     new WifiMetricsProto.ThroughputMbpsHistogram();
5084             mWifiLogProto.throughputMbpsHistogram.tx2G =
5085                     mTxThroughputMbpsHistogram2G.toProto();
5086             mWifiLogProto.throughputMbpsHistogram.txAbove2G =
5087                     mTxThroughputMbpsHistogramAbove2G.toProto();
5088             mWifiLogProto.throughputMbpsHistogram.rx2G =
5089                     mRxThroughputMbpsHistogram2G.toProto();
5090             mWifiLogProto.throughputMbpsHistogram.rxAbove2G =
5091                     mRxThroughputMbpsHistogramAbove2G.toProto();
5092             mWifiLogProto.meteredNetworkStatsSaved = mMeteredNetworkStatsBuilder.toProto(false);
5093             mWifiLogProto.meteredNetworkStatsSuggestion = mMeteredNetworkStatsBuilder.toProto(true);
5094 
5095             InitPartialScanStats initialPartialScanStats = new InitPartialScanStats();
5096             initialPartialScanStats.numScans = mInitPartialScanTotalCount;
5097             initialPartialScanStats.numSuccessScans = mInitPartialScanSuccessCount;
5098             initialPartialScanStats.numFailureScans = mInitPartialScanFailureCount;
5099             initialPartialScanStats.successfulScanChannelCountHistogram =
5100                     mInitPartialScanSuccessHistogram.toProto();
5101             initialPartialScanStats.failedScanChannelCountHistogram =
5102                     mInitPartialScanFailureHistogram.toProto();
5103             mWifiLogProto.initPartialScanStats = initialPartialScanStats;
5104             mWifiLogProto.carrierWifiMetrics = mCarrierWifiMetrics.toProto();
5105             mWifiLogProto.mainlineModuleVersion = mWifiHealthMonitor.getWifiStackVersion();
5106             mWifiLogProto.firstConnectAfterBootStats = mFirstConnectAfterBootStats;
5107             mWifiLogProto.wifiToWifiSwitchStats = buildWifiToWifiSwitchStats();
5108             mWifiLogProto.bandwidthEstimatorStats = mWifiScoreCard.dumpBandwidthEstimatorStats();
5109             mWifiLogProto.passpointDeauthImminentScope = mPasspointDeauthImminentScope.toProto();
5110             mWifiLogProto.recentFailureAssociationStatus =
5111                     mRecentFailureAssociationStatus.toProto();
5112             mWifiLogProto.countryCodeScanHistogram = mCountryCodeScanHistogram.toProto();
5113         }
5114     }
5115 
buildWifiToWifiSwitchStats()5116     private WifiToWifiSwitchStats buildWifiToWifiSwitchStats() {
5117         mWifiToWifiSwitchStats.makeBeforeBreakLingerDurationSeconds =
5118                 mMakeBeforeBreakLingeringDurationSeconds.toProto();
5119         return mWifiToWifiSwitchStats;
5120     }
5121 
linkProbeFailureReasonToProto(int reason)5122     private static int linkProbeFailureReasonToProto(int reason) {
5123         switch (reason) {
5124             case WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED:
5125                 return LinkProbeStats.LINK_PROBE_FAILURE_REASON_MCS_UNSUPPORTED;
5126             case WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_NO_ACK:
5127                 return LinkProbeStats.LINK_PROBE_FAILURE_REASON_NO_ACK;
5128             case WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_TIMEOUT:
5129                 return LinkProbeStats.LINK_PROBE_FAILURE_REASON_TIMEOUT;
5130             case WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_ALREADY_STARTED:
5131                 return LinkProbeStats.LINK_PROBE_FAILURE_REASON_ALREADY_STARTED;
5132             default:
5133                 return LinkProbeStats.LINK_PROBE_FAILURE_REASON_UNKNOWN;
5134         }
5135     }
5136 
makeNetworkSelectionExperimentDecisionsList()5137     private NetworkSelectionExperimentDecisions[] makeNetworkSelectionExperimentDecisionsList() {
5138         NetworkSelectionExperimentDecisions[] results = new NetworkSelectionExperimentDecisions[
5139                 mNetworkSelectionExperimentPairNumChoicesCounts.size()];
5140         int i = 0;
5141         for (Map.Entry<Pair<Integer, Integer>, NetworkSelectionExperimentResults> entry :
5142                 mNetworkSelectionExperimentPairNumChoicesCounts.entrySet()) {
5143             NetworkSelectionExperimentDecisions result = new NetworkSelectionExperimentDecisions();
5144             result.experiment1Id = entry.getKey().first;
5145             result.experiment2Id = entry.getKey().second;
5146             result.sameSelectionNumChoicesCounter =
5147                     entry.getValue().sameSelectionNumChoicesCounter.toProto();
5148             result.differentSelectionNumChoicesCounter =
5149                     entry.getValue().differentSelectionNumChoicesCounter.toProto();
5150             results[i] = result;
5151             i++;
5152         }
5153         return results;
5154     }
5155 
5156     /** Sets the scoring experiment id to current value */
consolidateScoringParams()5157     private void consolidateScoringParams() {
5158         synchronized (mLock) {
5159             if (mScoringParams != null) {
5160                 int experimentIdentifier = mScoringParams.getExperimentIdentifier();
5161                 if (experimentIdentifier == 0) {
5162                     mWifiLogProto.scoreExperimentId = "";
5163                 } else {
5164                     mWifiLogProto.scoreExperimentId = "x" + experimentIdentifier;
5165                 }
5166             }
5167         }
5168     }
5169 
makeNumConnectableNetworksBucketArray( SparseIntArray sia)5170     private WifiMetricsProto.NumConnectableNetworksBucket[] makeNumConnectableNetworksBucketArray(
5171             SparseIntArray sia) {
5172         WifiMetricsProto.NumConnectableNetworksBucket[] array =
5173                 new WifiMetricsProto.NumConnectableNetworksBucket[sia.size()];
5174         for (int i = 0; i < sia.size(); i++) {
5175             WifiMetricsProto.NumConnectableNetworksBucket keyVal =
5176                     new WifiMetricsProto.NumConnectableNetworksBucket();
5177             keyVal.numConnectableNetworks = sia.keyAt(i);
5178             keyVal.count = sia.valueAt(i);
5179             array[i] = keyVal;
5180         }
5181         return array;
5182     }
5183 
5184     private WifiMetricsProto.WifiConfigStoreIO.DurationBucket[]
makeWifiConfigStoreIODurationBucketArray(SparseIntArray sia)5185             makeWifiConfigStoreIODurationBucketArray(SparseIntArray sia) {
5186         MetricsUtils.GenericBucket[] genericBuckets =
5187                 MetricsUtils.linearHistogramToGenericBuckets(sia,
5188                         WIFI_CONFIG_STORE_IO_DURATION_BUCKET_RANGES_MS);
5189         WifiMetricsProto.WifiConfigStoreIO.DurationBucket[] array =
5190                 new WifiMetricsProto.WifiConfigStoreIO.DurationBucket[genericBuckets.length];
5191         try {
5192             for (int i = 0; i < genericBuckets.length; i++) {
5193                 array[i] = new WifiMetricsProto.WifiConfigStoreIO.DurationBucket();
5194                 array[i].rangeStartMs = toIntExact(genericBuckets[i].start);
5195                 array[i].rangeEndMs = toIntExact(genericBuckets[i].end);
5196                 array[i].count = genericBuckets[i].count;
5197             }
5198         } catch (ArithmeticException e) {
5199             // Return empty array on any overflow errors.
5200             array = new WifiMetricsProto.WifiConfigStoreIO.DurationBucket[0];
5201         }
5202         return array;
5203     }
5204 
5205     /**
5206      * Clear all WifiMetrics, except for currentConnectionEvent and Open Network Notification
5207      * feature enabled state, blocklist size.
5208      */
clear()5209     private void clear() {
5210         synchronized (mLock) {
5211             mConnectionEventList.clear();
5212             // Add in-progress events back
5213             mConnectionEventList.addAll(mCurrentConnectionEventPerIface.values());
5214 
5215             mScanReturnEntries.clear();
5216             mWifiSystemStateEntries.clear();
5217             mRecordStartTimeSec = mClock.getElapsedSinceBootMillis() / 1000;
5218             mRssiPollCountsMap.clear();
5219             mRssiDeltaCounts.clear();
5220             mLinkSpeedCounts.clear();
5221             mTxLinkSpeedCount2g.clear();
5222             mTxLinkSpeedCount5gLow.clear();
5223             mTxLinkSpeedCount5gMid.clear();
5224             mTxLinkSpeedCount5gHigh.clear();
5225             mTxLinkSpeedCount6gLow.clear();
5226             mTxLinkSpeedCount6gMid.clear();
5227             mTxLinkSpeedCount6gHigh.clear();
5228             mRxLinkSpeedCount2g.clear();
5229             mRxLinkSpeedCount5gLow.clear();
5230             mRxLinkSpeedCount5gMid.clear();
5231             mRxLinkSpeedCount5gHigh.clear();
5232             mRxLinkSpeedCount6gLow.clear();
5233             mRxLinkSpeedCount6gMid.clear();
5234             mRxLinkSpeedCount6gHigh.clear();
5235             mWifiAlertReasonCounts.clear();
5236             mMakeBeforeBreakLingeringDurationSeconds.clear();
5237             mWifiScoreCounts.clear();
5238             mWifiUsabilityScoreCounts.clear();
5239             mWifiLogProto.clear();
5240             mScanResultRssiTimestampMillis = -1;
5241             mSoftApManagerReturnCodeCounts.clear();
5242             mStaEventList.clear();
5243             mUserActionEventList.clear();
5244             mWifiAwareMetrics.clear();
5245             mRttMetrics.clear();
5246             mTotalSsidsInScanHistogram.clear();
5247             mTotalBssidsInScanHistogram.clear();
5248             mAvailableOpenSsidsInScanHistogram.clear();
5249             mAvailableOpenBssidsInScanHistogram.clear();
5250             mAvailableSavedSsidsInScanHistogram.clear();
5251             mAvailableSavedBssidsInScanHistogram.clear();
5252             mAvailableOpenOrSavedSsidsInScanHistogram.clear();
5253             mAvailableOpenOrSavedBssidsInScanHistogram.clear();
5254             mAvailableSavedPasspointProviderProfilesInScanHistogram.clear();
5255             mAvailableSavedPasspointProviderBssidsInScanHistogram.clear();
5256             mPnoScanMetrics.clear();
5257             mWifiLinkLayerUsageStats.clear();
5258             mRadioStats.clear();
5259             mConnectToNetworkNotificationCount.clear();
5260             mConnectToNetworkNotificationActionCount.clear();
5261             mNumOpenNetworkRecommendationUpdates = 0;
5262             mNumOpenNetworkConnectMessageFailedToSend = 0;
5263             mObservedHotspotR1ApInScanHistogram.clear();
5264             mObservedHotspotR2ApInScanHistogram.clear();
5265             mObservedHotspotR3ApInScanHistogram.clear();
5266             mObservedHotspotR1EssInScanHistogram.clear();
5267             mObservedHotspotR2EssInScanHistogram.clear();
5268             mObservedHotspotR3EssInScanHistogram.clear();
5269             mObservedHotspotR1ApsPerEssInScanHistogram.clear();
5270             mObservedHotspotR2ApsPerEssInScanHistogram.clear();
5271             mObservedHotspotR3ApsPerEssInScanHistogram.clear();
5272             mCountryCodeScanHistogram.clear();
5273             mSoftApEventListTethered.clear();
5274             mSoftApEventListLocalOnly.clear();
5275             mWifiWakeMetrics.clear();
5276             mObserved80211mcApInScanHistogram.clear();
5277             mWifiIsUnusableList.clear();
5278             mInstalledPasspointProfileTypeForR1.clear();
5279             mInstalledPasspointProfileTypeForR2.clear();
5280             mWifiUsabilityStatsListGood.clear();
5281             mWifiUsabilityStatsListBad.clear();
5282             mWifiUsabilityStatsEntriesList.clear();
5283             mMobilityStatePnoStatsMap.clear();
5284             mWifiP2pMetrics.clear();
5285             mDppMetrics.clear();
5286             mWifiUsabilityStatsCounter = 0;
5287             mLastBssid = null;
5288             mLastFrequency = -1;
5289             mSeqNumInsideFramework = 0;
5290             mLastWifiUsabilityScore = -1;
5291             mLastWifiUsabilityScoreNoReset = -1;
5292             mLastPredictionHorizonSec = -1;
5293             mLastPredictionHorizonSecNoReset = -1;
5294             mSeqNumToFramework = -1;
5295             mProbeStatusSinceLastUpdate =
5296                     android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE;
5297             mProbeElapsedTimeSinceLastUpdateMs = -1;
5298             mProbeMcsRateSinceLastUpdate = -1;
5299             mScoreBreachLowTimeMillis = -1;
5300             mMeteredNetworkStatsBuilder.clear();
5301             mWifiConfigStoreReadDurationHistogram.clear();
5302             mWifiConfigStoreWriteDurationHistogram.clear();
5303             mLinkProbeSuccessRssiCounts.clear();
5304             mLinkProbeFailureRssiCounts.clear();
5305             mLinkProbeSuccessLinkSpeedCounts.clear();
5306             mLinkProbeFailureLinkSpeedCounts.clear();
5307             mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram.clear();
5308             mLinkProbeFailureSecondsSinceLastTxSuccessHistogram.clear();
5309             mLinkProbeSuccessElapsedTimeMsHistogram.clear();
5310             mLinkProbeFailureReasonCounts.clear();
5311             mLinkProbeExperimentProbeCounts.clear();
5312             mLinkProbeStaEventCount = 0;
5313             mNetworkSelectionExperimentPairNumChoicesCounts.clear();
5314             mWifiNetworkSuggestionApiLog.clear();
5315             mWifiNetworkRequestApiMatchSizeHistogram.clear();
5316             mWifiNetworkRequestApiConnectionDurationSecOnPrimaryIfaceHistogram.clear();
5317             mWifiNetworkRequestApiConnectionDurationSecOnSecondaryIfaceHistogram.clear();
5318             mWifiNetworkRequestApiConcurrentConnectionDurationSecHistogram.clear();
5319             mWifiNetworkSuggestionApiListSizeHistogram.clear();
5320             mWifiNetworkSuggestionApiAppTypeCounter.clear();
5321             mUserApprovalSuggestionAppUiReactionList.clear();
5322             mUserApprovalCarrierUiReactionList.clear();
5323             mWifiLockHighPerfAcqDurationSecHistogram.clear();
5324             mWifiLockLowLatencyAcqDurationSecHistogram.clear();
5325             mWifiLockHighPerfActiveSessionDurationSecHistogram.clear();
5326             mWifiLockLowLatencyActiveSessionDurationSecHistogram.clear();
5327             mWifiLockStats.clear();
5328             mWifiToggleStats.clear();
5329             mChannelUtilizationHistogram2G.clear();
5330             mChannelUtilizationHistogramAbove2G.clear();
5331             mTxThroughputMbpsHistogram2G.clear();
5332             mRxThroughputMbpsHistogram2G.clear();
5333             mTxThroughputMbpsHistogramAbove2G.clear();
5334             mRxThroughputMbpsHistogramAbove2G.clear();
5335             mPasspointProvisionFailureCounts.clear();
5336             mNumProvisionSuccess = 0;
5337             mBssidBlocklistStats = new BssidBlocklistStats();
5338             mConnectionDurationStats.clear();
5339             mWifiLogProto.isExternalWifiScorerOn = false;
5340             mWifiOffMetrics.clear();
5341             mSoftApConfigLimitationMetrics.clear();
5342             //Initial partial scan metrics
5343             mInitPartialScanTotalCount = 0;
5344             mInitPartialScanSuccessCount = 0;
5345             mInitPartialScanFailureCount = 0;
5346             mInitPartialScanSuccessHistogram.clear();
5347             mInitPartialScanFailureHistogram.clear();
5348             mCarrierWifiMetrics.clear();
5349             mFirstConnectAfterBootStats = null;
5350             mWifiToWifiSwitchStats.clear();
5351             mPasspointDeauthImminentScope.clear();
5352             mRecentFailureAssociationStatus.clear();
5353             mWifiNetworkSuggestionPriorityGroups.clear();
5354             mWifiNetworkSuggestionCoexistSavedNetworks.clear();
5355         }
5356     }
5357 
5358     /**
5359      *  Set screen state (On/Off)
5360      */
setScreenState(boolean screenOn)5361     private void setScreenState(boolean screenOn) {
5362         synchronized (mLock) {
5363             mScreenOn = screenOn;
5364         }
5365     }
5366 
isPrimary(String ifaceName)5367     private boolean isPrimary(String ifaceName) {
5368         return mIfaceToRoleMap.get(ifaceName) == ActiveModeManager.ROLE_CLIENT_PRIMARY;
5369     }
5370 
5371     /**
5372      *  Set wifi state (WIFI_UNKNOWN, WIFI_DISABLED, WIFI_DISCONNECTED, WIFI_ASSOCIATED)
5373      */
setWifiState(String ifaceName, int wifiState)5374     public void setWifiState(String ifaceName, int wifiState) {
5375         synchronized (mLock) {
5376             mWifiState = wifiState;
5377             // set wifi priority over setting when any STA gets connected.
5378             if (wifiState == WifiMetricsProto.WifiLog.WIFI_ASSOCIATED) {
5379                 mWifiWins = true;
5380                 mWifiWinsUsabilityScore = true;
5381             }
5382             if (isPrimary(ifaceName) && (wifiState == WifiMetricsProto.WifiLog.WIFI_DISCONNECTED
5383                     || wifiState == WifiMetricsProto.WifiLog.WIFI_DISABLED)) {
5384                 mWifiStatusBuilder = new WifiStatusBuilder();
5385             }
5386         }
5387     }
5388 
5389     /**
5390      * Message handler for interesting WifiMonitor messages. Generates StaEvents
5391      */
processMessage(Message msg)5392     private void processMessage(Message msg) {
5393         String ifaceName = msg.getData().getString(WifiMonitor.KEY_IFACE);
5394 
5395         StaEvent event = new StaEvent();
5396         boolean logEvent = true;
5397         switch (msg.what) {
5398             case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
5399                 event.type = StaEvent.TYPE_ASSOCIATION_REJECTION_EVENT;
5400                 AssocRejectEventInfo assocRejectEventInfo = (AssocRejectEventInfo) msg.obj;
5401                 event.associationTimedOut = assocRejectEventInfo.timedOut;
5402                 event.status = assocRejectEventInfo.statusCode;
5403                 break;
5404             case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
5405                 event.type = StaEvent.TYPE_AUTHENTICATION_FAILURE_EVENT;
5406                 AuthenticationFailureEventInfo authenticationFailureEventInfo =
5407                         (AuthenticationFailureEventInfo) msg.obj;
5408                 switch (authenticationFailureEventInfo.reasonCode) {
5409                     case WifiManager.ERROR_AUTH_FAILURE_NONE:
5410                         event.authFailureReason = StaEvent.AUTH_FAILURE_NONE;
5411                         break;
5412                     case WifiManager.ERROR_AUTH_FAILURE_TIMEOUT:
5413                         event.authFailureReason = StaEvent.AUTH_FAILURE_TIMEOUT;
5414                         break;
5415                     case WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD:
5416                         event.authFailureReason = StaEvent.AUTH_FAILURE_WRONG_PSWD;
5417                         break;
5418                     case WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE:
5419                         event.authFailureReason = StaEvent.AUTH_FAILURE_EAP_FAILURE;
5420                         break;
5421                     default:
5422                         break;
5423                 }
5424                 break;
5425             case WifiMonitor.NETWORK_CONNECTION_EVENT:
5426                 event.type = StaEvent.TYPE_NETWORK_CONNECTION_EVENT;
5427                 break;
5428             case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
5429                 event.type = StaEvent.TYPE_NETWORK_DISCONNECTION_EVENT;
5430                 DisconnectEventInfo disconnectEventInfo = (DisconnectEventInfo) msg.obj;
5431                 event.reason = disconnectEventInfo.reasonCode;
5432                 event.localGen = disconnectEventInfo.locallyGenerated;
5433                 break;
5434             case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
5435                 logEvent = false;
5436                 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
5437                 mSupplicantStateChangeBitmask |= supplicantStateToBit(stateChangeResult.state);
5438                 break;
5439             case WifiMonitor.ASSOCIATED_BSSID_EVENT:
5440                 event.type = StaEvent.TYPE_CMD_ASSOCIATED_BSSID;
5441                 break;
5442             case WifiMonitor.TARGET_BSSID_EVENT:
5443                 event.type = StaEvent.TYPE_CMD_TARGET_BSSID;
5444                 break;
5445             default:
5446                 return;
5447         }
5448         if (logEvent) {
5449             addStaEvent(ifaceName, event);
5450         }
5451     }
5452     /**
5453      * Log a StaEvent from ClientModeImpl. The StaEvent must not be one of the supplicant
5454      * generated event types, which are logged through 'sendMessage'
5455      * @param type StaEvent.EventType describing the event
5456      */
logStaEvent(String ifaceName, int type)5457     public void logStaEvent(String ifaceName, int type) {
5458         logStaEvent(ifaceName, type, StaEvent.DISCONNECT_UNKNOWN, null);
5459     }
5460     /**
5461      * Log a StaEvent from ClientModeImpl. The StaEvent must not be one of the supplicant
5462      * generated event types, which are logged through 'sendMessage'
5463      * @param type StaEvent.EventType describing the event
5464      * @param config WifiConfiguration for a framework initiated connection attempt
5465      */
logStaEvent(String ifaceName, int type, WifiConfiguration config)5466     public void logStaEvent(String ifaceName, int type, WifiConfiguration config) {
5467         logStaEvent(ifaceName, type, StaEvent.DISCONNECT_UNKNOWN, config);
5468     }
5469     /**
5470      * Log a StaEvent from ClientModeImpl. The StaEvent must not be one of the supplicant
5471      * generated event types, which are logged through 'sendMessage'
5472      * @param type StaEvent.EventType describing the event
5473      * @param frameworkDisconnectReason StaEvent.FrameworkDisconnectReason explaining why framework
5474      *                                  initiated a FRAMEWORK_DISCONNECT
5475      */
logStaEvent(String ifaceName, int type, int frameworkDisconnectReason)5476     public void logStaEvent(String ifaceName, int type, int frameworkDisconnectReason) {
5477         logStaEvent(ifaceName, type, frameworkDisconnectReason, null);
5478     }
5479     /**
5480      * Log a StaEvent from ClientModeImpl. The StaEvent must not be one of the supplicant
5481      * generated event types, which are logged through 'sendMessage'
5482      * @param type StaEvent.EventType describing the event
5483      * @param frameworkDisconnectReason StaEvent.FrameworkDisconnectReason explaining why framework
5484      *                                  initiated a FRAMEWORK_DISCONNECT
5485      * @param config WifiConfiguration for a framework initiated connection attempt
5486      */
logStaEvent(String ifaceName, int type, int frameworkDisconnectReason, WifiConfiguration config)5487     public void logStaEvent(String ifaceName, int type, int frameworkDisconnectReason,
5488             WifiConfiguration config) {
5489         switch (type) {
5490             case StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL:
5491             case StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST:
5492             case StaEvent.TYPE_CMD_IP_REACHABILITY_LOST:
5493             case StaEvent.TYPE_CMD_START_CONNECT:
5494             case StaEvent.TYPE_CMD_START_ROAM:
5495             case StaEvent.TYPE_CONNECT_NETWORK:
5496             case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK:
5497                 mWifiStatusBuilder.setValidated(true);
5498             case StaEvent.TYPE_FRAMEWORK_DISCONNECT:
5499             case StaEvent.TYPE_SCORE_BREACH:
5500             case StaEvent.TYPE_MAC_CHANGE:
5501             case StaEvent.TYPE_WIFI_ENABLED:
5502             case StaEvent.TYPE_WIFI_DISABLED:
5503             case StaEvent.TYPE_WIFI_USABILITY_SCORE_BREACH:
5504                 break;
5505             default:
5506                 Log.e(TAG, "Unknown StaEvent:" + type);
5507                 return;
5508         }
5509         StaEvent event = new StaEvent();
5510         event.type = type;
5511         if (frameworkDisconnectReason != StaEvent.DISCONNECT_UNKNOWN) {
5512             event.frameworkDisconnectReason = frameworkDisconnectReason;
5513         }
5514         event.configInfo = createConfigInfo(config);
5515         addStaEvent(ifaceName, event);
5516     }
5517 
addStaEvent(String ifaceName, StaEvent staEvent)5518     private void addStaEvent(String ifaceName, StaEvent staEvent) {
5519         // Nano proto runtime will throw a NPE during serialization if interfaceName is null
5520         if (ifaceName == null) {
5521             Log.wtf(TAG, "Null StaEvent.ifaceName: " + staEventToString(staEvent));
5522             return;
5523         }
5524         staEvent.interfaceName = ifaceName;
5525         staEvent.interfaceRole = convertIfaceToEnum(ifaceName);
5526         staEvent.startTimeMillis = mClock.getElapsedSinceBootMillis();
5527         staEvent.lastRssi = mLastPollRssi;
5528         staEvent.lastFreq = mLastPollFreq;
5529         staEvent.lastLinkSpeed = mLastPollLinkSpeed;
5530         staEvent.supplicantStateChangesBitmask = mSupplicantStateChangeBitmask;
5531         staEvent.lastScore = mLastScore;
5532         staEvent.lastWifiUsabilityScore = mLastWifiUsabilityScore;
5533         staEvent.lastPredictionHorizonSec = mLastPredictionHorizonSec;
5534         staEvent.mobileTxBytes = mFacade.getMobileTxBytes();
5535         staEvent.mobileRxBytes = mFacade.getMobileRxBytes();
5536         staEvent.totalTxBytes = mFacade.getTotalTxBytes();
5537         staEvent.totalRxBytes = mFacade.getTotalRxBytes();
5538         staEvent.screenOn = mScreenOn;
5539         if (mWifiDataStall != null) {
5540             staEvent.isCellularDataAvailable = mWifiDataStall.isCellularDataAvailable();
5541         }
5542         staEvent.isAdaptiveConnectivityEnabled = mAdaptiveConnectivityEnabled;
5543         mSupplicantStateChangeBitmask = 0;
5544         mLastPollRssi = -127;
5545         mLastPollFreq = -1;
5546         mLastPollLinkSpeed = -1;
5547         mLastPollRxLinkSpeed = -1;
5548         mLastScore = -1;
5549         mLastWifiUsabilityScore = -1;
5550         mLastPredictionHorizonSec = -1;
5551         synchronized (mLock) {
5552             mStaEventList.add(new StaEventWithTime(staEvent, mClock.getWallClockMillis()));
5553             // Prune StaEventList if it gets too long
5554             if (mStaEventList.size() > MAX_STA_EVENTS) mStaEventList.remove();
5555         }
5556     }
5557 
createConfigInfo(WifiConfiguration config)5558     private ConfigInfo createConfigInfo(WifiConfiguration config) {
5559         if (config == null) return null;
5560         ConfigInfo info = new ConfigInfo();
5561         info.allowedKeyManagement = bitSetToInt(config.allowedKeyManagement);
5562         info.allowedProtocols = bitSetToInt(config.allowedProtocols);
5563         info.allowedAuthAlgorithms = bitSetToInt(config.allowedAuthAlgorithms);
5564         info.allowedPairwiseCiphers = bitSetToInt(config.allowedPairwiseCiphers);
5565         info.allowedGroupCiphers = bitSetToInt(config.allowedGroupCiphers);
5566         info.hiddenSsid = config.hiddenSSID;
5567         info.isPasspoint = config.isPasspoint();
5568         info.isEphemeral = config.isEphemeral();
5569         info.hasEverConnected = config.getNetworkSelectionStatus().hasEverConnected();
5570         ScanResult candidate = config.getNetworkSelectionStatus().getCandidate();
5571         if (candidate != null) {
5572             info.scanRssi = candidate.level;
5573             info.scanFreq = candidate.frequency;
5574         }
5575         return info;
5576     }
5577 
5578     private static final int[] WIFI_MONITOR_EVENTS = {
5579             WifiMonitor.ASSOCIATION_REJECTION_EVENT,
5580             WifiMonitor.AUTHENTICATION_FAILURE_EVENT,
5581             WifiMonitor.NETWORK_CONNECTION_EVENT,
5582             WifiMonitor.NETWORK_DISCONNECTION_EVENT,
5583             WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT,
5584             WifiMonitor.ASSOCIATED_BSSID_EVENT,
5585             WifiMonitor.TARGET_BSSID_EVENT,
5586     };
5587 
registerForWifiMonitorEvents(String ifaceName)5588     public void registerForWifiMonitorEvents(String ifaceName) {
5589         for (int event : WIFI_MONITOR_EVENTS) {
5590             mWifiMonitor.registerHandler(ifaceName, event, mHandler);
5591         }
5592     }
5593 
deregisterForWifiMonitorEvents(String ifaceName)5594     public void deregisterForWifiMonitorEvents(String ifaceName) {
5595         for (int event : WIFI_MONITOR_EVENTS) {
5596             mWifiMonitor.deregisterHandler(ifaceName, event, mHandler);
5597         }
5598     }
5599 
getWifiAwareMetrics()5600     public WifiAwareMetrics getWifiAwareMetrics() {
5601         return mWifiAwareMetrics;
5602     }
5603 
getWakeupMetrics()5604     public WifiWakeMetrics getWakeupMetrics() {
5605         return mWifiWakeMetrics;
5606     }
5607 
getRttMetrics()5608     public RttMetrics getRttMetrics() {
5609         return mRttMetrics;
5610     }
5611 
5612     // Rather than generate a StaEvent for each SUPPLICANT_STATE_CHANGE, cache these in a bitmask
5613     // and attach it to the next event which is generated.
5614     private int mSupplicantStateChangeBitmask = 0;
5615 
5616     /**
5617      * Converts a SupplicantState value to a single bit, with position defined by
5618      * {@code StaEvent.SupplicantState}
5619      */
supplicantStateToBit(SupplicantState state)5620     public static int supplicantStateToBit(SupplicantState state) {
5621         switch(state) {
5622             case DISCONNECTED:
5623                 return 1 << StaEvent.STATE_DISCONNECTED;
5624             case INTERFACE_DISABLED:
5625                 return 1 << StaEvent.STATE_INTERFACE_DISABLED;
5626             case INACTIVE:
5627                 return 1 << StaEvent.STATE_INACTIVE;
5628             case SCANNING:
5629                 return 1 << StaEvent.STATE_SCANNING;
5630             case AUTHENTICATING:
5631                 return 1 << StaEvent.STATE_AUTHENTICATING;
5632             case ASSOCIATING:
5633                 return 1 << StaEvent.STATE_ASSOCIATING;
5634             case ASSOCIATED:
5635                 return 1 << StaEvent.STATE_ASSOCIATED;
5636             case FOUR_WAY_HANDSHAKE:
5637                 return 1 << StaEvent.STATE_FOUR_WAY_HANDSHAKE;
5638             case GROUP_HANDSHAKE:
5639                 return 1 << StaEvent.STATE_GROUP_HANDSHAKE;
5640             case COMPLETED:
5641                 return 1 << StaEvent.STATE_COMPLETED;
5642             case DORMANT:
5643                 return 1 << StaEvent.STATE_DORMANT;
5644             case UNINITIALIZED:
5645                 return 1 << StaEvent.STATE_UNINITIALIZED;
5646             case INVALID:
5647                 return 1 << StaEvent.STATE_INVALID;
5648             default:
5649                 Log.wtf(TAG, "Got unknown supplicant state: " + state.ordinal());
5650                 return 0;
5651         }
5652     }
5653 
supplicantStateChangesBitmaskToString(int mask)5654     private static String supplicantStateChangesBitmaskToString(int mask) {
5655         StringBuilder sb = new StringBuilder();
5656         sb.append("supplicantStateChangeEvents: {");
5657         if ((mask & (1 << StaEvent.STATE_DISCONNECTED)) > 0) sb.append(" DISCONNECTED");
5658         if ((mask & (1 << StaEvent.STATE_INTERFACE_DISABLED)) > 0) sb.append(" INTERFACE_DISABLED");
5659         if ((mask & (1 << StaEvent.STATE_INACTIVE)) > 0) sb.append(" INACTIVE");
5660         if ((mask & (1 << StaEvent.STATE_SCANNING)) > 0) sb.append(" SCANNING");
5661         if ((mask & (1 << StaEvent.STATE_AUTHENTICATING)) > 0) sb.append(" AUTHENTICATING");
5662         if ((mask & (1 << StaEvent.STATE_ASSOCIATING)) > 0) sb.append(" ASSOCIATING");
5663         if ((mask & (1 << StaEvent.STATE_ASSOCIATED)) > 0) sb.append(" ASSOCIATED");
5664         if ((mask & (1 << StaEvent.STATE_FOUR_WAY_HANDSHAKE)) > 0) sb.append(" FOUR_WAY_HANDSHAKE");
5665         if ((mask & (1 << StaEvent.STATE_GROUP_HANDSHAKE)) > 0) sb.append(" GROUP_HANDSHAKE");
5666         if ((mask & (1 << StaEvent.STATE_COMPLETED)) > 0) sb.append(" COMPLETED");
5667         if ((mask & (1 << StaEvent.STATE_DORMANT)) > 0) sb.append(" DORMANT");
5668         if ((mask & (1 << StaEvent.STATE_UNINITIALIZED)) > 0) sb.append(" UNINITIALIZED");
5669         if ((mask & (1 << StaEvent.STATE_INVALID)) > 0) sb.append(" INVALID");
5670         sb.append(" }");
5671         return sb.toString();
5672     }
5673 
5674     /**
5675      * Returns a human readable string from a Sta Event. Only adds information relevant to the event
5676      * type.
5677      */
staEventToString(StaEvent event)5678     public static String staEventToString(StaEvent event) {
5679         if (event == null) return "<NULL>";
5680         StringBuilder sb = new StringBuilder();
5681         switch (event.type) {
5682             case StaEvent.TYPE_ASSOCIATION_REJECTION_EVENT:
5683                 sb.append("ASSOCIATION_REJECTION_EVENT")
5684                         .append(" timedOut=").append(event.associationTimedOut)
5685                         .append(" status=").append(event.status).append(":")
5686                         .append(StaIfaceStatusCode.toString(event.status));
5687                 break;
5688             case StaEvent.TYPE_AUTHENTICATION_FAILURE_EVENT:
5689                 sb.append("AUTHENTICATION_FAILURE_EVENT reason=").append(event.authFailureReason)
5690                         .append(":").append(authFailureReasonToString(event.authFailureReason));
5691                 break;
5692             case StaEvent.TYPE_NETWORK_CONNECTION_EVENT:
5693                 sb.append("NETWORK_CONNECTION_EVENT");
5694                 break;
5695             case StaEvent.TYPE_NETWORK_DISCONNECTION_EVENT:
5696                 sb.append("NETWORK_DISCONNECTION_EVENT")
5697                         .append(" local_gen=").append(event.localGen)
5698                         .append(" reason=").append(event.reason).append(":")
5699                         .append(StaIfaceReasonCode.toString(
5700                                 (event.reason >= 0 ? event.reason : -1 * event.reason)));
5701                 break;
5702             case StaEvent.TYPE_CMD_ASSOCIATED_BSSID:
5703                 sb.append("CMD_ASSOCIATED_BSSID");
5704                 break;
5705             case StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL:
5706                 sb.append("CMD_IP_CONFIGURATION_SUCCESSFUL");
5707                 break;
5708             case StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST:
5709                 sb.append("CMD_IP_CONFIGURATION_LOST");
5710                 break;
5711             case StaEvent.TYPE_CMD_IP_REACHABILITY_LOST:
5712                 sb.append("CMD_IP_REACHABILITY_LOST");
5713                 break;
5714             case StaEvent.TYPE_CMD_TARGET_BSSID:
5715                 sb.append("CMD_TARGET_BSSID");
5716                 break;
5717             case StaEvent.TYPE_CMD_START_CONNECT:
5718                 sb.append("CMD_START_CONNECT");
5719                 break;
5720             case StaEvent.TYPE_CMD_START_ROAM:
5721                 sb.append("CMD_START_ROAM");
5722                 break;
5723             case StaEvent.TYPE_CONNECT_NETWORK:
5724                 sb.append("CONNECT_NETWORK");
5725                 break;
5726             case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK:
5727                 sb.append("NETWORK_AGENT_VALID_NETWORK");
5728                 break;
5729             case StaEvent.TYPE_FRAMEWORK_DISCONNECT:
5730                 sb.append("FRAMEWORK_DISCONNECT")
5731                         .append(" reason=")
5732                         .append(frameworkDisconnectReasonToString(event.frameworkDisconnectReason));
5733                 break;
5734             case StaEvent.TYPE_SCORE_BREACH:
5735                 sb.append("SCORE_BREACH");
5736                 break;
5737             case StaEvent.TYPE_MAC_CHANGE:
5738                 sb.append("MAC_CHANGE");
5739                 break;
5740             case StaEvent.TYPE_WIFI_ENABLED:
5741                 sb.append("WIFI_ENABLED");
5742                 break;
5743             case StaEvent.TYPE_WIFI_DISABLED:
5744                 sb.append("WIFI_DISABLED");
5745                 break;
5746             case StaEvent.TYPE_WIFI_USABILITY_SCORE_BREACH:
5747                 sb.append("WIFI_USABILITY_SCORE_BREACH");
5748                 break;
5749             case StaEvent.TYPE_LINK_PROBE:
5750                 sb.append("LINK_PROBE");
5751                 sb.append(" linkProbeWasSuccess=").append(event.linkProbeWasSuccess);
5752                 if (event.linkProbeWasSuccess) {
5753                     sb.append(" linkProbeSuccessElapsedTimeMs=")
5754                             .append(event.linkProbeSuccessElapsedTimeMs);
5755                 } else {
5756                     sb.append(" linkProbeFailureReason=").append(event.linkProbeFailureReason);
5757                 }
5758                 break;
5759             default:
5760                 sb.append("UNKNOWN " + event.type + ":");
5761                 break;
5762         }
5763         if (event.lastRssi != -127) sb.append(" lastRssi=").append(event.lastRssi);
5764         if (event.lastFreq != -1) sb.append(" lastFreq=").append(event.lastFreq);
5765         if (event.lastLinkSpeed != -1) sb.append(" lastLinkSpeed=").append(event.lastLinkSpeed);
5766         if (event.lastScore != -1) sb.append(" lastScore=").append(event.lastScore);
5767         if (event.lastWifiUsabilityScore != -1) {
5768             sb.append(" lastWifiUsabilityScore=").append(event.lastWifiUsabilityScore);
5769             sb.append(" lastPredictionHorizonSec=").append(event.lastPredictionHorizonSec);
5770         }
5771         sb.append(" screenOn=").append(event.screenOn);
5772         sb.append(" cellularData=").append(event.isCellularDataAvailable);
5773         sb.append(" adaptiveConnectivity=").append(event.isAdaptiveConnectivityEnabled);
5774         if (event.supplicantStateChangesBitmask != 0) {
5775             sb.append(", ").append(supplicantStateChangesBitmaskToString(
5776                     event.supplicantStateChangesBitmask));
5777         }
5778         if (event.configInfo != null) {
5779             sb.append(", ").append(configInfoToString(event.configInfo));
5780         }
5781         if (event.mobileTxBytes > 0) sb.append(" mobileTxBytes=").append(event.mobileTxBytes);
5782         if (event.mobileRxBytes > 0) sb.append(" mobileRxBytes=").append(event.mobileRxBytes);
5783         if (event.totalTxBytes > 0) sb.append(" totalTxBytes=").append(event.totalTxBytes);
5784         if (event.totalRxBytes > 0) sb.append(" totalRxBytes=").append(event.totalRxBytes);
5785         sb.append(" interfaceName=").append(event.interfaceName);
5786         sb.append(" interfaceRole=").append(clientRoleEnumToString(event.interfaceRole));
5787         return sb.toString();
5788     }
5789 
convertIfaceToEnum(String ifaceName)5790     private int convertIfaceToEnum(String ifaceName) {
5791         ActiveModeManager.ClientRole role = mIfaceToRoleMap.get(ifaceName);
5792         if (role == ActiveModeManager.ROLE_CLIENT_SCAN_ONLY) {
5793             return WifiMetricsProto.ROLE_CLIENT_SCAN_ONLY;
5794         } else if (role == ActiveModeManager.ROLE_CLIENT_SECONDARY_TRANSIENT) {
5795             return WifiMetricsProto.ROLE_CLIENT_SECONDARY_TRANSIENT;
5796         } else if (role == ActiveModeManager.ROLE_CLIENT_LOCAL_ONLY) {
5797             return WifiMetricsProto.ROLE_CLIENT_LOCAL_ONLY;
5798         } else if (role == ActiveModeManager.ROLE_CLIENT_PRIMARY) {
5799             return WifiMetricsProto.ROLE_CLIENT_PRIMARY;
5800         } else if (role == ActiveModeManager.ROLE_CLIENT_SECONDARY_LONG_LIVED) {
5801             return WifiMetricsProto.ROLE_CLIENT_SECONDARY_LONG_LIVED;
5802         }
5803         return WifiMetricsProto.ROLE_UNKNOWN;
5804     }
5805 
clientRoleEnumToString(int role)5806     private static String clientRoleEnumToString(int role) {
5807         switch (role) {
5808             case WifiMetricsProto.ROLE_CLIENT_SCAN_ONLY:
5809                 return "ROLE_CLIENT_SCAN_ONLY";
5810             case WifiMetricsProto.ROLE_CLIENT_SECONDARY_TRANSIENT:
5811                 return "ROLE_CLIENT_SECONDARY_TRANSIENT";
5812             case WifiMetricsProto.ROLE_CLIENT_LOCAL_ONLY:
5813                 return "ROLE_CLIENT_LOCAL_ONLY";
5814             case WifiMetricsProto.ROLE_CLIENT_PRIMARY:
5815                 return "ROLE_CLIENT_PRIMARY";
5816             case WifiMetricsProto.ROLE_CLIENT_SECONDARY_LONG_LIVED:
5817                 return "ROLE_CLIENT_SECONDARY_LONG_LIVED";
5818             default:
5819                 return "ROLE_UNKNOWN";
5820         }
5821     }
5822 
authFailureReasonToString(int authFailureReason)5823     private static String authFailureReasonToString(int authFailureReason) {
5824         switch (authFailureReason) {
5825             case StaEvent.AUTH_FAILURE_NONE:
5826                 return "ERROR_AUTH_FAILURE_NONE";
5827             case StaEvent.AUTH_FAILURE_TIMEOUT:
5828                 return "ERROR_AUTH_FAILURE_TIMEOUT";
5829             case StaEvent.AUTH_FAILURE_WRONG_PSWD:
5830                 return "ERROR_AUTH_FAILURE_WRONG_PSWD";
5831             case StaEvent.AUTH_FAILURE_EAP_FAILURE:
5832                 return "ERROR_AUTH_FAILURE_EAP_FAILURE";
5833             default:
5834                 return "";
5835         }
5836     }
5837 
frameworkDisconnectReasonToString(int frameworkDisconnectReason)5838     private static String frameworkDisconnectReasonToString(int frameworkDisconnectReason) {
5839         switch (frameworkDisconnectReason) {
5840             case StaEvent.DISCONNECT_API:
5841                 return "DISCONNECT_API";
5842             case StaEvent.DISCONNECT_GENERIC:
5843                 return "DISCONNECT_GENERIC";
5844             case StaEvent.DISCONNECT_UNWANTED:
5845                 return "DISCONNECT_UNWANTED";
5846             case StaEvent.DISCONNECT_ROAM_WATCHDOG_TIMER:
5847                 return "DISCONNECT_ROAM_WATCHDOG_TIMER";
5848             case StaEvent.DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST:
5849                 return "DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST";
5850             case StaEvent.DISCONNECT_RESET_SIM_NETWORKS:
5851                 return "DISCONNECT_RESET_SIM_NETWORKS";
5852             case StaEvent.DISCONNECT_MBB_NO_INTERNET:
5853                 return "DISCONNECT_MBB_NO_INTERNET";
5854             case StaEvent.DISCONNECT_NETWORK_REMOVED:
5855                 return "DISCONNECT_NETWORK_REMOVED";
5856             case StaEvent.DISCONNECT_NETWORK_METERED:
5857                 return "DISCONNECT_NETWORK_METERED";
5858             case StaEvent.DISCONNECT_NETWORK_TEMPORARY_DISABLED:
5859                 return "DISCONNECT_NETWORK_TEMPORARY_DISABLED";
5860             case StaEvent.DISCONNECT_NETWORK_PERMANENT_DISABLED:
5861                 return "DISCONNECT_NETWORK_PERMANENT_DISABLED";
5862             case StaEvent.DISCONNECT_CARRIER_OFFLOAD_DISABLED:
5863                 return "DISCONNECT_CARRIER_OFFLOAD_DISABLED";
5864             case StaEvent.DISCONNECT_PASSPOINT_TAC:
5865                 return "DISCONNECT_PASSPOINT_TAC";
5866             case StaEvent.DISCONNECT_VCN_REQUEST:
5867                 return "DISCONNECT_VCN_REQUEST";
5868             case StaEvent.DISCONNECT_UNKNOWN_NETWORK:
5869                 return "DISCONNECT_UNKNOWN_NETWORK";
5870             default:
5871                 return "DISCONNECT_UNKNOWN=" + frameworkDisconnectReason;
5872         }
5873     }
5874 
configInfoToString(ConfigInfo info)5875     private static String configInfoToString(ConfigInfo info) {
5876         StringBuilder sb = new StringBuilder();
5877         sb.append("ConfigInfo:")
5878                 .append(" allowed_key_management=").append(info.allowedKeyManagement)
5879                 .append(" allowed_protocols=").append(info.allowedProtocols)
5880                 .append(" allowed_auth_algorithms=").append(info.allowedAuthAlgorithms)
5881                 .append(" allowed_pairwise_ciphers=").append(info.allowedPairwiseCiphers)
5882                 .append(" allowed_group_ciphers=").append(info.allowedGroupCiphers)
5883                 .append(" hidden_ssid=").append(info.hiddenSsid)
5884                 .append(" is_passpoint=").append(info.isPasspoint)
5885                 .append(" is_ephemeral=").append(info.isEphemeral)
5886                 .append(" has_ever_connected=").append(info.hasEverConnected)
5887                 .append(" scan_rssi=").append(info.scanRssi)
5888                 .append(" scan_freq=").append(info.scanFreq);
5889         return sb.toString();
5890     }
5891 
5892     /**
5893      * Converts the first 31 bits of a BitSet to a little endian int
5894      */
bitSetToInt(BitSet bits)5895     private static int bitSetToInt(BitSet bits) {
5896         int value = 0;
5897         int nBits = bits.length() < 31 ? bits.length() : 31;
5898         for (int i = 0; i < nBits; i++) {
5899             value += bits.get(i) ? (1 << i) : 0;
5900         }
5901         return value;
5902     }
5903     private void incrementSsid(SparseIntArray sia, int element) {
5904         increment(sia, Math.min(element, MAX_CONNECTABLE_SSID_NETWORK_BUCKET));
5905     }
5906     private void incrementBssid(SparseIntArray sia, int element) {
5907         increment(sia, Math.min(element, MAX_CONNECTABLE_BSSID_NETWORK_BUCKET));
5908     }
5909     private void incrementTotalScanResults(SparseIntArray sia, int element) {
5910         increment(sia, Math.min(element, MAX_TOTAL_SCAN_RESULTS_BUCKET));
5911     }
5912     private void incrementTotalScanSsids(SparseIntArray sia, int element) {
5913         increment(sia, Math.min(element, MAX_TOTAL_SCAN_RESULT_SSIDS_BUCKET));
5914     }
5915     private void incrementTotalPasspointAps(SparseIntArray sia, int element) {
5916         increment(sia, Math.min(element, MAX_TOTAL_PASSPOINT_APS_BUCKET));
5917     }
5918     private void incrementTotalUniquePasspointEss(SparseIntArray sia, int element) {
5919         increment(sia, Math.min(element, MAX_TOTAL_PASSPOINT_UNIQUE_ESS_BUCKET));
5920     }
5921     private void incrementPasspointPerUniqueEss(SparseIntArray sia, int element) {
5922         increment(sia, Math.min(element, MAX_PASSPOINT_APS_PER_UNIQUE_ESS_BUCKET));
5923     }
5924     private void increment80211mcAps(SparseIntArray sia, int element) {
5925         increment(sia, Math.min(element, MAX_TOTAL_80211MC_APS_BUCKET));
5926     }
5927     private void increment(SparseIntArray sia, int element) {
5928         int count = sia.get(element);
5929         sia.put(element, count + 1);
5930     }
5931 
5932     private static class StaEventWithTime {
5933         public StaEvent staEvent;
5934         public long wallClockMillis;
5935 
5936         StaEventWithTime(StaEvent event, long wallClockMillis) {
5937             staEvent = event;
5938             this.wallClockMillis = wallClockMillis;
5939         }
5940 
5941         public String toString() {
5942             StringBuilder sb = new StringBuilder();
5943             Calendar c = Calendar.getInstance();
5944             c.setTimeInMillis(wallClockMillis);
5945             if (wallClockMillis != 0) {
5946                 sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
5947             } else {
5948                 sb.append("                  ");
5949             }
5950             sb.append(" ").append(staEventToString(staEvent));
5951             return sb.toString();
5952         }
5953     }
5954 
5955     private LinkedList<WifiIsUnusableWithTime> mWifiIsUnusableList =
5956             new LinkedList<WifiIsUnusableWithTime>();
5957     private long mTxScucessDelta = 0;
5958     private long mTxRetriesDelta = 0;
5959     private long mTxBadDelta = 0;
5960     private long mRxSuccessDelta = 0;
5961     private long mLlStatsUpdateTimeDelta = 0;
5962     private long mLlStatsLastUpdateTime = 0;
5963     private int mLastScoreNoReset = -1;
5964     private long mLastDataStallTime = Long.MIN_VALUE;
5965 
5966     private static class WifiIsUnusableWithTime {
5967         public WifiIsUnusableEvent event;
5968         public long wallClockMillis;
5969 
5970         WifiIsUnusableWithTime(WifiIsUnusableEvent event, long wallClockMillis) {
5971             this.event = event;
5972             this.wallClockMillis = wallClockMillis;
5973         }
5974 
5975         public String toString() {
5976             if (event == null) return "<NULL>";
5977             StringBuilder sb = new StringBuilder();
5978             if (wallClockMillis != 0) {
5979                 Calendar c = Calendar.getInstance();
5980                 c.setTimeInMillis(wallClockMillis);
5981                 sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
5982             } else {
5983                 sb.append("                  ");
5984             }
5985             sb.append(" ");
5986 
5987             switch(event.type) {
5988                 case WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX:
5989                     sb.append("DATA_STALL_BAD_TX");
5990                     break;
5991                 case WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX:
5992                     sb.append("DATA_STALL_TX_WITHOUT_RX");
5993                     break;
5994                 case WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH:
5995                     sb.append("DATA_STALL_BOTH");
5996                     break;
5997                 case WifiIsUnusableEvent.TYPE_FIRMWARE_ALERT:
5998                     sb.append("FIRMWARE_ALERT");
5999                     break;
6000                 case WifiIsUnusableEvent.TYPE_IP_REACHABILITY_LOST:
6001                     sb.append("IP_REACHABILITY_LOST");
6002                     break;
6003                 default:
6004                     sb.append("UNKNOWN " + event.type);
6005                     break;
6006             }
6007 
6008             sb.append(" lastScore=").append(event.lastScore);
6009             sb.append(" txSuccessDelta=").append(event.txSuccessDelta);
6010             sb.append(" txRetriesDelta=").append(event.txRetriesDelta);
6011             sb.append(" txBadDelta=").append(event.txBadDelta);
6012             sb.append(" rxSuccessDelta=").append(event.rxSuccessDelta);
6013             sb.append(" packetUpdateTimeDelta=").append(event.packetUpdateTimeDelta)
6014                     .append("ms");
6015             if (event.firmwareAlertCode != -1) {
6016                 sb.append(" firmwareAlertCode=").append(event.firmwareAlertCode);
6017             }
6018             sb.append(" lastWifiUsabilityScore=").append(event.lastWifiUsabilityScore);
6019             sb.append(" lastPredictionHorizonSec=").append(event.lastPredictionHorizonSec);
6020             sb.append(" screenOn=").append(event.screenOn);
6021             sb.append(" mobileTxBytes=").append(event.mobileTxBytes);
6022             sb.append(" mobileRxBytes=").append(event.mobileRxBytes);
6023             sb.append(" totalTxBytes=").append(event.totalTxBytes);
6024             sb.append(" totalRxBytes=").append(event.totalRxBytes);
6025             return sb.toString();
6026         }
6027     }
6028 
6029     /**
6030      * Converts MeteredOverride enum to UserActionEvent type.
6031      * @param value
6032      */
6033     public static int convertMeteredOverrideEnumToUserActionEventType(@MeteredOverride int value) {
6034         int result = UserActionEvent.EVENT_UNKNOWN;
6035         switch(value) {
6036             case WifiConfiguration.METERED_OVERRIDE_NONE:
6037                 result = UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_AUTO;
6038                 break;
6039             case WifiConfiguration.METERED_OVERRIDE_METERED:
6040                 result = UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_METERED;
6041                 break;
6042             case WifiConfiguration.METERED_OVERRIDE_NOT_METERED:
6043                 result = UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_UNMETERED;
6044                 break;
6045         }
6046         return result;
6047     }
6048 
6049     /**
6050      * Converts Adaptive Connectivity state to UserActionEvent type.
6051      * @param value
6052      */
6053     public static int convertAdaptiveConnectivityStateToUserActionEventType(boolean value) {
6054         return value ? UserActionEvent.EVENT_CONFIGURE_ADAPTIVE_CONNECTIVITY_ON
6055                 : UserActionEvent.EVENT_CONFIGURE_ADAPTIVE_CONNECTIVITY_OFF;
6056     }
6057 
6058     static class MeteredNetworkStatsBuilder {
6059         // A map from network identifier to MeteredDetail
6060         Map<String, MeteredDetail> mNetworkMap = new ArrayMap<>();
6061 
6062         void put(WifiConfiguration config, boolean detectedAsMetered) {
6063             MeteredDetail meteredDetail = new MeteredDetail();
6064             boolean isMetered = detectedAsMetered;
6065             if (config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_METERED) {
6066                 isMetered = true;
6067             } else if (config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_NOT_METERED) {
6068                 isMetered = false;
6069             }
6070             meteredDetail.isMetered = isMetered;
6071             meteredDetail.isMeteredOverrideSet = config.meteredOverride
6072                     != WifiConfiguration.METERED_OVERRIDE_NONE;
6073             meteredDetail.isFromSuggestion = config.fromWifiNetworkSuggestion;
6074             mNetworkMap.put(config.getProfileKey(), meteredDetail);
6075         }
6076 
6077         void clear() {
6078             mNetworkMap.clear();
6079         }
6080 
6081         MeteredNetworkStats toProto(boolean isFromSuggestion) {
6082             MeteredNetworkStats result = new MeteredNetworkStats();
6083             for (MeteredDetail meteredDetail : mNetworkMap.values()) {
6084                 if (meteredDetail.isFromSuggestion != isFromSuggestion) {
6085                     continue;
6086                 }
6087                 if (meteredDetail.isMetered) {
6088                     result.numMetered++;
6089                 } else {
6090                     result.numUnmetered++;
6091                 }
6092                 if (meteredDetail.isMeteredOverrideSet) {
6093                     if (meteredDetail.isMetered) {
6094                         result.numOverrideMetered++;
6095                     } else {
6096                         result.numOverrideUnmetered++;
6097                     }
6098                 }
6099             }
6100             return result;
6101         }
6102 
6103         static class MeteredDetail {
6104             public boolean isMetered;
6105             public boolean isMeteredOverrideSet;
6106             public boolean isFromSuggestion;
6107         }
6108     }
6109 
6110     /**
6111      * Add metered information of this network.
6112      * @param config WifiConfiguration representing the netework.
6113      * @param detectedAsMetered is the network detected as metered.
6114      */
6115     public void addMeteredStat(WifiConfiguration config, boolean detectedAsMetered) {
6116         synchronized (mLock) {
6117             if (config == null) {
6118                 return;
6119             }
6120             mMeteredNetworkStatsBuilder.put(config, detectedAsMetered);
6121         }
6122     }
6123     /**
6124      * Logs a UserActionEvent without a target network.
6125      * @param eventType the type of user action (one of WifiMetricsProto.UserActionEvent.EventType)
6126      */
6127     public void logUserActionEvent(int eventType) {
6128         logUserActionEvent(eventType, -1);
6129     }
6130 
6131     /**
6132      * Logs a UserActionEvent which has a target network.
6133      * @param eventType the type of user action (one of WifiMetricsProto.UserActionEvent.EventType)
6134      * @param networkId networkId of the target network.
6135      */
6136     public void logUserActionEvent(int eventType, int networkId) {
6137         synchronized (mLock) {
6138             mUserActionEventList.add(new UserActionEventWithTime(eventType, networkId));
6139             if (mUserActionEventList.size() > MAX_USER_ACTION_EVENTS) {
6140                 mUserActionEventList.remove();
6141             }
6142         }
6143     }
6144 
6145     /**
6146      * Logs a UserActionEvent, directly specifying the target network's properties.
6147      * @param eventType the type of user action (one of WifiMetricsProto.UserActionEvent.EventType)
6148      * @param isEphemeral true if the target network is ephemeral.
6149      * @param isPasspoint true if the target network is passpoint.
6150      */
6151     public void logUserActionEvent(int eventType, boolean isEphemeral, boolean isPasspoint) {
6152         synchronized (mLock) {
6153             TargetNetworkInfo networkInfo = new TargetNetworkInfo();
6154             networkInfo.isEphemeral = isEphemeral;
6155             networkInfo.isPasspoint = isPasspoint;
6156             mUserActionEventList.add(new UserActionEventWithTime(eventType, networkInfo));
6157             if (mUserActionEventList.size() > MAX_USER_ACTION_EVENTS) {
6158                 mUserActionEventList.remove();
6159             }
6160         }
6161     }
6162 
6163     /**
6164      * Update the difference between the last two WifiLinkLayerStats for WifiIsUnusableEvent
6165      */
6166     public void updateWifiIsUnusableLinkLayerStats(long txSuccessDelta, long txRetriesDelta,
6167             long txBadDelta, long rxSuccessDelta, long updateTimeDelta) {
6168         mTxScucessDelta = txSuccessDelta;
6169         mTxRetriesDelta = txRetriesDelta;
6170         mTxBadDelta = txBadDelta;
6171         mRxSuccessDelta = rxSuccessDelta;
6172         mLlStatsUpdateTimeDelta = updateTimeDelta;
6173         mLlStatsLastUpdateTime = mClock.getElapsedSinceBootMillis();
6174     }
6175 
6176     /**
6177      * Clear the saved difference between the last two WifiLinkLayerStats
6178      */
6179     public void resetWifiIsUnusableLinkLayerStats() {
6180         mTxScucessDelta = 0;
6181         mTxRetriesDelta = 0;
6182         mTxBadDelta = 0;
6183         mRxSuccessDelta = 0;
6184         mLlStatsUpdateTimeDelta = 0;
6185         mLlStatsLastUpdateTime = 0;
6186         mLastDataStallTime = Long.MIN_VALUE;
6187     }
6188 
6189     /**
6190      * Log a WifiIsUnusableEvent
6191      * @param triggerType WifiIsUnusableEvent.type describing the event
6192      * @param ifaceName name of the interface.
6193      */
6194     public void logWifiIsUnusableEvent(String ifaceName, int triggerType) {
6195         logWifiIsUnusableEvent(ifaceName, triggerType, -1);
6196     }
6197 
6198     /**
6199      * Log a WifiIsUnusableEvent
6200      * @param triggerType WifiIsUnusableEvent.type describing the event
6201      * @param firmwareAlertCode WifiIsUnusableEvent.firmwareAlertCode for firmware alert code
6202      * @param ifaceName name of the interface.
6203      */
6204     public void logWifiIsUnusableEvent(String ifaceName, int triggerType, int firmwareAlertCode) {
6205         if (!isPrimary(ifaceName)) {
6206             return;
6207         }
6208         mScoreBreachLowTimeMillis = -1;
6209         if (!mContext.getResources().getBoolean(R.bool.config_wifiIsUnusableEventMetricsEnabled)) {
6210             return;
6211         }
6212 
6213         long currentBootTime = mClock.getElapsedSinceBootMillis();
6214         switch (triggerType) {
6215             case WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX:
6216             case WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX:
6217             case WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH:
6218                 // Have a time-based throttle for generating WifiIsUnusableEvent from data stalls
6219                 if (currentBootTime < mLastDataStallTime + MIN_DATA_STALL_WAIT_MS) {
6220                     return;
6221                 }
6222                 mLastDataStallTime = currentBootTime;
6223                 break;
6224             case WifiIsUnusableEvent.TYPE_FIRMWARE_ALERT:
6225                 break;
6226             case WifiIsUnusableEvent.TYPE_IP_REACHABILITY_LOST:
6227                 break;
6228             default:
6229                 Log.e(TAG, "Unknown WifiIsUnusableEvent: " + triggerType);
6230                 return;
6231         }
6232 
6233         WifiIsUnusableEvent event = new WifiIsUnusableEvent();
6234         event.type = triggerType;
6235         if (triggerType == WifiIsUnusableEvent.TYPE_FIRMWARE_ALERT) {
6236             event.firmwareAlertCode = firmwareAlertCode;
6237         }
6238         event.startTimeMillis = currentBootTime;
6239         event.lastScore = mLastScoreNoReset;
6240         event.lastWifiUsabilityScore = mLastWifiUsabilityScoreNoReset;
6241         event.lastPredictionHorizonSec = mLastPredictionHorizonSecNoReset;
6242         event.txSuccessDelta = mTxScucessDelta;
6243         event.txRetriesDelta = mTxRetriesDelta;
6244         event.txBadDelta = mTxBadDelta;
6245         event.rxSuccessDelta = mRxSuccessDelta;
6246         event.packetUpdateTimeDelta = mLlStatsUpdateTimeDelta;
6247         event.lastLinkLayerStatsUpdateTime = mLlStatsLastUpdateTime;
6248         event.screenOn = mScreenOn;
6249         event.mobileTxBytes = mFacade.getMobileTxBytes();
6250         event.mobileRxBytes = mFacade.getMobileRxBytes();
6251         event.totalTxBytes = mFacade.getTotalTxBytes();
6252         event.totalRxBytes = mFacade.getTotalRxBytes();
6253 
6254         mWifiIsUnusableList.add(new WifiIsUnusableWithTime(event, mClock.getWallClockMillis()));
6255         if (mWifiIsUnusableList.size() > MAX_UNUSABLE_EVENTS) {
6256             mWifiIsUnusableList.removeFirst();
6257         }
6258     }
6259 
6260     /**
6261      * Extract data from |info| and |stats| to build a WifiUsabilityStatsEntry and then adds it
6262      * into an internal ring buffer.
6263      * @param info
6264      * @param stats
6265      * @param ifaceName
6266      */
6267     public void updateWifiUsabilityStatsEntries(String ifaceName, WifiInfo info,
6268             WifiLinkLayerStats stats) {
6269         // This is only collected for primary STA currently because RSSI polling is disabled for
6270         // non-primary STAs.
6271         synchronized (mLock) {
6272             if (info == null) {
6273                 return;
6274             }
6275             if (stats == null) {
6276                 // For devices lacking vendor hal, fill in the parts that we can
6277                 stats = new WifiLinkLayerStats();
6278                 stats.timeStampInMs = mClock.getElapsedSinceBootMillis();
6279                 stats.txmpdu_be = info.txSuccess;
6280                 stats.retries_be = info.txRetries;
6281                 stats.lostmpdu_be = info.txBad;
6282                 stats.rxmpdu_be = info.rxSuccess;
6283             }
6284             WifiUsabilityStatsEntry wifiUsabilityStatsEntry =
6285                     mWifiUsabilityStatsEntriesList.size()
6286                     < MAX_WIFI_USABILITY_STATS_ENTRIES_LIST_SIZE
6287                     ? new WifiUsabilityStatsEntry() : mWifiUsabilityStatsEntriesList.remove();
6288             wifiUsabilityStatsEntry.timeStampMs = stats.timeStampInMs;
6289             wifiUsabilityStatsEntry.totalTxSuccess = stats.txmpdu_be + stats.txmpdu_bk
6290                     + stats.txmpdu_vi + stats.txmpdu_vo;
6291             wifiUsabilityStatsEntry.totalTxRetries = stats.retries_be + stats.retries_bk
6292                     + stats.retries_vi + stats.retries_vo;
6293             wifiUsabilityStatsEntry.totalTxBad = stats.lostmpdu_be + stats.lostmpdu_bk
6294                     + stats.lostmpdu_vi + stats.lostmpdu_vo;
6295             wifiUsabilityStatsEntry.totalRxSuccess = stats.rxmpdu_be + stats.rxmpdu_bk
6296                     + stats.rxmpdu_vi + stats.rxmpdu_vo;
6297             /* Update per radio stats */
6298             if (stats.radioStats != null && stats.radioStats.length > 0) {
6299                 int numRadios = stats.radioStats.length;
6300                 wifiUsabilityStatsEntry.radioStats =
6301                         new RadioStats[numRadios];
6302                 for (int i = 0; i < numRadios; i++) {
6303                     RadioStats radioStats = new RadioStats();
6304                     WifiLinkLayerStats.RadioStat radio = stats.radioStats[i];
6305                     radioStats.radioId = radio.radio_id;
6306                     radioStats.totalRadioOnTimeMs = radio.on_time;
6307                     radioStats.totalRadioTxTimeMs = radio.tx_time;
6308                     radioStats.totalRadioRxTimeMs = radio.rx_time;
6309                     radioStats.totalScanTimeMs = radio.on_time_scan;
6310                     radioStats.totalNanScanTimeMs = radio.on_time_nan_scan;
6311                     radioStats.totalBackgroundScanTimeMs = radio.on_time_background_scan;
6312                     radioStats.totalRoamScanTimeMs = radio.on_time_roam_scan;
6313                     radioStats.totalPnoScanTimeMs = radio.on_time_pno_scan;
6314                     radioStats.totalHotspot2ScanTimeMs = radio.on_time_hs20_scan;
6315                     wifiUsabilityStatsEntry.radioStats[i] = radioStats;
6316                 }
6317             }
6318             wifiUsabilityStatsEntry.totalRadioOnTimeMs = stats.on_time;
6319             wifiUsabilityStatsEntry.totalRadioTxTimeMs = stats.tx_time;
6320             wifiUsabilityStatsEntry.totalRadioRxTimeMs = stats.rx_time;
6321             wifiUsabilityStatsEntry.totalScanTimeMs = stats.on_time_scan;
6322             wifiUsabilityStatsEntry.totalNanScanTimeMs = stats.on_time_nan_scan;
6323             wifiUsabilityStatsEntry.totalBackgroundScanTimeMs = stats.on_time_background_scan;
6324             wifiUsabilityStatsEntry.totalRoamScanTimeMs = stats.on_time_roam_scan;
6325             wifiUsabilityStatsEntry.totalPnoScanTimeMs = stats.on_time_pno_scan;
6326             wifiUsabilityStatsEntry.totalHotspot2ScanTimeMs = stats.on_time_hs20_scan;
6327             wifiUsabilityStatsEntry.rssi = info.getRssi();
6328             wifiUsabilityStatsEntry.linkSpeedMbps = info.getLinkSpeed();
6329             WifiLinkLayerStats.ChannelStats statsMap =
6330                     stats.channelStatsMap.get(info.getFrequency());
6331             if (statsMap != null) {
6332                 wifiUsabilityStatsEntry.totalRadioOnFreqTimeMs = statsMap.radioOnTimeMs;
6333                 wifiUsabilityStatsEntry.totalCcaBusyFreqTimeMs = statsMap.ccaBusyTimeMs;
6334             }
6335             wifiUsabilityStatsEntry.totalBeaconRx = stats.beacon_rx;
6336             wifiUsabilityStatsEntry.timeSliceDutyCycleInPercent = stats.timeSliceDutyCycleInPercent;
6337 
6338             boolean isSameBssidAndFreq = mLastBssid == null || mLastFrequency == -1
6339                     || (mLastBssid.equals(info.getBSSID())
6340                     && mLastFrequency == info.getFrequency());
6341             mLastBssid = info.getBSSID();
6342             mLastFrequency = info.getFrequency();
6343             wifiUsabilityStatsEntry.wifiScore = mLastScoreNoReset;
6344             wifiUsabilityStatsEntry.wifiUsabilityScore = mLastWifiUsabilityScoreNoReset;
6345             wifiUsabilityStatsEntry.seqNumToFramework = mSeqNumToFramework;
6346             wifiUsabilityStatsEntry.predictionHorizonSec = mLastPredictionHorizonSecNoReset;
6347             switch (mProbeStatusSinceLastUpdate) {
6348                 case android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE:
6349                     wifiUsabilityStatsEntry.probeStatusSinceLastUpdate =
6350                             WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE;
6351                     break;
6352                 case android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS:
6353                     wifiUsabilityStatsEntry.probeStatusSinceLastUpdate =
6354                             WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS;
6355                     break;
6356                 case android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE:
6357                     wifiUsabilityStatsEntry.probeStatusSinceLastUpdate =
6358                             WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE;
6359                     break;
6360                 default:
6361                     wifiUsabilityStatsEntry.probeStatusSinceLastUpdate =
6362                             WifiUsabilityStatsEntry.PROBE_STATUS_UNKNOWN;
6363                     Log.e(TAG, "Unknown link probe status: " + mProbeStatusSinceLastUpdate);
6364             }
6365             wifiUsabilityStatsEntry.probeElapsedTimeSinceLastUpdateMs =
6366                     mProbeElapsedTimeSinceLastUpdateMs;
6367             wifiUsabilityStatsEntry.probeMcsRateSinceLastUpdate = mProbeMcsRateSinceLastUpdate;
6368             wifiUsabilityStatsEntry.rxLinkSpeedMbps = info.getRxLinkSpeedMbps();
6369             wifiUsabilityStatsEntry.isSameBssidAndFreq = isSameBssidAndFreq;
6370             wifiUsabilityStatsEntry.seqNumInsideFramework = mSeqNumInsideFramework;
6371             wifiUsabilityStatsEntry.deviceMobilityState = mCurrentDeviceMobilityState;
6372             wifiUsabilityStatsEntry.contentionTimeStats =
6373                     new ContentionTimeStats[NUM_WME_ACCESS_CATEGORIES];
6374             for (int ac = 0; ac < NUM_WME_ACCESS_CATEGORIES; ac++) {
6375                 ContentionTimeStats contentionTimeStats = new ContentionTimeStats();
6376                 switch (ac) {
6377                     case ContentionTimeStats.WME_ACCESS_CATEGORY_BE:
6378                         contentionTimeStats.accessCategory =
6379                                 ContentionTimeStats.WME_ACCESS_CATEGORY_BE;
6380                         contentionTimeStats.contentionTimeMinMicros =
6381                                 stats.contentionTimeMinBeInUsec;
6382                         contentionTimeStats.contentionTimeMaxMicros =
6383                                 stats.contentionTimeMaxBeInUsec;
6384                         contentionTimeStats.contentionTimeAvgMicros =
6385                                 stats.contentionTimeAvgBeInUsec;
6386                         contentionTimeStats.contentionNumSamples =
6387                                 stats.contentionNumSamplesBe;
6388                         break;
6389                     case ContentionTimeStats.WME_ACCESS_CATEGORY_BK:
6390                         contentionTimeStats.accessCategory =
6391                                 ContentionTimeStats.WME_ACCESS_CATEGORY_BK;
6392                         contentionTimeStats.contentionTimeMinMicros =
6393                                 stats.contentionTimeMinBkInUsec;
6394                         contentionTimeStats.contentionTimeMaxMicros =
6395                                 stats.contentionTimeMaxBkInUsec;
6396                         contentionTimeStats.contentionTimeAvgMicros =
6397                                 stats.contentionTimeAvgBkInUsec;
6398                         contentionTimeStats.contentionNumSamples =
6399                                 stats.contentionNumSamplesBk;
6400                         break;
6401                     case ContentionTimeStats.WME_ACCESS_CATEGORY_VI:
6402                         contentionTimeStats.accessCategory =
6403                                 ContentionTimeStats.WME_ACCESS_CATEGORY_VI;
6404                         contentionTimeStats.contentionTimeMinMicros =
6405                                 stats.contentionTimeMinViInUsec;
6406                         contentionTimeStats.contentionTimeMaxMicros =
6407                                 stats.contentionTimeMaxViInUsec;
6408                         contentionTimeStats.contentionTimeAvgMicros =
6409                                 stats.contentionTimeAvgViInUsec;
6410                         contentionTimeStats.contentionNumSamples =
6411                                 stats.contentionNumSamplesVi;
6412                         break;
6413                     case ContentionTimeStats.WME_ACCESS_CATEGORY_VO:
6414                         contentionTimeStats.accessCategory =
6415                                 ContentionTimeStats.WME_ACCESS_CATEGORY_VO;
6416                         contentionTimeStats.contentionTimeMinMicros =
6417                                 stats.contentionTimeMinVoInUsec;
6418                         contentionTimeStats.contentionTimeMaxMicros =
6419                                 stats.contentionTimeMaxVoInUsec;
6420                         contentionTimeStats.contentionTimeAvgMicros =
6421                                 stats.contentionTimeAvgVoInUsec;
6422                         contentionTimeStats.contentionNumSamples =
6423                                 stats.contentionNumSamplesVo;
6424                         break;
6425                     default:
6426                         Log.e(TAG, "Unknown WME Access Category: " + ac);
6427                 }
6428                 wifiUsabilityStatsEntry.contentionTimeStats[ac] = contentionTimeStats;
6429             }
6430             if (mWifiChannelUtilization != null) {
6431                 wifiUsabilityStatsEntry.channelUtilizationRatio =
6432                         mWifiChannelUtilization.getUtilizationRatio(mLastFrequency);
6433             }
6434             if (mWifiDataStall != null) {
6435                 wifiUsabilityStatsEntry.isThroughputSufficient =
6436                         mWifiDataStall.isThroughputSufficient();
6437                 wifiUsabilityStatsEntry.isCellularDataAvailable =
6438                         mWifiDataStall.isCellularDataAvailable();
6439             }
6440             if (mWifiSettingsStore != null) {
6441                 wifiUsabilityStatsEntry.isWifiScoringEnabled =
6442                         mWifiSettingsStore.isWifiScoringEnabled();
6443             }
6444             // Here it is assumed there is only one peer information from HAL and the peer is the
6445             // AP that STA is associated with.
6446             if (stats.peerInfo != null && stats.peerInfo.length > 0
6447                     && stats.peerInfo[0].rateStats != null) {
6448                 wifiUsabilityStatsEntry.staCount = stats.peerInfo[0].staCount;
6449                 wifiUsabilityStatsEntry.channelUtilization = stats.peerInfo[0].chanUtil;
6450                 int numRates = stats.peerInfo[0].rateStats != null
6451                         ? stats.peerInfo[0].rateStats.length : 0;
6452                 wifiUsabilityStatsEntry.rateStats = new RateStats[numRates];
6453                 for (int i = 0; i < numRates; i++) {
6454                     RateStats rate = new RateStats();
6455                     WifiLinkLayerStats.RateStat curRate = stats.peerInfo[0].rateStats[i];
6456                     rate.preamble = curRate.preamble;
6457                     rate.nss = curRate.nss;
6458                     rate.bw = curRate.bw;
6459                     rate.rateMcsIdx = curRate.rateMcsIdx;
6460                     rate.bitRateInKbps = curRate.bitRateInKbps;
6461                     rate.txMpdu = curRate.txMpdu;
6462                     rate.rxMpdu = curRate.rxMpdu;
6463                     rate.mpduLost = curRate.mpduLost;
6464                     rate.retries = curRate.retries;
6465                     wifiUsabilityStatsEntry.rateStats[i] = rate;
6466                 }
6467             }
6468 
6469             mWifiUsabilityStatsEntriesList.add(wifiUsabilityStatsEntry);
6470             mWifiUsabilityStatsCounter++;
6471             if (mWifiUsabilityStatsCounter >= NUM_WIFI_USABILITY_STATS_ENTRIES_PER_WIFI_GOOD) {
6472                 addToWifiUsabilityStatsList(ifaceName, WifiUsabilityStats.LABEL_GOOD,
6473                         WifiUsabilityStats.TYPE_UNKNOWN, -1);
6474             }
6475             if (mScoreBreachLowTimeMillis != -1) {
6476                 long elapsedTime =  mClock.getElapsedSinceBootMillis() - mScoreBreachLowTimeMillis;
6477                 if (elapsedTime >= MIN_SCORE_BREACH_TO_GOOD_STATS_WAIT_TIME_MS) {
6478                     mScoreBreachLowTimeMillis = -1;
6479                     if (elapsedTime <= VALIDITY_PERIOD_OF_SCORE_BREACH_LOW_MS) {
6480                         addToWifiUsabilityStatsList(ifaceName, WifiUsabilityStats.LABEL_GOOD,
6481                                 WifiUsabilityStats.TYPE_UNKNOWN, -1);
6482                     }
6483                 }
6484             }
6485 
6486             // Invoke Wifi usability stats listener.
6487             // TODO(b/179518316): Enable this for secondary transient STA also if external scorer
6488             // is in charge of MBB.
6489             sendWifiUsabilityStats(mSeqNumInsideFramework, isSameBssidAndFreq,
6490                     createNewWifiUsabilityStatsEntryParcelable(wifiUsabilityStatsEntry));
6491 
6492             mSeqNumInsideFramework++;
6493             mProbeStatusSinceLastUpdate =
6494                     android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE;
6495             mProbeElapsedTimeSinceLastUpdateMs = -1;
6496             mProbeMcsRateSinceLastUpdate = -1;
6497         }
6498     }
6499 
6500     /**
6501      * Send Wifi usability stats.
6502      * @param seqNum
6503      * @param isSameBssidAndFreq
6504      * @param statsEntry
6505      */
6506     private void sendWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
6507             android.net.wifi.WifiUsabilityStatsEntry statsEntry) {
6508         int itemCount = mOnWifiUsabilityListeners.beginBroadcast();
6509         for (int i = 0; i < itemCount; i++) {
6510             try {
6511                 mOnWifiUsabilityListeners.getBroadcastItem(i).onWifiUsabilityStats(seqNum,
6512                         isSameBssidAndFreq, statsEntry);
6513             } catch (RemoteException e) {
6514                 Log.e(TAG, "Unable to invoke Wifi usability stats entry listener ", e);
6515             }
6516         }
6517         mOnWifiUsabilityListeners.finishBroadcast();
6518     }
6519 
6520     private android.net.wifi.WifiUsabilityStatsEntry createNewWifiUsabilityStatsEntryParcelable(
6521             WifiUsabilityStatsEntry s) {
6522         int probeStatus;
6523         switch (s.probeStatusSinceLastUpdate) {
6524             case WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE:
6525                 probeStatus = android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE;
6526                 break;
6527             case WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS:
6528                 probeStatus = android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS;
6529                 break;
6530             case WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE:
6531                 probeStatus = android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE;
6532                 break;
6533             default:
6534                 probeStatus = android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_UNKNOWN;
6535                 Log.e(TAG, "Unknown link probe status: " + s.probeStatusSinceLastUpdate);
6536         }
6537         android.net.wifi.WifiUsabilityStatsEntry.ContentionTimeStats[] contentionTimeStats =
6538                 new android.net.wifi.WifiUsabilityStatsEntry.ContentionTimeStats[
6539                         android.net.wifi.WifiUsabilityStatsEntry.NUM_WME_ACCESS_CATEGORIES];
6540         createNewContentionTimeStatsParcelable(contentionTimeStats, s.contentionTimeStats);
6541         int numRates = s.rateStats != null ? s.rateStats.length : 0;
6542         android.net.wifi.WifiUsabilityStatsEntry.RateStats[] rateStats =
6543                 new android.net.wifi.WifiUsabilityStatsEntry.RateStats[numRates];
6544         createNewRateStatsParcelable(rateStats, s.rateStats);
6545         int numRadios = s.radioStats != null ? s.radioStats.length : 0;
6546         android.net.wifi.WifiUsabilityStatsEntry.RadioStats[] radioStats =
6547                 new android.net.wifi.WifiUsabilityStatsEntry.RadioStats[numRadios];
6548         createNewRadioStatsParcelable(radioStats, s.radioStats);
6549         // TODO: remove the following hardcoded values once if they are removed from public API
6550         return new android.net.wifi.WifiUsabilityStatsEntry(s.timeStampMs, s.rssi,
6551                 s.linkSpeedMbps, s.totalTxSuccess, s.totalTxRetries,
6552                 s.totalTxBad, s.totalRxSuccess, s.totalRadioOnTimeMs,
6553                 s.totalRadioTxTimeMs, s.totalRadioRxTimeMs, s.totalScanTimeMs,
6554                 s.totalNanScanTimeMs, s.totalBackgroundScanTimeMs, s.totalRoamScanTimeMs,
6555                 s.totalPnoScanTimeMs, s.totalHotspot2ScanTimeMs, s.totalCcaBusyFreqTimeMs,
6556                 s.totalRadioOnFreqTimeMs, s.totalBeaconRx, probeStatus,
6557                 s.probeElapsedTimeSinceLastUpdateMs, s.probeMcsRateSinceLastUpdate,
6558                 s.rxLinkSpeedMbps, s.timeSliceDutyCycleInPercent, contentionTimeStats, rateStats,
6559                 radioStats, s.channelUtilizationRatio, s.isThroughputSufficient,
6560                 s.isWifiScoringEnabled, s.isCellularDataAvailable, 0, 0, 0, false
6561         );
6562     }
6563 
6564     private void createNewContentionTimeStatsParcelable(
6565             android.net.wifi.WifiUsabilityStatsEntry.ContentionTimeStats[] statsParcelable,
6566                     ContentionTimeStats[] stats) {
6567         if (statsParcelable.length != stats.length || stats.length != NUM_WME_ACCESS_CATEGORIES) {
6568             Log.e(TAG, "The two ContentionTimeStats do not match in length: "
6569                     + " in proto: " + stats.length
6570                     + " in system API: " + statsParcelable.length);
6571             return;
6572         }
6573         for (int ac = 0; ac < NUM_WME_ACCESS_CATEGORIES; ac++) {
6574             android.net.wifi.WifiUsabilityStatsEntry.ContentionTimeStats stat =
6575                     new android.net.wifi.WifiUsabilityStatsEntry.ContentionTimeStats(
6576                             stats[ac].contentionTimeMinMicros,
6577                             stats[ac].contentionTimeMaxMicros,
6578                             stats[ac].contentionTimeAvgMicros,
6579                             stats[ac].contentionNumSamples);
6580             switch (ac) {
6581                 case ContentionTimeStats.WME_ACCESS_CATEGORY_BE:
6582                     statsParcelable[
6583                             android.net.wifi.WifiUsabilityStatsEntry.WME_ACCESS_CATEGORY_BE] = stat;
6584                     break;
6585                 case ContentionTimeStats.WME_ACCESS_CATEGORY_BK:
6586                     statsParcelable[
6587                             android.net.wifi.WifiUsabilityStatsEntry.WME_ACCESS_CATEGORY_BK] = stat;
6588                     break;
6589                 case ContentionTimeStats.WME_ACCESS_CATEGORY_VI:
6590                     statsParcelable[
6591                             android.net.wifi.WifiUsabilityStatsEntry.WME_ACCESS_CATEGORY_VI] = stat;
6592                     break;
6593                 case ContentionTimeStats.WME_ACCESS_CATEGORY_VO:
6594                     statsParcelable[
6595                             android.net.wifi.WifiUsabilityStatsEntry.WME_ACCESS_CATEGORY_VO] = stat;
6596                     break;
6597                 default:
6598                     Log.e(TAG, "Unknown WME Access Category: " + ac);
6599             }
6600         }
6601     }
6602 
6603     private void createNewRateStatsParcelable(
6604             android.net.wifi.WifiUsabilityStatsEntry.RateStats[] statsParcelable,
6605                     RateStats[] stats) {
6606         if (stats == null) {
6607             return;
6608         }
6609         for (int i = 0; i < stats.length; i++) {
6610             statsParcelable[i] = new android.net.wifi.WifiUsabilityStatsEntry.RateStats(
6611                     convertPreambleTypeEnumToUsabilityStatsType(stats[i].preamble),
6612                     convertSpatialStreamEnumToUsabilityStatsType(stats[i].nss),
6613                     convertBandwidthEnumToUsabilityStatsType(stats[i].bw),
6614                     stats[i].rateMcsIdx, stats[i].bitRateInKbps, stats[i].txMpdu, stats[i].rxMpdu,
6615                     stats[i].mpduLost, stats[i].retries
6616             );
6617         }
6618     }
6619 
6620     /**
6621      * Converts bandwidth enum in proto to WifiUsabilityStatsEntry type.
6622      * @param value
6623      */
6624     private static int convertBandwidthEnumToUsabilityStatsType(int value) {
6625         switch (value) {
6626             case RateStats.WIFI_BANDWIDTH_20_MHZ:
6627                 return android.net.wifi.WifiUsabilityStatsEntry.WIFI_BANDWIDTH_20_MHZ;
6628             case RateStats.WIFI_BANDWIDTH_40_MHZ:
6629                 return android.net.wifi.WifiUsabilityStatsEntry.WIFI_BANDWIDTH_40_MHZ;
6630             case RateStats.WIFI_BANDWIDTH_80_MHZ:
6631                 return android.net.wifi.WifiUsabilityStatsEntry.WIFI_BANDWIDTH_80_MHZ;
6632             case RateStats.WIFI_BANDWIDTH_160_MHZ:
6633                 return android.net.wifi.WifiUsabilityStatsEntry.WIFI_BANDWIDTH_160_MHZ;
6634             case RateStats.WIFI_BANDWIDTH_80P80_MHZ:
6635                 return android.net.wifi.WifiUsabilityStatsEntry.WIFI_BANDWIDTH_80P80_MHZ;
6636             case RateStats.WIFI_BANDWIDTH_5_MHZ:
6637                 return android.net.wifi.WifiUsabilityStatsEntry.WIFI_BANDWIDTH_5_MHZ;
6638             case RateStats.WIFI_BANDWIDTH_10_MHZ:
6639                 return android.net.wifi.WifiUsabilityStatsEntry.WIFI_BANDWIDTH_10_MHZ;
6640         }
6641         return android.net.wifi.WifiUsabilityStatsEntry.WIFI_BANDWIDTH_INVALID;
6642     }
6643 
6644     /**
6645      * Converts spatial streams enum in proto to WifiUsabilityStatsEntry type.
6646      * @param value
6647      */
6648     private static int convertSpatialStreamEnumToUsabilityStatsType(int value) {
6649         switch (value) {
6650             case RateStats.WIFI_SPATIAL_STREAMS_ONE:
6651                 return android.net.wifi.WifiUsabilityStatsEntry.WIFI_SPATIAL_STREAMS_ONE;
6652             case RateStats.WIFI_SPATIAL_STREAMS_TWO:
6653                 return android.net.wifi.WifiUsabilityStatsEntry.WIFI_SPATIAL_STREAMS_TWO;
6654             case RateStats.WIFI_SPATIAL_STREAMS_THREE:
6655                 return android.net.wifi.WifiUsabilityStatsEntry.WIFI_SPATIAL_STREAMS_THREE;
6656             case RateStats.WIFI_SPATIAL_STREAMS_FOUR:
6657                 return android.net.wifi.WifiUsabilityStatsEntry.WIFI_SPATIAL_STREAMS_FOUR;
6658         }
6659         return android.net.wifi.WifiUsabilityStatsEntry.WIFI_SPATIAL_STREAMS_INVALID;
6660     }
6661 
6662     /**
6663      * Converts preamble type enum in proto to WifiUsabilityStatsEntry type.
6664      * @param value
6665      */
6666     private static int convertPreambleTypeEnumToUsabilityStatsType(int value) {
6667         switch (value) {
6668             case RateStats.WIFI_PREAMBLE_OFDM:
6669                 return android.net.wifi.WifiUsabilityStatsEntry.WIFI_PREAMBLE_OFDM;
6670             case RateStats.WIFI_PREAMBLE_CCK:
6671                 return android.net.wifi.WifiUsabilityStatsEntry.WIFI_PREAMBLE_CCK;
6672             case RateStats.WIFI_PREAMBLE_HT:
6673                 return android.net.wifi.WifiUsabilityStatsEntry.WIFI_PREAMBLE_HT;
6674             case RateStats.WIFI_PREAMBLE_VHT:
6675                 return android.net.wifi.WifiUsabilityStatsEntry.WIFI_PREAMBLE_VHT;
6676             case RateStats.WIFI_PREAMBLE_HE:
6677                 return android.net.wifi.WifiUsabilityStatsEntry.WIFI_PREAMBLE_HE;
6678         }
6679         return android.net.wifi.WifiUsabilityStatsEntry.WIFI_PREAMBLE_INVALID;
6680     }
6681 
6682     private void createNewRadioStatsParcelable(
6683             android.net.wifi.WifiUsabilityStatsEntry.RadioStats[] statsParcelable,
6684             RadioStats[] stats) {
6685         if (stats == null) {
6686             return;
6687         }
6688         for (int i = 0; i < stats.length; i++) {
6689             statsParcelable[i] =
6690                     new android.net.wifi.WifiUsabilityStatsEntry.RadioStats(
6691                             stats[i].radioId,
6692                             stats[i].totalRadioOnTimeMs,
6693                             stats[i].totalRadioTxTimeMs,
6694                             stats[i].totalRadioRxTimeMs,
6695                             stats[i].totalScanTimeMs,
6696                             stats[i].totalNanScanTimeMs,
6697                             stats[i].totalBackgroundScanTimeMs,
6698                             stats[i].totalRoamScanTimeMs,
6699                             stats[i].totalPnoScanTimeMs,
6700                             stats[i].totalHotspot2ScanTimeMs);
6701         }
6702     }
6703 
6704     private WifiUsabilityStatsEntry createNewWifiUsabilityStatsEntry(WifiUsabilityStatsEntry s) {
6705         WifiUsabilityStatsEntry out = new WifiUsabilityStatsEntry();
6706         out.timeStampMs = s.timeStampMs;
6707         out.totalTxSuccess = s.totalTxSuccess;
6708         out.totalTxRetries = s.totalTxRetries;
6709         out.totalTxBad = s.totalTxBad;
6710         out.totalRxSuccess = s.totalRxSuccess;
6711         out.totalRadioOnTimeMs = s.totalRadioOnTimeMs;
6712         out.totalRadioTxTimeMs = s.totalRadioTxTimeMs;
6713         out.totalRadioRxTimeMs = s.totalRadioRxTimeMs;
6714         out.totalScanTimeMs = s.totalScanTimeMs;
6715         out.totalNanScanTimeMs = s.totalNanScanTimeMs;
6716         out.totalBackgroundScanTimeMs = s.totalBackgroundScanTimeMs;
6717         out.totalRoamScanTimeMs = s.totalRoamScanTimeMs;
6718         out.totalPnoScanTimeMs = s.totalPnoScanTimeMs;
6719         out.totalHotspot2ScanTimeMs = s.totalHotspot2ScanTimeMs;
6720         out.rssi = s.rssi;
6721         out.linkSpeedMbps = s.linkSpeedMbps;
6722         out.totalCcaBusyFreqTimeMs = s.totalCcaBusyFreqTimeMs;
6723         out.totalRadioOnFreqTimeMs = s.totalRadioOnFreqTimeMs;
6724         out.totalBeaconRx = s.totalBeaconRx;
6725         out.wifiScore = s.wifiScore;
6726         out.wifiUsabilityScore = s.wifiUsabilityScore;
6727         out.seqNumToFramework = s.seqNumToFramework;
6728         out.predictionHorizonSec = s.predictionHorizonSec;
6729         out.probeStatusSinceLastUpdate = s.probeStatusSinceLastUpdate;
6730         out.probeElapsedTimeSinceLastUpdateMs = s.probeElapsedTimeSinceLastUpdateMs;
6731         out.probeMcsRateSinceLastUpdate = s.probeMcsRateSinceLastUpdate;
6732         out.rxLinkSpeedMbps = s.rxLinkSpeedMbps;
6733         out.isSameBssidAndFreq = s.isSameBssidAndFreq;
6734         out.seqNumInsideFramework = s.seqNumInsideFramework;
6735         out.deviceMobilityState = s.deviceMobilityState;
6736         out.timeSliceDutyCycleInPercent = s.timeSliceDutyCycleInPercent;
6737         out.contentionTimeStats = s.contentionTimeStats;
6738         out.channelUtilizationRatio = s.channelUtilizationRatio;
6739         out.isThroughputSufficient = s.isThroughputSufficient;
6740         out.isWifiScoringEnabled = s.isWifiScoringEnabled;
6741         out.isCellularDataAvailable = s.isCellularDataAvailable;
6742         out.rateStats = s.rateStats;
6743         out.staCount = s.staCount;
6744         out.channelUtilization = s.channelUtilization;
6745         out.radioStats = s.radioStats;
6746         return out;
6747     }
6748 
6749     private WifiUsabilityStats createWifiUsabilityStatsWithLabel(int label, int triggerType,
6750             int firmwareAlertCode) {
6751         WifiUsabilityStats wifiUsabilityStats = new WifiUsabilityStats();
6752         wifiUsabilityStats.label = label;
6753         wifiUsabilityStats.triggerType = triggerType;
6754         wifiUsabilityStats.firmwareAlertCode = firmwareAlertCode;
6755         wifiUsabilityStats.timeStampMs = mClock.getElapsedSinceBootMillis();
6756         wifiUsabilityStats.stats =
6757                 new WifiUsabilityStatsEntry[mWifiUsabilityStatsEntriesList.size()];
6758         for (int i = 0; i < mWifiUsabilityStatsEntriesList.size(); i++) {
6759             wifiUsabilityStats.stats[i] =
6760                     createNewWifiUsabilityStatsEntry(mWifiUsabilityStatsEntriesList.get(i));
6761         }
6762         return wifiUsabilityStats;
6763     }
6764 
6765     /**
6766      * Label the current snapshot of WifiUsabilityStatsEntrys and save the labeled data in memory.
6767      * @param label WifiUsabilityStats.LABEL_GOOD or WifiUsabilityStats.LABEL_BAD
6768      * @param triggerType what event triggers WifiUsabilityStats
6769      * @param firmwareAlertCode the firmware alert code when the stats was triggered by a
6770      *        firmware alert
6771      */
6772     public void addToWifiUsabilityStatsList(String ifaceName, int label, int triggerType,
6773             int firmwareAlertCode) {
6774         synchronized (mLock) {
6775             if (!isPrimary(ifaceName)) {
6776                 return;
6777             }
6778             if (mWifiUsabilityStatsEntriesList.isEmpty() || !mScreenOn) {
6779                 return;
6780             }
6781             if (label == WifiUsabilityStats.LABEL_GOOD) {
6782                 // Only add a good event if at least |MIN_WIFI_GOOD_USABILITY_STATS_PERIOD_MS|
6783                 // has passed.
6784                 if (mWifiUsabilityStatsListGood.isEmpty()
6785                         || mWifiUsabilityStatsListGood.getLast().stats[mWifiUsabilityStatsListGood
6786                         .getLast().stats.length - 1].timeStampMs
6787                         + MIN_WIFI_GOOD_USABILITY_STATS_PERIOD_MS
6788                         < mWifiUsabilityStatsEntriesList.getLast().timeStampMs) {
6789                     while (mWifiUsabilityStatsListGood.size()
6790                             >= MAX_WIFI_USABILITY_STATS_LIST_SIZE_PER_TYPE) {
6791                         mWifiUsabilityStatsListGood.remove(
6792                                 mRand.nextInt(mWifiUsabilityStatsListGood.size()));
6793                     }
6794                     mWifiUsabilityStatsListGood.add(
6795                             createWifiUsabilityStatsWithLabel(label, triggerType,
6796                                     firmwareAlertCode));
6797                 }
6798             } else {
6799                 // Only add a bad event if at least |MIN_DATA_STALL_WAIT_MS|
6800                 // has passed.
6801                 mScoreBreachLowTimeMillis = -1;
6802                 if (mWifiUsabilityStatsListBad.isEmpty()
6803                         || (mWifiUsabilityStatsListBad.getLast().stats[mWifiUsabilityStatsListBad
6804                         .getLast().stats.length - 1].timeStampMs
6805                         + MIN_DATA_STALL_WAIT_MS
6806                         < mWifiUsabilityStatsEntriesList.getLast().timeStampMs)) {
6807                     while (mWifiUsabilityStatsListBad.size()
6808                             >= MAX_WIFI_USABILITY_STATS_LIST_SIZE_PER_TYPE) {
6809                         mWifiUsabilityStatsListBad.remove(
6810                                 mRand.nextInt(mWifiUsabilityStatsListBad.size()));
6811                     }
6812                     mWifiUsabilityStatsListBad.add(
6813                             createWifiUsabilityStatsWithLabel(label, triggerType,
6814                                     firmwareAlertCode));
6815                 }
6816             }
6817             mWifiUsabilityStatsCounter = 0;
6818             mWifiUsabilityStatsEntriesList.clear();
6819         }
6820     }
6821 
6822     private DeviceMobilityStatePnoScanStats getOrCreateDeviceMobilityStatePnoScanStats(
6823             @DeviceMobilityState int deviceMobilityState) {
6824         DeviceMobilityStatePnoScanStats stats = mMobilityStatePnoStatsMap.get(deviceMobilityState);
6825         if (stats == null) {
6826             stats = new DeviceMobilityStatePnoScanStats();
6827             stats.deviceMobilityState = deviceMobilityState;
6828             stats.numTimesEnteredState = 0;
6829             stats.totalDurationMs = 0;
6830             stats.pnoDurationMs = 0;
6831             mMobilityStatePnoStatsMap.put(deviceMobilityState, stats);
6832         }
6833         return stats;
6834     }
6835 
6836     /**
6837      * Updates the current device mobility state's total duration. This method should be called
6838      * before entering a new device mobility state.
6839      */
6840     private void updateCurrentMobilityStateTotalDuration(long now) {
6841         DeviceMobilityStatePnoScanStats stats =
6842                 getOrCreateDeviceMobilityStatePnoScanStats(mCurrentDeviceMobilityState);
6843         stats.totalDurationMs += now - mCurrentDeviceMobilityStateStartMs;
6844         mCurrentDeviceMobilityStateStartMs = now;
6845     }
6846 
6847     /**
6848      * Convert the IntCounter of passpoint profile types and counts to proto's
6849      * repeated IntKeyVal array.
6850      *
6851      * @param passpointProfileTypes passpoint profile types and counts.
6852      */
6853     private PasspointProfileTypeCount[] convertPasspointProfilesToProto(
6854                 IntCounter passpointProfileTypes) {
6855         return passpointProfileTypes.toProto(PasspointProfileTypeCount.class, (key, count) -> {
6856             PasspointProfileTypeCount entry = new PasspointProfileTypeCount();
6857             entry.eapMethodType = key;
6858             entry.count = count;
6859             return entry;
6860         });
6861     }
6862 
6863     /**
6864      * Reports that the device entered a new mobility state.
6865      *
6866      * @param newState the new device mobility state.
6867      */
6868     public void enterDeviceMobilityState(@DeviceMobilityState int newState) {
6869         synchronized (mLock) {
6870             long now = mClock.getElapsedSinceBootMillis();
6871             updateCurrentMobilityStateTotalDuration(now);
6872 
6873             if (newState == mCurrentDeviceMobilityState) return;
6874 
6875             mCurrentDeviceMobilityState = newState;
6876             DeviceMobilityStatePnoScanStats stats =
6877                     getOrCreateDeviceMobilityStatePnoScanStats(mCurrentDeviceMobilityState);
6878             stats.numTimesEnteredState++;
6879         }
6880     }
6881 
6882     /**
6883      * Logs the start of a PNO scan.
6884      */
6885     public void logPnoScanStart() {
6886         synchronized (mLock) {
6887             long now = mClock.getElapsedSinceBootMillis();
6888             mCurrentDeviceMobilityStatePnoScanStartMs = now;
6889             updateCurrentMobilityStateTotalDuration(now);
6890         }
6891     }
6892 
6893     /**
6894      * Logs the end of a PNO scan. This is attributed to the current device mobility state, as
6895      * logged by {@link #enterDeviceMobilityState(int)}. Thus, if the mobility state changes during
6896      * a PNO scan, one should call {@link #logPnoScanStop()}, {@link #enterDeviceMobilityState(int)}
6897      * , then {@link #logPnoScanStart()} so that the portion of PNO scan before the mobility state
6898      * change can be correctly attributed to the previous mobility state.
6899      */
6900     public void logPnoScanStop() {
6901         synchronized (mLock) {
6902             if (mCurrentDeviceMobilityStatePnoScanStartMs < 0) {
6903                 Log.e(TAG, "Called WifiMetrics#logPNoScanStop() without calling "
6904                         + "WifiMetrics#logPnoScanStart() first!");
6905                 return;
6906             }
6907             DeviceMobilityStatePnoScanStats stats =
6908                     getOrCreateDeviceMobilityStatePnoScanStats(mCurrentDeviceMobilityState);
6909             long now = mClock.getElapsedSinceBootMillis();
6910             stats.pnoDurationMs += now - mCurrentDeviceMobilityStatePnoScanStartMs;
6911             mCurrentDeviceMobilityStatePnoScanStartMs = -1;
6912             updateCurrentMobilityStateTotalDuration(now);
6913         }
6914     }
6915 
6916     /**
6917      * Logs that wifi bug report is taken
6918      */
6919     public void logBugReport() {
6920         synchronized (mLock) {
6921             for (ConnectionEvent connectionEvent : mCurrentConnectionEventPerIface.values()) {
6922                 if (connectionEvent != null) {
6923                     connectionEvent.mConnectionEvent.automaticBugReportTaken = true;
6924                 }
6925             }
6926         }
6927     }
6928 
6929     /**
6930      * Add a new listener for Wi-Fi usability stats handling.
6931      */
6932     public void addOnWifiUsabilityListener(IOnWifiUsabilityStatsListener listener) {
6933         if (!mOnWifiUsabilityListeners.register(listener)) {
6934             Log.e(TAG, "Failed to add listener");
6935             return;
6936         }
6937         if (DBG) {
6938             Log.v(TAG, "Adding listener. Num listeners: "
6939                     + mOnWifiUsabilityListeners.getRegisteredCallbackCount());
6940         }
6941     }
6942 
6943     /**
6944      * Remove an existing listener for Wi-Fi usability stats handling.
6945      */
6946     public void removeOnWifiUsabilityListener(IOnWifiUsabilityStatsListener listener) {
6947         mOnWifiUsabilityListeners.unregister(listener);
6948         if (DBG) {
6949             Log.v(TAG, "Removing listener. Num listeners: "
6950                     + mOnWifiUsabilityListeners.getRegisteredCallbackCount());
6951         }
6952     }
6953 
6954     /**
6955      * Updates the Wi-Fi usability score and increments occurence of a particular Wifi usability
6956      * score passed in from outside framework. Scores are bounded within
6957      * [MIN_WIFI_USABILITY_SCORE, MAX_WIFI_USABILITY_SCORE].
6958      *
6959      * Also records events when the Wifi usability score breaches significant thresholds.
6960      *
6961      * @param seqNum Sequence number of the Wi-Fi usability score.
6962      * @param score The Wi-Fi usability score.
6963      * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score.
6964      */
6965     public void incrementWifiUsabilityScoreCount(String ifaceName, int seqNum, int score,
6966             int predictionHorizonSec) {
6967         if (score < MIN_WIFI_USABILITY_SCORE || score > MAX_WIFI_USABILITY_SCORE) {
6968             return;
6969         }
6970         synchronized (mLock) {
6971             mSeqNumToFramework = seqNum;
6972             mLastWifiUsabilityScore = score;
6973             mLastWifiUsabilityScoreNoReset = score;
6974             mWifiUsabilityScoreCounts.put(score, mWifiUsabilityScoreCounts.get(score) + 1);
6975             mLastPredictionHorizonSec = predictionHorizonSec;
6976             mLastPredictionHorizonSecNoReset = predictionHorizonSec;
6977 
6978             boolean wifiWins = mWifiWinsUsabilityScore;
6979             if (score > LOW_WIFI_USABILITY_SCORE) {
6980                 wifiWins = true;
6981             } else if (score < LOW_WIFI_USABILITY_SCORE) {
6982                 wifiWins = false;
6983             }
6984 
6985             if (wifiWins != mWifiWinsUsabilityScore) {
6986                 mWifiWinsUsabilityScore = wifiWins;
6987                 StaEvent event = new StaEvent();
6988                 event.type = StaEvent.TYPE_WIFI_USABILITY_SCORE_BREACH;
6989                 addStaEvent(ifaceName, event);
6990                 // Only record the first score breach by checking whether mScoreBreachLowTimeMillis
6991                 // has been set to -1
6992                 if (!wifiWins && mScoreBreachLowTimeMillis == -1) {
6993                     mScoreBreachLowTimeMillis = mClock.getElapsedSinceBootMillis();
6994                 }
6995             }
6996         }
6997     }
6998 
6999     /**
7000      * Reports stats for a successful link probe.
7001      *
7002      * @param timeSinceLastTxSuccessMs At {@code startTimestampMs}, the number of milliseconds since
7003      *                                 the last Tx success (according to
7004      *                                 {@link WifiInfo#txSuccess}).
7005      * @param rssi The Rx RSSI at {@code startTimestampMs}.
7006      * @param linkSpeed The Tx link speed in Mbps at {@code startTimestampMs}.
7007      * @param elapsedTimeMs The number of milliseconds between when the command to transmit the
7008      *                      probe was sent to the driver and when the driver responded that the
7009      *                      probe was ACKed. Note: this number should be correlated with the number
7010      *                      of retries that the driver attempted before the probe was ACKed.
7011      */
7012     public void logLinkProbeSuccess(String ifaceName, long timeSinceLastTxSuccessMs,
7013             int rssi, int linkSpeed, int elapsedTimeMs) {
7014         synchronized (mLock) {
7015             mProbeStatusSinceLastUpdate =
7016                     android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS;
7017             mProbeElapsedTimeSinceLastUpdateMs = elapsedTimeMs;
7018 
7019             mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram.increment(
7020                     (int) (timeSinceLastTxSuccessMs / 1000));
7021             mLinkProbeSuccessRssiCounts.increment(rssi);
7022             mLinkProbeSuccessLinkSpeedCounts.increment(linkSpeed);
7023             mLinkProbeSuccessElapsedTimeMsHistogram.increment(elapsedTimeMs);
7024 
7025             if (mLinkProbeStaEventCount < MAX_LINK_PROBE_STA_EVENTS) {
7026                 StaEvent event = new StaEvent();
7027                 event.type = StaEvent.TYPE_LINK_PROBE;
7028                 event.linkProbeWasSuccess = true;
7029                 event.linkProbeSuccessElapsedTimeMs = elapsedTimeMs;
7030                 addStaEvent(ifaceName, event);
7031             }
7032             mLinkProbeStaEventCount++;
7033         }
7034     }
7035 
7036     /**
7037      * Reports stats for an unsuccessful link probe.
7038      *
7039      * @param timeSinceLastTxSuccessMs At {@code startTimestampMs}, the number of milliseconds since
7040      *                                 the last Tx success (according to
7041      *                                 {@link WifiInfo#txSuccess}).
7042      * @param rssi The Rx RSSI at {@code startTimestampMs}.
7043      * @param linkSpeed The Tx link speed in Mbps at {@code startTimestampMs}.
7044      * @param reason The error code for the failure. See
7045      * {@link WifiNl80211Manager.SendMgmtFrameError}.
7046      */
7047     public void logLinkProbeFailure(String ifaceName, long timeSinceLastTxSuccessMs,
7048             int rssi, int linkSpeed, int reason) {
7049         synchronized (mLock) {
7050             mProbeStatusSinceLastUpdate =
7051                     android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE;
7052             mProbeElapsedTimeSinceLastUpdateMs = Integer.MAX_VALUE;
7053 
7054             mLinkProbeFailureSecondsSinceLastTxSuccessHistogram.increment(
7055                     (int) (timeSinceLastTxSuccessMs / 1000));
7056             mLinkProbeFailureRssiCounts.increment(rssi);
7057             mLinkProbeFailureLinkSpeedCounts.increment(linkSpeed);
7058             mLinkProbeFailureReasonCounts.increment(reason);
7059 
7060             if (mLinkProbeStaEventCount < MAX_LINK_PROBE_STA_EVENTS) {
7061                 StaEvent event = new StaEvent();
7062                 event.type = StaEvent.TYPE_LINK_PROBE;
7063                 event.linkProbeWasSuccess = false;
7064                 event.linkProbeFailureReason = linkProbeFailureReasonToProto(reason);
7065                 addStaEvent(ifaceName, event);
7066             }
7067             mLinkProbeStaEventCount++;
7068         }
7069     }
7070 
7071     /**
7072      * Increments the number of probes triggered by the experiment `experimentId`.
7073      */
7074     public void incrementLinkProbeExperimentProbeCount(String experimentId) {
7075         synchronized (mLock) {
7076             mLinkProbeExperimentProbeCounts.increment(experimentId);
7077         }
7078     }
7079 
7080     /**
7081      * Update wifi config store read duration.
7082      *
7083      * @param timeMs Time it took to complete the operation, in milliseconds
7084      */
7085     public void noteWifiConfigStoreReadDuration(int timeMs) {
7086         synchronized (mLock) {
7087             MetricsUtils.addValueToLinearHistogram(timeMs, mWifiConfigStoreReadDurationHistogram,
7088                     WIFI_CONFIG_STORE_IO_DURATION_BUCKET_RANGES_MS);
7089         }
7090     }
7091 
7092     /**
7093      * Update wifi config store write duration.
7094      *
7095      * @param timeMs Time it took to complete the operation, in milliseconds
7096      */
7097     public void noteWifiConfigStoreWriteDuration(int timeMs) {
7098         synchronized (mLock) {
7099             MetricsUtils.addValueToLinearHistogram(timeMs, mWifiConfigStoreWriteDurationHistogram,
7100                     WIFI_CONFIG_STORE_IO_DURATION_BUCKET_RANGES_MS);
7101         }
7102     }
7103 
7104     /**
7105      * Logs the decision of a network selection algorithm when compared against another network
7106      * selection algorithm.
7107      *
7108      * @param experiment1Id ID of one experiment
7109      * @param experiment2Id ID of the other experiment
7110      * @param isSameDecision did the 2 experiments make the same decision?
7111      * @param numNetworkChoices the number of non-null network choices there were, where the null
7112      *                          choice is not selecting any network
7113      */
7114     public void logNetworkSelectionDecision(int experiment1Id, int experiment2Id,
7115             boolean isSameDecision, int numNetworkChoices) {
7116         if (numNetworkChoices < 0) {
7117             Log.e(TAG, "numNetworkChoices cannot be negative!");
7118             return;
7119         }
7120         if (experiment1Id == experiment2Id) {
7121             Log.e(TAG, "comparing the same experiment id: " + experiment1Id);
7122             return;
7123         }
7124 
7125         Pair<Integer, Integer> key = new Pair<>(experiment1Id, experiment2Id);
7126         synchronized (mLock) {
7127             NetworkSelectionExperimentResults results =
7128                     mNetworkSelectionExperimentPairNumChoicesCounts
7129                             .computeIfAbsent(key, k -> new NetworkSelectionExperimentResults());
7130 
7131             IntCounter counter = isSameDecision
7132                     ? results.sameSelectionNumChoicesCounter
7133                     : results.differentSelectionNumChoicesCounter;
7134 
7135             counter.increment(numNetworkChoices);
7136         }
7137     }
7138 
7139     /** Increment number of network request API usage stats */
7140     public void incrementNetworkRequestApiNumRequest() {
7141         synchronized (mLock) {
7142             mWifiNetworkRequestApiLog.numRequest++;
7143         }
7144     }
7145 
7146     /** Add to the network request API match size histogram */
7147     public void incrementNetworkRequestApiMatchSizeHistogram(int matchSize) {
7148         synchronized (mLock) {
7149             mWifiNetworkRequestApiMatchSizeHistogram.increment(matchSize);
7150         }
7151     }
7152 
7153     /** Increment number of connection success on primary iface via network request API */
7154     public void incrementNetworkRequestApiNumConnectSuccessOnPrimaryIface() {
7155         synchronized (mLock) {
7156             mWifiNetworkRequestApiLog.numConnectSuccessOnPrimaryIface++;
7157         }
7158     }
7159 
7160     /** Increment number of requests that bypassed user approval via network request API */
7161     public void incrementNetworkRequestApiNumUserApprovalBypass() {
7162         synchronized (mLock) {
7163             mWifiNetworkRequestApiLog.numUserApprovalBypass++;
7164         }
7165     }
7166 
7167     /** Increment number of requests that user rejected via network request API */
7168     public void incrementNetworkRequestApiNumUserReject() {
7169         synchronized (mLock) {
7170             mWifiNetworkRequestApiLog.numUserReject++;
7171         }
7172     }
7173 
7174     /** Increment number of requests from unique apps via network request API */
7175     public void incrementNetworkRequestApiNumApps() {
7176         synchronized (mLock) {
7177             mWifiNetworkRequestApiLog.numApps++;
7178         }
7179     }
7180 
7181     /** Add to the network request API connection duration histogram */
7182     public void incrementNetworkRequestApiConnectionDurationSecOnPrimaryIfaceHistogram(
7183             int durationSec) {
7184         synchronized (mLock) {
7185             mWifiNetworkRequestApiConnectionDurationSecOnPrimaryIfaceHistogram.increment(
7186                     durationSec);
7187         }
7188     }
7189 
7190     /** Add to the network request API connection duration on secondary iface histogram */
7191     public void incrementNetworkRequestApiConnectionDurationSecOnSecondaryIfaceHistogram(
7192             int durationSec) {
7193         synchronized (mLock) {
7194             mWifiNetworkRequestApiConnectionDurationSecOnSecondaryIfaceHistogram.increment(
7195                     durationSec);
7196         }
7197     }
7198 
7199     /** Increment number of connection on primary iface via network request API */
7200     public void incrementNetworkRequestApiNumConnectOnPrimaryIface() {
7201         synchronized (mLock) {
7202             mWifiNetworkRequestApiLog.numConnectOnPrimaryIface++;
7203         }
7204     }
7205 
7206     /** Increment number of connection on secondary iface via network request API */
7207     public void incrementNetworkRequestApiNumConnectOnSecondaryIface() {
7208         synchronized (mLock) {
7209             mWifiNetworkRequestApiLog.numConnectOnSecondaryIface++;
7210         }
7211     }
7212 
7213     /** Increment number of connection success on secondary iface via network request API */
7214     public void incrementNetworkRequestApiNumConnectSuccessOnSecondaryIface() {
7215         synchronized (mLock) {
7216             mWifiNetworkRequestApiLog.numConnectSuccessOnSecondaryIface++;
7217         }
7218     }
7219 
7220     /** Increment number of concurrent connection via network request API */
7221     public void incrementNetworkRequestApiNumConcurrentConnection() {
7222         synchronized (mLock) {
7223             mWifiNetworkRequestApiLog.numConcurrentConnection++;
7224         }
7225     }
7226 
7227     /** Add to the network request API concurrent connection duration histogram */
7228     public void incrementNetworkRequestApiConcurrentConnectionDurationSecHistogram(
7229             int durationSec) {
7230         synchronized (mLock) {
7231             mWifiNetworkRequestApiConcurrentConnectionDurationSecHistogram.increment(
7232                     durationSec);
7233         }
7234     }
7235 
7236     /** Increment number of network suggestion API modification by app stats */
7237     public void incrementNetworkSuggestionApiNumModification() {
7238         synchronized (mLock) {
7239             mWifiNetworkSuggestionApiLog.numModification++;
7240         }
7241     }
7242 
7243     /** Increment number of connection success via network suggestion API */
7244     public void incrementNetworkSuggestionApiNumConnectSuccess() {
7245         synchronized (mLock) {
7246             mWifiNetworkSuggestionApiLog.numConnectSuccess++;
7247         }
7248     }
7249 
7250     /** Increment number of connection failure via network suggestion API */
7251     public void incrementNetworkSuggestionApiNumConnectFailure() {
7252         synchronized (mLock) {
7253             mWifiNetworkSuggestionApiLog.numConnectFailure++;
7254         }
7255     }
7256 
7257     /** Increment number of user revoke suggestion permission. Including from settings or
7258      * disallowed from UI.
7259      */
7260     public void incrementNetworkSuggestionUserRevokePermission() {
7261         synchronized (mLock) {
7262             mWifiNetworkSuggestionApiLog.userRevokeAppSuggestionPermission++;
7263         }
7264     }
7265 
7266     /**
7267      * Increment number of times a ScanResult matches more than one WifiNetworkSuggestion.
7268      */
7269     public void incrementNetworkSuggestionMoreThanOneSuggestionForSingleScanResult() {
7270         synchronized (mLock) {
7271             mWifiNetworkSuggestionApiLog.numMultipleSuggestions++;
7272         }
7273     }
7274 
7275     /**
7276      * Add a saved network which has at least has one suggestion for same network on the device.
7277      */
7278     public void addSuggestionExistsForSavedNetwork(String key) {
7279         synchronized (mLock) {
7280             mWifiNetworkSuggestionCoexistSavedNetworks.add(key);
7281         }
7282     }
7283 
7284     /**
7285      * Add a priority group which is using on the device.(Except default priority group).
7286      */
7287     public void addNetworkSuggestionPriorityGroup(int priorityGroup) {
7288         synchronized (mLock) {
7289             // Ignore the default group
7290             if (priorityGroup == 0) {
7291                 return;
7292             }
7293             mWifiNetworkSuggestionPriorityGroups.put(priorityGroup, true);
7294         }
7295 
7296     }
7297 
7298     /** Clear and set the latest network suggestion API max list size histogram */
7299     public void noteNetworkSuggestionApiListSizeHistogram(List<Integer> listSizes) {
7300         synchronized (mLock) {
7301             mWifiNetworkSuggestionApiListSizeHistogram.clear();
7302             for (Integer listSize : listSizes) {
7303                 mWifiNetworkSuggestionApiListSizeHistogram.increment(listSize);
7304             }
7305         }
7306     }
7307 
7308     /** Increment number of app add suggestion with different privilege */
7309     public void incrementNetworkSuggestionApiUsageNumOfAppInType(int appType) {
7310         int typeCode;
7311         synchronized (mLock) {
7312             switch (appType) {
7313                 case WifiNetworkSuggestionsManager.APP_TYPE_CARRIER_PRIVILEGED:
7314                     typeCode = WifiNetworkSuggestionApiLog.TYPE_CARRIER_PRIVILEGED;
7315                     break;
7316                 case WifiNetworkSuggestionsManager.APP_TYPE_NETWORK_PROVISIONING:
7317                     typeCode = WifiNetworkSuggestionApiLog.TYPE_NETWORK_PROVISIONING;
7318                     break;
7319                 case WifiNetworkSuggestionsManager.APP_TYPE_NON_PRIVILEGED:
7320                     typeCode = WifiNetworkSuggestionApiLog.TYPE_NON_PRIVILEGED;
7321                     break;
7322                 default:
7323                     typeCode = WifiNetworkSuggestionApiLog.TYPE_UNKNOWN;
7324             }
7325             mWifiNetworkSuggestionApiAppTypeCounter.increment(typeCode);
7326         }
7327     }
7328 
7329     /** Add user action to the approval suggestion app UI */
7330     public void addUserApprovalSuggestionAppUiReaction(@WifiNetworkSuggestionsManager.UserActionCode
7331             int actionType, boolean isDialog) {
7332         int actionCode;
7333         switch (actionType) {
7334             case WifiNetworkSuggestionsManager.ACTION_USER_ALLOWED_APP:
7335                 actionCode = UserReactionToApprovalUiEvent.ACTION_ALLOWED;
7336                 break;
7337             case WifiNetworkSuggestionsManager.ACTION_USER_DISALLOWED_APP:
7338                 actionCode = UserReactionToApprovalUiEvent.ACTION_DISALLOWED;
7339                 break;
7340             case WifiNetworkSuggestionsManager.ACTION_USER_DISMISS:
7341                 actionCode = UserReactionToApprovalUiEvent.ACTION_DISMISS;
7342                 break;
7343             default:
7344                 actionCode = UserReactionToApprovalUiEvent.ACTION_UNKNOWN;
7345         }
7346         UserReaction event = new UserReaction();
7347         event.userAction = actionCode;
7348         event.isDialog = isDialog;
7349         synchronized (mLock) {
7350             mUserApprovalSuggestionAppUiReactionList.add(event);
7351         }
7352     }
7353 
7354     /** Add user action to the approval Carrier Imsi protection exemption UI */
7355     public void addUserApprovalCarrierUiReaction(@WifiCarrierInfoManager.UserActionCode
7356             int actionType, boolean isDialog) {
7357         int actionCode;
7358         switch (actionType) {
7359             case WifiCarrierInfoManager.ACTION_USER_ALLOWED_CARRIER:
7360                 actionCode = UserReactionToApprovalUiEvent.ACTION_ALLOWED;
7361                 break;
7362             case WifiCarrierInfoManager.ACTION_USER_DISALLOWED_CARRIER:
7363                 actionCode = UserReactionToApprovalUiEvent.ACTION_DISALLOWED;
7364                 break;
7365             case WifiCarrierInfoManager.ACTION_USER_DISMISS:
7366                 actionCode = UserReactionToApprovalUiEvent.ACTION_DISMISS;
7367                 break;
7368             default:
7369                 actionCode = UserReactionToApprovalUiEvent.ACTION_UNKNOWN;
7370         }
7371         UserReaction event = new UserReaction();
7372         event.userAction = actionCode;
7373         event.isDialog = isDialog;
7374 
7375         synchronized (mLock) {
7376             mUserApprovalCarrierUiReactionList.add(event);
7377         }
7378     }
7379 
7380     /**
7381      * Sets the nominator for a network (i.e. which entity made the suggestion to connect)
7382      * @param networkId the ID of the network, from its {@link WifiConfiguration}
7383      * @param nominatorId the entity that made the suggestion to connect to this network,
7384      *                    from {@link WifiMetricsProto.ConnectionEvent.ConnectionNominator}
7385      */
7386     public void setNominatorForNetwork(int networkId, int nominatorId) {
7387         synchronized (mLock) {
7388             if (networkId == WifiConfiguration.INVALID_NETWORK_ID) return;
7389             mNetworkIdToNominatorId.put(networkId, nominatorId);
7390 
7391             // user connect choice is preventing switching off from the connected network
7392             if (nominatorId
7393                     == WifiMetricsProto.ConnectionEvent.NOMINATOR_SAVED_USER_CONNECT_CHOICE
7394                     && mWifiStatusBuilder.getNetworkId() == networkId) {
7395                 mWifiStatusBuilder.setUserChoice(true);
7396             }
7397         }
7398     }
7399 
7400     /**
7401      * Sets the numeric CandidateScorer id.
7402      */
7403     public void setNetworkSelectorExperimentId(int expId) {
7404         synchronized (mLock) {
7405             mNetworkSelectorExperimentId = expId;
7406         }
7407     }
7408 
7409     /** Add a WifiLock acqusition session */
7410     public void addWifiLockAcqSession(int lockType, long duration) {
7411         switch (lockType) {
7412             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
7413                 mWifiLockHighPerfAcqDurationSecHistogram.increment((int) (duration / 1000));
7414                 break;
7415 
7416             case WifiManager.WIFI_MODE_FULL_LOW_LATENCY:
7417                 mWifiLockLowLatencyAcqDurationSecHistogram.increment((int) (duration / 1000));
7418                 break;
7419 
7420             default:
7421                 Log.e(TAG, "addWifiLockAcqSession: Invalid lock type: " + lockType);
7422                 break;
7423         }
7424     }
7425 
7426     /** Add a WifiLock active session */
7427     public void addWifiLockActiveSession(int lockType, long duration) {
7428         switch (lockType) {
7429             case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
7430                 mWifiLockStats.highPerfActiveTimeMs += duration;
7431                 mWifiLockHighPerfActiveSessionDurationSecHistogram.increment(
7432                         (int) (duration / 1000));
7433                 break;
7434 
7435             case WifiManager.WIFI_MODE_FULL_LOW_LATENCY:
7436                 mWifiLockStats.lowLatencyActiveTimeMs += duration;
7437                 mWifiLockLowLatencyActiveSessionDurationSecHistogram.increment(
7438                         (int) (duration / 1000));
7439                 break;
7440 
7441             default:
7442                 Log.e(TAG, "addWifiLockActiveSession: Invalid lock type: " + lockType);
7443                 break;
7444         }
7445     }
7446 
7447     /** Increments metrics counting number of addOrUpdateNetwork calls. **/
7448     public void incrementNumAddOrUpdateNetworkCalls() {
7449         synchronized (mLock) {
7450             mWifiLogProto.numAddOrUpdateNetworkCalls++;
7451         }
7452     }
7453 
7454     /** Increments metrics counting number of enableNetwork calls. **/
7455     public void incrementNumEnableNetworkCalls() {
7456         synchronized (mLock) {
7457             mWifiLogProto.numEnableNetworkCalls++;
7458         }
7459     }
7460 
7461     /** Add to WifiToggleStats **/
7462     public void incrementNumWifiToggles(boolean isPrivileged, boolean enable) {
7463         synchronized (mLock) {
7464             if (isPrivileged && enable) {
7465                 mWifiToggleStats.numToggleOnPrivileged++;
7466             } else if (isPrivileged && !enable) {
7467                 mWifiToggleStats.numToggleOffPrivileged++;
7468             } else if (!isPrivileged && enable) {
7469                 mWifiToggleStats.numToggleOnNormal++;
7470             } else {
7471                 mWifiToggleStats.numToggleOffNormal++;
7472             }
7473         }
7474     }
7475 
7476     /**
7477      * Increment number of passpoint provision failure
7478      * @param failureCode indicates error condition
7479      */
7480     public void incrementPasspointProvisionFailure(@OsuFailure int failureCode) {
7481         int provisionFailureCode;
7482         synchronized (mLock) {
7483             switch (failureCode) {
7484                 case ProvisioningCallback.OSU_FAILURE_AP_CONNECTION:
7485                     provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_AP_CONNECTION;
7486                     break;
7487                 case ProvisioningCallback.OSU_FAILURE_SERVER_URL_INVALID:
7488                     provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_SERVER_URL_INVALID;
7489                     break;
7490                 case ProvisioningCallback.OSU_FAILURE_SERVER_CONNECTION:
7491                     provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_SERVER_CONNECTION;
7492                     break;
7493                 case ProvisioningCallback.OSU_FAILURE_SERVER_VALIDATION:
7494                     provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_SERVER_VALIDATION;
7495                     break;
7496                 case ProvisioningCallback.OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION:
7497                     provisionFailureCode = PasspointProvisionStats
7498                             .OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION;
7499                     break;
7500                 case ProvisioningCallback.OSU_FAILURE_PROVISIONING_ABORTED:
7501                     provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_PROVISIONING_ABORTED;
7502                     break;
7503                 case ProvisioningCallback.OSU_FAILURE_PROVISIONING_NOT_AVAILABLE:
7504                     provisionFailureCode = PasspointProvisionStats
7505                             .OSU_FAILURE_PROVISIONING_NOT_AVAILABLE;
7506                     break;
7507                 case ProvisioningCallback.OSU_FAILURE_INVALID_URL_FORMAT_FOR_OSU:
7508                     provisionFailureCode = PasspointProvisionStats
7509                             .OSU_FAILURE_INVALID_URL_FORMAT_FOR_OSU;
7510                     break;
7511                 case ProvisioningCallback.OSU_FAILURE_UNEXPECTED_COMMAND_TYPE:
7512                     provisionFailureCode = PasspointProvisionStats
7513                             .OSU_FAILURE_UNEXPECTED_COMMAND_TYPE;
7514                     break;
7515                 case ProvisioningCallback.OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE:
7516                     provisionFailureCode = PasspointProvisionStats
7517                             .OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE;
7518                     break;
7519                 case ProvisioningCallback.OSU_FAILURE_SOAP_MESSAGE_EXCHANGE:
7520                     provisionFailureCode = PasspointProvisionStats
7521                             .OSU_FAILURE_SOAP_MESSAGE_EXCHANGE;
7522                     break;
7523                 case ProvisioningCallback.OSU_FAILURE_START_REDIRECT_LISTENER:
7524                     provisionFailureCode = PasspointProvisionStats
7525                             .OSU_FAILURE_START_REDIRECT_LISTENER;
7526                     break;
7527                 case ProvisioningCallback.OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER:
7528                     provisionFailureCode = PasspointProvisionStats
7529                             .OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER;
7530                     break;
7531                 case ProvisioningCallback.OSU_FAILURE_NO_OSU_ACTIVITY_FOUND:
7532                     provisionFailureCode = PasspointProvisionStats
7533                             .OSU_FAILURE_NO_OSU_ACTIVITY_FOUND;
7534                     break;
7535                 case ProvisioningCallback.OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS:
7536                     provisionFailureCode = PasspointProvisionStats
7537                             .OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS;
7538                     break;
7539                 case ProvisioningCallback.OSU_FAILURE_NO_PPS_MO:
7540                     provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_NO_PPS_MO;
7541                     break;
7542                 case ProvisioningCallback.OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE:
7543                     provisionFailureCode = PasspointProvisionStats
7544                             .OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE;
7545                     break;
7546                 case ProvisioningCallback.OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE:
7547                     provisionFailureCode = PasspointProvisionStats
7548                             .OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE;
7549                     break;
7550                 case ProvisioningCallback.OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE:
7551                     provisionFailureCode = PasspointProvisionStats
7552                             .OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE;
7553                     break;
7554                 case ProvisioningCallback.OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES:
7555                     provisionFailureCode = PasspointProvisionStats
7556                             .OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES;
7557                     break;
7558                 case ProvisioningCallback.OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE:
7559                     provisionFailureCode = PasspointProvisionStats
7560                             .OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE;
7561                     break;
7562                 case ProvisioningCallback.OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION:
7563                     provisionFailureCode = PasspointProvisionStats
7564                             .OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION;
7565                     break;
7566                 case ProvisioningCallback.OSU_FAILURE_OSU_PROVIDER_NOT_FOUND:
7567                     provisionFailureCode = PasspointProvisionStats
7568                             .OSU_FAILURE_OSU_PROVIDER_NOT_FOUND;
7569                     break;
7570                 default:
7571                     provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_UNKNOWN;
7572             }
7573             mPasspointProvisionFailureCounts.increment(provisionFailureCode);
7574         }
7575     }
7576 
7577     /**
7578      * Add to the histogram of number of BSSIDs filtered out from network selection.
7579      */
7580     public void incrementNetworkSelectionFilteredBssidCount(int numBssid) {
7581         mBssidBlocklistStats.networkSelectionFilteredBssidCount.increment(numBssid);
7582     }
7583 
7584     /**
7585      * Increment the number of network connections skipped due to the high movement feature.
7586      */
7587     public void incrementNumHighMovementConnectionSkipped() {
7588         mBssidBlocklistStats.numHighMovementConnectionSkipped++;
7589     }
7590 
7591     /**
7592      * Increment the number of network connections initiated while under the high movement
7593      * feature.
7594      */
7595     public void incrementNumHighMovementConnectionStarted() {
7596         mBssidBlocklistStats.numHighMovementConnectionStarted++;
7597     }
7598 
7599     /**
7600      * Increment the number of times BSSIDs are blocked per reason.
7601      * @param blockReason one of {@link WifiBlocklistMonitor.FailureReason}
7602      */
7603     public void incrementBssidBlocklistCount(int blockReason) {
7604         mBssidBlocklistStats.incrementBssidBlocklistCount(blockReason);
7605     }
7606 
7607     /**
7608      * Increment the number of times WifiConfigurations are blocked per reason.
7609      * @param blockReason one of {@Link NetworkSelectionStatus.NetworkSelectionDisableReason}
7610      */
7611     public void incrementWificonfigurationBlocklistCount(int blockReason) {
7612         mBssidBlocklistStats.incrementWificonfigurationBlocklistCount(blockReason);
7613     }
7614 
7615     /**
7616      * Increment number of passpoint provision success
7617      */
7618     public void incrementPasspointProvisionSuccess() {
7619         synchronized (mLock) {
7620             mNumProvisionSuccess++;
7621         }
7622     }
7623 
7624     /**
7625      * Increment number of IP renewal failures.
7626      */
7627     public void incrementIpRenewalFailure() {
7628         synchronized (mLock) {
7629             mWifiLogProto.numIpRenewalFailure++;
7630         }
7631     }
7632 
7633     /**
7634      * Sets the duration for evaluating Wifi condition to trigger a data stall
7635      */
7636     public void setDataStallDurationMs(int duration) {
7637         synchronized (mLock) {
7638             mExperimentValues.dataStallDurationMs = duration;
7639         }
7640     }
7641 
7642     /**
7643      * Sets the threshold of Tx throughput below which to trigger a data stall
7644      */
7645     public void setDataStallTxTputThrKbps(int txTputThr) {
7646         synchronized (mLock) {
7647             mExperimentValues.dataStallTxTputThrKbps = txTputThr;
7648         }
7649     }
7650 
7651     /**
7652      * Sets the threshold of Rx throughput below which to trigger a data stall
7653      */
7654     public void setDataStallRxTputThrKbps(int rxTputThr) {
7655         synchronized (mLock) {
7656             mExperimentValues.dataStallRxTputThrKbps = rxTputThr;
7657         }
7658     }
7659 
7660     /**
7661      * Sets the threshold of Tx packet error rate above which to trigger a data stall
7662      */
7663     public void setDataStallTxPerThr(int txPerThr) {
7664         synchronized (mLock) {
7665             mExperimentValues.dataStallTxPerThr = txPerThr;
7666         }
7667     }
7668 
7669     /**
7670      * Sets the threshold of CCA level above which to trigger a data stall
7671      */
7672     public void setDataStallCcaLevelThr(int ccaLevel) {
7673         synchronized (mLock) {
7674             mExperimentValues.dataStallCcaLevelThr = ccaLevel;
7675         }
7676     }
7677 
7678     /**
7679      * Sets health monitor RSSI poll valid time in ms
7680      */
7681     public void setHealthMonitorRssiPollValidTimeMs(int rssiPollValidTimeMs) {
7682         synchronized (mLock) {
7683             mExperimentValues.healthMonitorRssiPollValidTimeMs = rssiPollValidTimeMs;
7684         }
7685     }
7686 
7687     /**
7688      * Increment connection duration while link layer stats report are on
7689      */
7690     public void incrementConnectionDuration(int timeDeltaLastTwoPollsMs,
7691             boolean isThroughputSufficient, boolean isCellularDataAvailable) {
7692         synchronized (mLock) {
7693             mConnectionDurationStats.incrementDurationCount(timeDeltaLastTwoPollsMs,
7694                     isThroughputSufficient, isCellularDataAvailable, mWifiWins);
7695 
7696             int band = KnownBandsChannelHelper.getBand(mLastPollFreq);
7697             WifiStatsLog.write(WifiStatsLog.WIFI_HEALTH_STAT_REPORTED, timeDeltaLastTwoPollsMs,
7698                     isThroughputSufficient || !mWifiWins,  isCellularDataAvailable, band);
7699         }
7700     }
7701 
7702     /**
7703      * Sets the status to indicate whether external WiFi connected network scorer is present or not.
7704      */
7705     public void setIsExternalWifiScorerOn(boolean value) {
7706         synchronized (mLock) {
7707             mWifiLogProto.isExternalWifiScorerOn = value;
7708         }
7709     }
7710 
7711     /**
7712      * Note Wi-Fi off metrics
7713      */
7714     public void noteWifiOff(boolean isDeferred, boolean isTimeout, int duration) {
7715         synchronized (mLock) {
7716             mWifiOffMetrics.numWifiOff++;
7717             if (isDeferred) {
7718                 mWifiOffMetrics.numWifiOffDeferring++;
7719                 if (isTimeout) {
7720                     mWifiOffMetrics.numWifiOffDeferringTimeout++;
7721                 }
7722                 mWifiOffMetrics.wifiOffDeferringTimeHistogram.increment(duration);
7723             }
7724         }
7725     }
7726 
7727     /**
7728      * Increment number of BSSIDs filtered out from network selection due to MBO Association
7729      * disallowed indication.
7730      */
7731     public void incrementNetworkSelectionFilteredBssidCountDueToMboAssocDisallowInd() {
7732         synchronized (mLock) {
7733             mWifiLogProto.numBssidFilteredDueToMboAssocDisallowInd++;
7734         }
7735     }
7736 
7737     /**
7738      * Increment number of times BSS transition management request frame is received from the AP.
7739      */
7740     public void incrementSteeringRequestCount() {
7741         synchronized (mLock) {
7742             mWifiLogProto.numSteeringRequest++;
7743         }
7744     }
7745 
7746     /**
7747      * Increment number of times force scan is triggered due to a
7748      * BSS transition management request frame from AP.
7749      */
7750     public void incrementForceScanCountDueToSteeringRequest() {
7751         synchronized (mLock) {
7752             mWifiLogProto.numForceScanDueToSteeringRequest++;
7753         }
7754     }
7755 
7756     /**
7757      * Increment number of times STA received cellular switch
7758      * request from MBO supported AP.
7759      */
7760     public void incrementMboCellularSwitchRequestCount() {
7761         synchronized (mLock) {
7762             mWifiLogProto.numMboCellularSwitchRequest++;
7763         }
7764     }
7765 
7766     /**
7767      * Increment number of times STA received steering request
7768      * including MBO association retry delay.
7769      */
7770     public void incrementSteeringRequestCountIncludingMboAssocRetryDelay() {
7771         synchronized (mLock) {
7772             mWifiLogProto.numSteeringRequestIncludingMboAssocRetryDelay++;
7773         }
7774     }
7775 
7776     /**
7777      * Increment number of connect request to AP adding FILS AKM.
7778      */
7779     public void incrementConnectRequestWithFilsAkmCount() {
7780         synchronized (mLock) {
7781             mWifiLogProto.numConnectRequestWithFilsAkm++;
7782         }
7783     }
7784 
7785     /**
7786      * Increment number of times STA connected through FILS
7787      * authentication.
7788      */
7789     public void incrementL2ConnectionThroughFilsAuthCount() {
7790         synchronized (mLock) {
7791             mWifiLogProto.numL2ConnectionThroughFilsAuthentication++;
7792         }
7793     }
7794 
7795     /**
7796      * Note SoftapConfig Reset Metrics
7797      */
7798     public void noteSoftApConfigReset(SoftApConfiguration originalConfig,
7799             SoftApConfiguration newConfig) {
7800         synchronized (mLock) {
7801             if (originalConfig.getSecurityType() != newConfig.getSecurityType()) {
7802                 mSoftApConfigLimitationMetrics.numSecurityTypeResetToDefault++;
7803             }
7804             if (originalConfig.getMaxNumberOfClients() != newConfig.getMaxNumberOfClients()) {
7805                 mSoftApConfigLimitationMetrics.numMaxClientSettingResetToDefault++;
7806             }
7807             if (originalConfig.isClientControlByUserEnabled()
7808                     != newConfig.isClientControlByUserEnabled()) {
7809                 mSoftApConfigLimitationMetrics.numClientControlByUserResetToDefault++;
7810             }
7811         }
7812     }
7813 
7814     /**
7815      * Note Softap client blocked due to max client limitation
7816      */
7817     public void noteSoftApClientBlocked(int maxClient) {
7818         mSoftApConfigLimitationMetrics.maxClientSettingWhenReachHistogram.increment(maxClient);
7819     }
7820 
7821     /**
7822      * Increment number of connection with different BSSID between framework and firmware selection.
7823      */
7824     public void incrementNumBssidDifferentSelectionBetweenFrameworkAndFirmware() {
7825         synchronized (mLock) {
7826             mWifiLogProto.numBssidDifferentSelectionBetweenFrameworkAndFirmware++;
7827         }
7828     }
7829 
7830     /**
7831      * Note the carrier wifi network connected successfully.
7832      */
7833     public void incrementNumOfCarrierWifiConnectionSuccess() {
7834         synchronized (mLock) {
7835             mCarrierWifiMetrics.numConnectionSuccess++;
7836         }
7837     }
7838 
7839     /**
7840      * Note the carrier wifi network connection authentication failure.
7841      */
7842     public void incrementNumOfCarrierWifiConnectionAuthFailure() {
7843         synchronized (mLock) {
7844             mCarrierWifiMetrics.numConnectionAuthFailure++;
7845         }
7846     }
7847 
7848     /**
7849      * Note the carrier wifi network connection non-authentication failure.
7850      */
7851     public void incrementNumOfCarrierWifiConnectionNonAuthFailure() {
7852         synchronized (mLock) {
7853             mCarrierWifiMetrics.numConnectionNonAuthFailure++;
7854         }
7855     }
7856 
7857     /**
7858      *  Set Adaptive Connectivity state (On/Off)
7859      */
7860     public void setAdaptiveConnectivityState(boolean adaptiveConnectivityEnabled) {
7861         synchronized (mLock) {
7862             mAdaptiveConnectivityEnabled = adaptiveConnectivityEnabled;
7863         }
7864     }
7865 
7866     /**
7867      * Get total beacon receive count
7868      */
7869     public long getTotalBeaconRxCount() {
7870         if (mWifiUsabilityStatsEntriesList.isEmpty()) {
7871             return -1;
7872         } else {
7873             return mWifiUsabilityStatsEntriesList.getLast().totalBeaconRx;
7874         }
7875     }
7876 
7877     /** Note whether Wifi was enabled at boot time. */
7878     public void noteWifiEnabledDuringBoot(boolean isWifiEnabled) {
7879         synchronized (mLock) {
7880             if (mIsFirstConnectionAttemptComplete
7881                     || mFirstConnectAfterBootStats == null
7882                     || mFirstConnectAfterBootStats.wifiEnabledAtBoot != null) {
7883                 return;
7884             }
7885             Attempt wifiEnabledAtBoot = new Attempt();
7886             wifiEnabledAtBoot.isSuccess = isWifiEnabled;
7887             wifiEnabledAtBoot.timestampSinceBootMillis = mClock.getElapsedSinceBootMillis();
7888             mFirstConnectAfterBootStats.wifiEnabledAtBoot = wifiEnabledAtBoot;
7889             if (!isWifiEnabled) {
7890                 mIsFirstConnectionAttemptComplete = true;
7891             }
7892         }
7893     }
7894 
7895     /** Note the first network selection after boot. */
7896     public void noteFirstNetworkSelectionAfterBoot(boolean wasAnyCandidatesFound) {
7897         synchronized (mLock) {
7898             if (mIsFirstConnectionAttemptComplete
7899                     || mFirstConnectAfterBootStats == null
7900                     || mFirstConnectAfterBootStats.firstNetworkSelection != null) {
7901                 return;
7902             }
7903             Attempt firstNetworkSelection = new Attempt();
7904             firstNetworkSelection.isSuccess = wasAnyCandidatesFound;
7905             firstNetworkSelection.timestampSinceBootMillis = mClock.getElapsedSinceBootMillis();
7906             mFirstConnectAfterBootStats.firstNetworkSelection = firstNetworkSelection;
7907             if (!wasAnyCandidatesFound) {
7908                 mIsFirstConnectionAttemptComplete = true;
7909             }
7910         }
7911     }
7912 
7913     /** Note the first L2 connection after boot. */
7914     public void noteFirstL2ConnectionAfterBoot(boolean wasConnectionSuccessful) {
7915         synchronized (mLock) {
7916             if (mIsFirstConnectionAttemptComplete
7917                     || mFirstConnectAfterBootStats == null
7918                     || mFirstConnectAfterBootStats.firstL2Connection != null) {
7919                 return;
7920             }
7921             Attempt firstL2Connection = new Attempt();
7922             firstL2Connection.isSuccess = wasConnectionSuccessful;
7923             firstL2Connection.timestampSinceBootMillis = mClock.getElapsedSinceBootMillis();
7924             mFirstConnectAfterBootStats.firstL2Connection = firstL2Connection;
7925             if (!wasConnectionSuccessful) {
7926                 mIsFirstConnectionAttemptComplete = true;
7927             }
7928         }
7929     }
7930 
7931     /** Note the first L3 connection after boot. */
7932     public void noteFirstL3ConnectionAfterBoot(boolean wasConnectionSuccessful) {
7933         synchronized (mLock) {
7934             if (mIsFirstConnectionAttemptComplete
7935                     || mFirstConnectAfterBootStats == null
7936                     || mFirstConnectAfterBootStats.firstL3Connection != null) {
7937                 return;
7938             }
7939             Attempt firstL3Connection = new Attempt();
7940             firstL3Connection.isSuccess = wasConnectionSuccessful;
7941             firstL3Connection.timestampSinceBootMillis = mClock.getElapsedSinceBootMillis();
7942             mFirstConnectAfterBootStats.firstL3Connection = firstL3Connection;
7943             if (!wasConnectionSuccessful) {
7944                 mIsFirstConnectionAttemptComplete = true;
7945             }
7946         }
7947     }
7948 
7949     private static String attemptToString(@Nullable Attempt attempt) {
7950         if (attempt == null) return "Attempt=null";
7951         return "Attempt{"
7952                 + "timestampSinceBootMillis=" + attempt.timestampSinceBootMillis
7953                 + ",isSuccess=" + attempt.isSuccess
7954                 + "}";
7955     }
7956 
7957     private static String firstConnectAfterBootStatsToString(
7958             @Nullable FirstConnectAfterBootStats stats) {
7959         if (stats == null) return "FirstConnectAfterBootStats=null";
7960         return "FirstConnectAfterBootStats{"
7961                 + "wifiEnabledAtBoot=" + attemptToString(stats.wifiEnabledAtBoot)
7962                 + ",firstNetworkSelection" + attemptToString(stats.firstNetworkSelection)
7963                 + ",firstL2Connection" + attemptToString(stats.firstL2Connection)
7964                 + ",firstL3Connection" + attemptToString(stats.firstL3Connection)
7965                 + "}";
7966     }
7967 
7968     public ScanMetrics getScanMetrics() {
7969         return mScanMetrics;
7970     }
7971 
7972     public enum ScanType { SINGLE, BACKGROUND }
7973 
7974     public enum PnoScanState { STARTED, FAILED_TO_START, COMPLETED_NETWORK_FOUND, FAILED }
7975 
7976     /**
7977      * This class reports Scan metrics to statsd and holds intermediate scan request state.
7978      */
7979     public static class ScanMetrics {
7980         private static final String TAG_SCANS = "ScanMetrics";
7981         private static final String GMS_PACKAGE = "com.google.android.gms";
7982 
7983         // Scan types.
7984         public static final int SCAN_TYPE_SINGLE = 0;
7985         public static final int SCAN_TYPE_BACKGROUND = 1;
7986         public static final int SCAN_TYPE_MAX_VALUE = SCAN_TYPE_BACKGROUND;
7987         @IntDef(prefix = { "SCAN_TYPE_" }, value = {
7988                 SCAN_TYPE_SINGLE,
7989                 SCAN_TYPE_BACKGROUND,
7990         })
7991         public @interface ScanType {}
7992 
7993         // PNO scan states.
7994         public static final int PNO_SCAN_STATE_STARTED = 1;
7995         public static final int PNO_SCAN_STATE_FAILED_TO_START = 2;
7996         public static final int PNO_SCAN_STATE_COMPLETED_NETWORK_FOUND = 3;
7997         public static final int PNO_SCAN_STATE_FAILED = 4;
7998         @IntDef(prefix = { "PNO_SCAN_STATE_" }, value = {
7999                 PNO_SCAN_STATE_STARTED,
8000                 PNO_SCAN_STATE_FAILED_TO_START,
8001                 PNO_SCAN_STATE_COMPLETED_NETWORK_FOUND,
8002                 PNO_SCAN_STATE_FAILED
8003         })
8004         public @interface PnoScanState {}
8005 
8006         private final Object mLock = new Object();
8007         private Clock mClock;
8008 
8009         private List<String> mSettingsPackages = new ArrayList<>();
8010         private int mGmsUid = -1;
8011 
8012         // mNextScanState collects metadata about the next scan that's about to happen.
8013         // It is mutated by external callers via setX methods before the call to logScanStarted.
8014         private State mNextScanState = new State();
8015         // mActiveScanState is an immutable copy of mNextScanState during the scan process,
8016         // i.e. between logScanStarted and logScanSucceeded/Failed. Since the state is pushed to
8017         // statsd only when a scan ends, it's important to keep the immutable copy
8018         // for the duration of the scan.
8019         private State[] mActiveScanStates = new State[SCAN_TYPE_MAX_VALUE + 1];
8020 
8021         ScanMetrics(Context context, Clock clock) {
8022             mClock = clock;
8023 
8024             PackageManager pm = context.getPackageManager();
8025             if (pm != null) {
8026                 Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS);
8027                 List<ResolveInfo> packages = pm.queryIntentActivities(settingsIntent, 0);
8028                 for (ResolveInfo res : packages) {
8029                     String packageName = res.activityInfo.packageName;
8030                     Log.d(TAG_SCANS, "Settings package: " + packageName);
8031                     mSettingsPackages.add(packageName);
8032                 }
8033             }
8034 
8035             try {
8036                 mGmsUid = context.getPackageManager().getApplicationInfo(GMS_PACKAGE, 0).uid;
8037                 Log.d(TAG_SCANS, "GMS uid: " + mGmsUid);
8038             } catch (Exception e) {
8039                 Log.e(TAG_SCANS, "Can't get GMS uid");
8040             }
8041         }
8042 
8043         /**
8044          * Set WorkSource for the upcoming scan request.
8045          *
8046          * @param workSource
8047          */
8048         public void setWorkSource(WorkSource workSource) {
8049             synchronized (mLock) {
8050                 if (mNextScanState.mWorkSource == null) {
8051                     mNextScanState.mWorkSource = workSource;
8052                     if (DBG) Log.d(TAG_SCANS, "setWorkSource: workSource = " + workSource);
8053                 }
8054             }
8055         }
8056 
8057         /**
8058          * Set ClientUid for the upcoming scan request.
8059          *
8060          * @param uid
8061          */
8062         public void setClientUid(int uid) {
8063             synchronized (mLock) {
8064                 mNextScanState.mClientUid = uid;
8065 
8066                 if (DBG) Log.d(TAG_SCANS, "setClientUid: uid = " + uid);
8067             }
8068         }
8069 
8070         /**
8071          * Set Importance for the upcoming scan request.
8072          *
8073          * @param packageImportance See {@link ActivityManager.RunningAppProcessInfo.Importance}
8074          */
8075         public void setImportance(int packageImportance) {
8076             synchronized (mLock) {
8077                 mNextScanState.mPackageImportance = packageImportance;
8078 
8079                 if (DBG) {
8080                     Log.d(TAG_SCANS,
8081                             "setRequestFromBackground: packageImportance = " + packageImportance);
8082                 }
8083             }
8084         }
8085 
8086         /**
8087          * Indicate that a scan started.
8088          * @param scanType See {@link ScanMetrics.ScanType}
8089          */
8090         public void logScanStarted(@ScanType int scanType) {
8091             synchronized (mLock) {
8092                 if (DBG) Log.d(TAG_SCANS, "logScanStarted");
8093 
8094                 mNextScanState.mTimeStartMillis = mClock.getElapsedSinceBootMillis();
8095                 mActiveScanStates[scanType] = mNextScanState;
8096                 mNextScanState = new State();
8097             }
8098         }
8099 
8100         /**
8101          * Indicate that a scan failed to start.
8102          * @param scanType See {@link ScanMetrics.ScanType}
8103          */
8104         public void logScanFailedToStart(@ScanType int scanType) {
8105             synchronized (mLock) {
8106                 Log.d(TAG_SCANS, "logScanFailedToStart");
8107 
8108                 mNextScanState.mTimeStartMillis = mClock.getElapsedSinceBootMillis();
8109                 mActiveScanStates[scanType] = mNextScanState;
8110                 mNextScanState = new State();
8111 
8112                 log(scanType, WifiStatsLog.WIFI_SCAN_REPORTED__RESULT__RESULT_FAILED_TO_START, 0);
8113                 mActiveScanStates[scanType] = null;
8114             }
8115         }
8116 
8117         /**
8118          * Indicate that a scan finished successfully.
8119          * @param scanType See {@link ScanMetrics.ScanType}
8120          * @param countOfNetworksFound How many networks were found.
8121          */
8122         public void logScanSucceeded(@ScanType int scanType, int countOfNetworksFound) {
8123             synchronized (mLock) {
8124                 if (DBG) Log.d(TAG_SCANS, "logScanSucceeded: found = " + countOfNetworksFound);
8125 
8126                 log(scanType, WifiStatsLog.WIFI_SCAN_REPORTED__RESULT__RESULT_SUCCESS,
8127                         countOfNetworksFound);
8128                 mActiveScanStates[scanType] = null;
8129             }
8130         }
8131 
8132         /**
8133          * Log a PNO scan event: start/finish/fail.
8134          * @param pnoScanState See {@link PnoScanState}
8135          */
8136         public void logPnoScanEvent(@PnoScanState int pnoScanState) {
8137             synchronized (mLock) {
8138                 int state = 0;
8139 
8140                 switch (pnoScanState) {
8141                     case PNO_SCAN_STATE_STARTED:
8142                         state = WifiStatsLog.WIFI_PNO_SCAN_REPORTED__STATE__STARTED;
8143                         break;
8144                     case PNO_SCAN_STATE_FAILED_TO_START:
8145                         state = WifiStatsLog.WIFI_PNO_SCAN_REPORTED__STATE__FAILED_TO_START;
8146                         break;
8147                     case PNO_SCAN_STATE_COMPLETED_NETWORK_FOUND:
8148                         state = WifiStatsLog.WIFI_PNO_SCAN_REPORTED__STATE__FINISHED_NETWORKS_FOUND;
8149                         break;
8150                     case PNO_SCAN_STATE_FAILED:
8151                         state = WifiStatsLog.WIFI_PNO_SCAN_REPORTED__STATE__FAILED;
8152                         break;
8153                 }
8154 
8155                 WifiStatsLog.write(WifiStatsLog.WIFI_PNO_SCAN_REPORTED, state);
8156 
8157                 if (DBG) Log.d(TAG_SCANS, "logPnoScanEvent: pnoScanState = " + pnoScanState);
8158             }
8159         }
8160 
8161         /**
8162          * Indicate that a scan failed.
8163          */
8164         public void logScanFailed(@ScanType int scanType) {
8165             synchronized (mLock) {
8166                 if (DBG) Log.d(TAG_SCANS, "logScanFailed");
8167 
8168                 log(scanType, WifiStatsLog.WIFI_SCAN_REPORTED__RESULT__RESULT_FAILED_TO_SCAN, 0);
8169                 mActiveScanStates[scanType] = null;
8170             }
8171         }
8172 
8173         private void log(@ScanType int scanType, int result, int countNetworks) {
8174             State state = mActiveScanStates[scanType];
8175 
8176             if (state == null) {
8177                 if (DBG) Log.e(TAG_SCANS, "Wifi scan result log called with no prior start calls!");
8178                 return;
8179             }
8180 
8181             int type = WifiStatsLog.WIFI_SCAN_REPORTED__TYPE__TYPE_UNKNOWN;
8182             if (scanType == SCAN_TYPE_SINGLE) {
8183                 type = WifiStatsLog.WIFI_SCAN_REPORTED__TYPE__TYPE_SINGLE;
8184             } else if (scanType == SCAN_TYPE_BACKGROUND) {
8185                 type = WifiStatsLog.WIFI_SCAN_REPORTED__TYPE__TYPE_BACKGROUND;
8186             }
8187 
8188             long duration = mClock.getElapsedSinceBootMillis() - state.mTimeStartMillis;
8189 
8190             int source = WifiStatsLog.WIFI_SCAN_REPORTED__SOURCE__SOURCE_NO_WORK_SOURCE;
8191             if (state.mClientUid != -1 && state.mClientUid == mGmsUid) {
8192                 source = WifiStatsLog.WIFI_SCAN_REPORTED__SOURCE__SOURCE_GMS;
8193             } else if (state.mWorkSource != null) {
8194                 if (state.mWorkSource.equals(ClientModeImpl.WIFI_WORK_SOURCE)) {
8195                     source = WifiStatsLog.WIFI_SCAN_REPORTED__SOURCE__SOURCE_WIFI_STACK;
8196                 } else {
8197                     source = WifiStatsLog.WIFI_SCAN_REPORTED__SOURCE__SOURCE_OTHER_APP;
8198 
8199                     for (int i = 0; i < state.mWorkSource.size(); i++) {
8200                         if (mSettingsPackages.contains(
8201                                 state.mWorkSource.getPackageName(i))) {
8202                             source = WifiStatsLog.WIFI_SCAN_REPORTED__SOURCE__SOURCE_SETTINGS_APP;
8203                             break;
8204                         }
8205                     }
8206                 }
8207             }
8208 
8209             int importance = WifiStatsLog.WIFI_SCAN_REPORTED__IMPORTANCE__IMPORTANCE_UNKNOWN;
8210             if (state.mPackageImportance != -1) {
8211                 if (state.mPackageImportance
8212                         <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
8213                     importance = WifiStatsLog.WIFI_SCAN_REPORTED__IMPORTANCE__IMPORTANCE_FOREGROUND;
8214                 } else if (state.mPackageImportance
8215                         <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE) {
8216                     importance =
8217                             WifiStatsLog.WIFI_SCAN_REPORTED__IMPORTANCE__IMPORTANCE_FOREGROUND_SERVICE;
8218                 } else {
8219                     importance = WifiStatsLog.WIFI_SCAN_REPORTED__IMPORTANCE__IMPORTANCE_BACKGROUND;
8220                 }
8221             }
8222 
8223             WifiStatsLog.write(WifiStatsLog.WIFI_SCAN_REPORTED,
8224                     type,
8225                     result,
8226                     source,
8227                     importance,
8228                     (int) duration,
8229                     countNetworks);
8230 
8231             if (DBG) {
8232                 Log.d(TAG_SCANS,
8233                         "WifiScanReported: type = " + type
8234                                 + ", result = " + result
8235                                 + ", source = " + source
8236                                 + ", importance = " + importance
8237                                 + ", networks = " + countNetworks);
8238             }
8239         }
8240 
8241         static class State {
8242             WorkSource mWorkSource = null;
8243             int mClientUid = -1;
8244             // see @ActivityManager.RunningAppProcessInfo.Importance
8245             int mPackageImportance = -1;
8246 
8247             long mTimeStartMillis;
8248         }
8249     }
8250 
8251     /** Set whether Make Before Break is supported by the hardware and enabled. */
8252     public void setIsMakeBeforeBreakSupported(boolean supported) {
8253         synchronized (mLock) {
8254             mWifiToWifiSwitchStats.isMakeBeforeBreakSupported = supported;
8255         }
8256     }
8257 
8258     /**
8259      * Increment the number of times Wifi to Wifi switch was triggered. This includes Make Before
8260      * Break and Break Before Make.
8261      */
8262     public void incrementWifiToWifiSwitchTriggerCount() {
8263         synchronized (mLock) {
8264             mWifiToWifiSwitchStats.wifiToWifiSwitchTriggerCount++;
8265         }
8266     }
8267 
8268     /**
8269      * Increment the Number of times Wifi to Wifi switch was triggered using Make Before Break
8270      * (MBB). Note that MBB may not always be used for various reasons e.g. no additional iface
8271      * available due to ongoing SoftAP, both old and new network have MAC randomization disabled,
8272      * etc.
8273      */
8274     public void incrementMakeBeforeBreakTriggerCount() {
8275         synchronized (mLock) {
8276             mWifiToWifiSwitchStats.makeBeforeBreakTriggerCount++;
8277         }
8278     }
8279 
8280     /**
8281      * Increment the number of times Make Before Break was aborted due to the new network not having
8282      * internet.
8283      */
8284     public void incrementMakeBeforeBreakNoInternetCount() {
8285         synchronized (mLock) {
8286             mWifiToWifiSwitchStats.makeBeforeBreakNoInternetCount++;
8287         }
8288     }
8289 
8290     /**
8291      * Increment the number of times where, for some reason, Make Before Break resulted in the
8292      * loss of the primary ClientModeManager, and we needed to recover by making one of the
8293      * SECONDARY_TRANSIENT ClientModeManagers primary.
8294      */
8295     public void incrementMakeBeforeBreakRecoverPrimaryCount() {
8296         synchronized (mLock) {
8297             mWifiToWifiSwitchStats.makeBeforeBreakRecoverPrimaryCount++;
8298         }
8299     }
8300 
8301     /**
8302      * Increment the number of times the new network in Make Before Break had its internet
8303      * connection validated.
8304      */
8305     public void incrementMakeBeforeBreakInternetValidatedCount() {
8306         synchronized (mLock) {
8307             mWifiToWifiSwitchStats.makeBeforeBreakInternetValidatedCount++;
8308         }
8309     }
8310 
8311     /**
8312      * Increment the number of times the old network in Make Before Break was successfully
8313      * transitioned from PRIMARY to SECONDARY_TRANSIENT role.
8314      */
8315     public void incrementMakeBeforeBreakSuccessCount() {
8316         synchronized (mLock) {
8317             mWifiToWifiSwitchStats.makeBeforeBreakSuccessCount++;
8318         }
8319     }
8320 
8321     /**
8322      * Increment the number of times the old network in Make Before Break completed lingering and
8323      * was disconnected.
8324      * @param duration the lingering duration in ms
8325      */
8326     public void incrementMakeBeforeBreakLingerCompletedCount(long duration) {
8327         synchronized (mLock) {
8328             mWifiToWifiSwitchStats.makeBeforeBreakLingerCompletedCount++;
8329             int lingeringDurationSeconds = Math.min(MBB_LINGERING_DURATION_MAX_SECONDS,
8330                     (int) duration / 1000);
8331             mMakeBeforeBreakLingeringDurationSeconds.increment(lingeringDurationSeconds);
8332         }
8333     }
8334 
8335     private String wifiToWifiSwitchStatsToString(WifiToWifiSwitchStats stats) {
8336         return "WifiToWifiSwitchStats{"
8337                 + "isMakeBeforeBreakSupported=" + stats.isMakeBeforeBreakSupported
8338                 + ",wifiToWifiSwitchTriggerCount=" + stats.wifiToWifiSwitchTriggerCount
8339                 + ",makeBeforeBreakTriggerCount=" + stats.makeBeforeBreakTriggerCount
8340                 + ",makeBeforeBreakNoInternetCount=" + stats.makeBeforeBreakNoInternetCount
8341                 + ",makeBeforeBreakRecoverPrimaryCount=" + stats.makeBeforeBreakRecoverPrimaryCount
8342                 + ",makeBeforeBreakInternetValidatedCount="
8343                 + stats.makeBeforeBreakInternetValidatedCount
8344                 + ",makeBeforeBreakSuccessCount=" + stats.makeBeforeBreakSuccessCount
8345                 + ",makeBeforeBreakLingerCompletedCount="
8346                 + stats.makeBeforeBreakLingerCompletedCount
8347                 + ",makeBeforeBreakLingeringDurationSeconds="
8348                 + mMakeBeforeBreakLingeringDurationSeconds
8349                 + "}";
8350     }
8351 
8352     /**
8353      * Increment number of number of Passpoint connections with a venue URL
8354      */
8355     public void incrementTotalNumberOfPasspointConnectionsWithVenueUrl() {
8356         synchronized (mLock) {
8357             mWifiLogProto.totalNumberOfPasspointConnectionsWithVenueUrl++;
8358         }
8359     }
8360 
8361     /**
8362      * Increment number of number of Passpoint connections with a T&C URL
8363      */
8364     public void incrementTotalNumberOfPasspointConnectionsWithTermsAndConditionsUrl() {
8365         synchronized (mLock) {
8366             mWifiLogProto.totalNumberOfPasspointConnectionsWithTermsAndConditionsUrl++;
8367         }
8368     }
8369 
8370     /**
8371      * Increment number of successful acceptance of Passpoint T&C
8372      */
8373     public void incrementTotalNumberOfPasspointAcceptanceOfTermsAndConditions() {
8374         synchronized (mLock) {
8375             mWifiLogProto.totalNumberOfPasspointAcceptanceOfTermsAndConditions++;
8376         }
8377     }
8378 
8379     /**
8380      * Increment number of Passpoint profiles with decorated identity prefix
8381      */
8382     public void incrementTotalNumberOfPasspointProfilesWithDecoratedIdentity() {
8383         synchronized (mLock) {
8384             mWifiLogProto.totalNumberOfPasspointProfilesWithDecoratedIdentity++;
8385         }
8386     }
8387 
8388     /**
8389      * Increment number of Passpoint Deauth-Imminent notification scope
8390      */
8391     public void incrementPasspointDeauthImminentScope(boolean isEss) {
8392         synchronized (mLock) {
8393             mPasspointDeauthImminentScope.increment(isEss ? PASSPOINT_DEAUTH_IMMINENT_SCOPE_ESS
8394                     : PASSPOINT_DEAUTH_IMMINENT_SCOPE_BSS);
8395         }
8396     }
8397 
8398     /**
8399      * Increment number of times connection failure status reported per
8400      * WifiConfiguration.RecentFailureReason
8401      */
8402     public void incrementRecentFailureAssociationStatusCount(
8403             @WifiConfiguration.RecentFailureReason int reason) {
8404         synchronized (mLock) {
8405             mRecentFailureAssociationStatus.increment(reason);
8406         }
8407     }
8408 }
8409