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