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