• 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 android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback;
20 import android.net.NetworkAgent;
21 import android.net.wifi.ScanResult;
22 import android.net.wifi.SupplicantState;
23 import android.net.wifi.WifiConfiguration;
24 import android.net.wifi.WifiInfo;
25 import android.net.wifi.WifiManager;
26 import android.os.Handler;
27 import android.os.Looper;
28 import android.os.Message;
29 import android.util.Base64;
30 import android.util.Log;
31 import android.util.Pair;
32 import android.util.SparseIntArray;
33 
34 import com.android.server.wifi.aware.WifiAwareMetrics;
35 import com.android.server.wifi.hotspot2.NetworkDetail;
36 import com.android.server.wifi.hotspot2.PasspointManager;
37 import com.android.server.wifi.hotspot2.PasspointMatch;
38 import com.android.server.wifi.hotspot2.PasspointProvider;
39 import com.android.server.wifi.nano.WifiMetricsProto;
40 import com.android.server.wifi.nano.WifiMetricsProto.ConnectToNetworkNotificationAndActionCount;
41 import com.android.server.wifi.nano.WifiMetricsProto.PnoScanMetrics;
42 import com.android.server.wifi.nano.WifiMetricsProto.StaEvent;
43 import com.android.server.wifi.nano.WifiMetricsProto.StaEvent.ConfigInfo;
44 import com.android.server.wifi.util.InformationElementUtil;
45 import com.android.server.wifi.util.ScanResultUtil;
46 
47 import java.io.FileDescriptor;
48 import java.io.PrintWriter;
49 import java.util.ArrayList;
50 import java.util.BitSet;
51 import java.util.Calendar;
52 import java.util.HashSet;
53 import java.util.LinkedList;
54 import java.util.List;
55 import java.util.Set;
56 
57 /**
58  * Provides storage for wireless connectivity metrics, as they are generated.
59  * Metrics logged by this class include:
60  *   Aggregated connection stats (num of connections, num of failures, ...)
61  *   Discrete connection event stats (time, duration, failure codes, ...)
62  *   Router details (technology type, authentication type, ...)
63  *   Scan stats
64  */
65 public class WifiMetrics {
66     private static final String TAG = "WifiMetrics";
67     private static final boolean DBG = false;
68     /**
69      * Clamp the RSSI poll counts to values between [MIN,MAX]_RSSI_POLL
70      */
71     private static final int MAX_RSSI_POLL = 0;
72     private static final int MIN_RSSI_POLL = -127;
73     public static final int MAX_RSSI_DELTA = 127;
74     public static final int MIN_RSSI_DELTA = -127;
75     /** Maximum time period between ScanResult and RSSI poll to generate rssi delta datapoint */
76     public static final long TIMEOUT_RSSI_DELTA_MILLIS =  3000;
77     private static final int MIN_WIFI_SCORE = 0;
78     private static final int MAX_WIFI_SCORE = NetworkAgent.WIFI_BASE_SCORE;
79     private final Object mLock = new Object();
80     private static final int MAX_CONNECTION_EVENTS = 256;
81     // Largest bucket in the NumConnectableNetworkCount histogram,
82     // anything large will be stored in this bucket
83     public static final int MAX_CONNECTABLE_SSID_NETWORK_BUCKET = 20;
84     public static final int MAX_CONNECTABLE_BSSID_NETWORK_BUCKET = 50;
85     public static final int MAX_TOTAL_SCAN_RESULT_SSIDS_BUCKET = 100;
86     public static final int MAX_TOTAL_SCAN_RESULTS_BUCKET = 250;
87     private static final int CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER = 1000;
88     private Clock mClock;
89     private boolean mScreenOn;
90     private int mWifiState;
91     private WifiAwareMetrics mWifiAwareMetrics;
92     private final PnoScanMetrics mPnoScanMetrics = new PnoScanMetrics();
93     private Handler mHandler;
94     private WifiConfigManager mWifiConfigManager;
95     private WifiNetworkSelector mWifiNetworkSelector;
96     private PasspointManager mPasspointManager;
97     /**
98      * Metrics are stored within an instance of the WifiLog proto during runtime,
99      * The ConnectionEvent, SystemStateEntries & ScanReturnEntries metrics are stored during
100      * runtime in member lists of this WifiMetrics class, with the final WifiLog proto being pieced
101      * together at dump-time
102      */
103     private final WifiMetricsProto.WifiLog mWifiLogProto = new WifiMetricsProto.WifiLog();
104     /**
105      * Session information that gets logged for every Wifi connection attempt.
106      */
107     private final List<ConnectionEvent> mConnectionEventList = new ArrayList<>();
108     /**
109      * The latest started (but un-ended) connection attempt
110      */
111     private ConnectionEvent mCurrentConnectionEvent;
112     /**
113      * Count of number of times each scan return code, indexed by WifiLog.ScanReturnCode
114      */
115     private final SparseIntArray mScanReturnEntries = new SparseIntArray();
116     /**
117      * Mapping of system state to the counts of scans requested in that wifi state * screenOn
118      * combination. Indexed by WifiLog.WifiState * (1 + screenOn)
119      */
120     private final SparseIntArray mWifiSystemStateEntries = new SparseIntArray();
121     /** Mapping of RSSI values to counts. */
122     private final SparseIntArray mRssiPollCounts = new SparseIntArray();
123     /** Mapping of RSSI scan-poll delta values to counts. */
124     private final SparseIntArray mRssiDeltaCounts = new SparseIntArray();
125     /** RSSI of the scan result for the last connection event*/
126     private int mScanResultRssi = 0;
127     /** Boot-relative timestamp when the last candidate scanresult was received, used to calculate
128         RSSI deltas. -1 designates no candidate scanResult being tracked */
129     private long mScanResultRssiTimestampMillis = -1;
130     /** Mapping of alert reason to the respective alert count. */
131     private final SparseIntArray mWifiAlertReasonCounts = new SparseIntArray();
132     /**
133      * Records the getElapsedSinceBootMillis (in seconds) that represents the beginning of data
134      * capture for for this WifiMetricsProto
135      */
136     private long mRecordStartTimeSec;
137     /** Mapping of Wifi Scores to counts */
138     private final SparseIntArray mWifiScoreCounts = new SparseIntArray();
139     /** Mapping of SoftApManager start SoftAp return codes to counts */
140     private final SparseIntArray mSoftApManagerReturnCodeCounts = new SparseIntArray();
141 
142     private final SparseIntArray mTotalSsidsInScanHistogram = new SparseIntArray();
143     private final SparseIntArray mTotalBssidsInScanHistogram = new SparseIntArray();
144     private final SparseIntArray mAvailableOpenSsidsInScanHistogram = new SparseIntArray();
145     private final SparseIntArray mAvailableOpenBssidsInScanHistogram = new SparseIntArray();
146     private final SparseIntArray mAvailableSavedSsidsInScanHistogram = new SparseIntArray();
147     private final SparseIntArray mAvailableSavedBssidsInScanHistogram = new SparseIntArray();
148     private final SparseIntArray mAvailableOpenOrSavedSsidsInScanHistogram = new SparseIntArray();
149     private final SparseIntArray mAvailableOpenOrSavedBssidsInScanHistogram = new SparseIntArray();
150     private final SparseIntArray mAvailableSavedPasspointProviderProfilesInScanHistogram =
151             new SparseIntArray();
152     private final SparseIntArray mAvailableSavedPasspointProviderBssidsInScanHistogram =
153             new SparseIntArray();
154 
155     /** Mapping of "Connect to Network" notifications to counts. */
156     private final SparseIntArray mConnectToNetworkNotificationCount = new SparseIntArray();
157     /** Mapping of "Connect to Network" notification user actions to counts. */
158     private final SparseIntArray mConnectToNetworkNotificationActionCount = new SparseIntArray();
159     private int mOpenNetworkRecommenderBlacklistSize = 0;
160     private boolean mIsWifiNetworksAvailableNotificationOn = false;
161     private int mNumOpenNetworkConnectMessageFailedToSend = 0;
162     private int mNumOpenNetworkRecommendationUpdates = 0;
163 
164     class RouterFingerPrint {
165         private WifiMetricsProto.RouterFingerPrint mRouterFingerPrintProto;
RouterFingerPrint()166         RouterFingerPrint() {
167             mRouterFingerPrintProto = new WifiMetricsProto.RouterFingerPrint();
168         }
169 
toString()170         public String toString() {
171             StringBuilder sb = new StringBuilder();
172             synchronized (mLock) {
173                 sb.append("mConnectionEvent.roamType=" + mRouterFingerPrintProto.roamType);
174                 sb.append(", mChannelInfo=" + mRouterFingerPrintProto.channelInfo);
175                 sb.append(", mDtim=" + mRouterFingerPrintProto.dtim);
176                 sb.append(", mAuthentication=" + mRouterFingerPrintProto.authentication);
177                 sb.append(", mHidden=" + mRouterFingerPrintProto.hidden);
178                 sb.append(", mRouterTechnology=" + mRouterFingerPrintProto.routerTechnology);
179                 sb.append(", mSupportsIpv6=" + mRouterFingerPrintProto.supportsIpv6);
180             }
181             return sb.toString();
182         }
updateFromWifiConfiguration(WifiConfiguration config)183         public void updateFromWifiConfiguration(WifiConfiguration config) {
184             synchronized (mLock) {
185                 if (config != null) {
186                     // Is this a hidden network
187                     mRouterFingerPrintProto.hidden = config.hiddenSSID;
188                     // Config may not have a valid dtimInterval set yet, in which case dtim will be zero
189                     // (These are only populated from beacon frame scan results, which are returned as
190                     // scan results from the chip far less frequently than Probe-responses)
191                     if (config.dtimInterval > 0) {
192                         mRouterFingerPrintProto.dtim = config.dtimInterval;
193                     }
194                     mCurrentConnectionEvent.mConfigSsid = config.SSID;
195                     // Get AuthType information from config (We do this again from ScanResult after
196                     // associating with BSSID)
197                     if (config.allowedKeyManagement != null
198                             && config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) {
199                         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
200                                 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_OPEN;
201                     } else if (config.isEnterprise()) {
202                         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
203                                 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE;
204                     } else {
205                         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
206                                 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL;
207                     }
208                     mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
209                             .passpoint = config.isPasspoint();
210                     // If there's a ScanResult candidate associated with this config already, get it and
211                     // log (more accurate) metrics from it
212                     ScanResult candidate = config.getNetworkSelectionStatus().getCandidate();
213                     if (candidate != null) {
214                         updateMetricsFromScanResult(candidate);
215                     }
216                 }
217             }
218         }
219     }
220 
221     /**
222      * Log event, tracking the start time, end time and result of a wireless connection attempt.
223      */
224     class ConnectionEvent {
225         WifiMetricsProto.ConnectionEvent mConnectionEvent;
226         //<TODO> Move these constants into a wifi.proto Enum, and create a new Failure Type field
227         //covering more than just l2 failures. see b/27652362
228         /**
229          * Failure codes, used for the 'level_2_failure_code' Connection event field (covers a lot
230          * more failures than just l2 though, since the proto does not have a place to log
231          * framework failures)
232          */
233         // Failure is unknown
234         public static final int FAILURE_UNKNOWN = 0;
235         // NONE
236         public static final int FAILURE_NONE = 1;
237         // ASSOCIATION_REJECTION_EVENT
238         public static final int FAILURE_ASSOCIATION_REJECTION = 2;
239         // AUTHENTICATION_FAILURE_EVENT
240         public static final int FAILURE_AUTHENTICATION_FAILURE = 3;
241         // SSID_TEMP_DISABLED (Also Auth failure)
242         public static final int FAILURE_SSID_TEMP_DISABLED = 4;
243         // reconnect() or reassociate() call to WifiNative failed
244         public static final int FAILURE_CONNECT_NETWORK_FAILED = 5;
245         // NETWORK_DISCONNECTION_EVENT
246         public static final int FAILURE_NETWORK_DISCONNECTION = 6;
247         // NEW_CONNECTION_ATTEMPT before previous finished
248         public static final int FAILURE_NEW_CONNECTION_ATTEMPT = 7;
249         // New connection attempt to the same network & bssid
250         public static final int FAILURE_REDUNDANT_CONNECTION_ATTEMPT = 8;
251         // Roam Watchdog timer triggered (Roaming timed out)
252         public static final int FAILURE_ROAM_TIMEOUT = 9;
253         // DHCP failure
254         public static final int FAILURE_DHCP = 10;
255 
256         RouterFingerPrint mRouterFingerPrint;
257         private long mRealStartTime;
258         private long mRealEndTime;
259         private String mConfigSsid;
260         private String mConfigBssid;
261         private int mWifiState;
262         private boolean mScreenOn;
263 
ConnectionEvent()264         private ConnectionEvent() {
265             mConnectionEvent = new WifiMetricsProto.ConnectionEvent();
266             mRealEndTime = 0;
267             mRealStartTime = 0;
268             mRouterFingerPrint = new RouterFingerPrint();
269             mConnectionEvent.routerFingerprint = mRouterFingerPrint.mRouterFingerPrintProto;
270             mConfigSsid = "<NULL>";
271             mConfigBssid = "<NULL>";
272             mWifiState = WifiMetricsProto.WifiLog.WIFI_UNKNOWN;
273             mScreenOn = false;
274         }
275 
toString()276         public String toString() {
277             StringBuilder sb = new StringBuilder();
278             sb.append("startTime=");
279             Calendar c = Calendar.getInstance();
280             synchronized (mLock) {
281                 c.setTimeInMillis(mConnectionEvent.startTimeMillis);
282                 sb.append(mConnectionEvent.startTimeMillis == 0 ? "            <null>" :
283                         String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
284                 sb.append(", SSID=");
285                 sb.append(mConfigSsid);
286                 sb.append(", BSSID=");
287                 sb.append(mConfigBssid);
288                 sb.append(", durationMillis=");
289                 sb.append(mConnectionEvent.durationTakenToConnectMillis);
290                 sb.append(", roamType=");
291                 switch(mConnectionEvent.roamType) {
292                     case 1:
293                         sb.append("ROAM_NONE");
294                         break;
295                     case 2:
296                         sb.append("ROAM_DBDC");
297                         break;
298                     case 3:
299                         sb.append("ROAM_ENTERPRISE");
300                         break;
301                     case 4:
302                         sb.append("ROAM_USER_SELECTED");
303                         break;
304                     case 5:
305                         sb.append("ROAM_UNRELATED");
306                         break;
307                     default:
308                         sb.append("ROAM_UNKNOWN");
309                 }
310                 sb.append(", connectionResult=");
311                 sb.append(mConnectionEvent.connectionResult);
312                 sb.append(", level2FailureCode=");
313                 switch(mConnectionEvent.level2FailureCode) {
314                     case FAILURE_NONE:
315                         sb.append("NONE");
316                         break;
317                     case FAILURE_ASSOCIATION_REJECTION:
318                         sb.append("ASSOCIATION_REJECTION");
319                         break;
320                     case FAILURE_AUTHENTICATION_FAILURE:
321                         sb.append("AUTHENTICATION_FAILURE");
322                         break;
323                     case FAILURE_SSID_TEMP_DISABLED:
324                         sb.append("SSID_TEMP_DISABLED");
325                         break;
326                     case FAILURE_CONNECT_NETWORK_FAILED:
327                         sb.append("CONNECT_NETWORK_FAILED");
328                         break;
329                     case FAILURE_NETWORK_DISCONNECTION:
330                         sb.append("NETWORK_DISCONNECTION");
331                         break;
332                     case FAILURE_NEW_CONNECTION_ATTEMPT:
333                         sb.append("NEW_CONNECTION_ATTEMPT");
334                         break;
335                     case FAILURE_REDUNDANT_CONNECTION_ATTEMPT:
336                         sb.append("REDUNDANT_CONNECTION_ATTEMPT");
337                         break;
338                     case FAILURE_ROAM_TIMEOUT:
339                         sb.append("ROAM_TIMEOUT");
340                         break;
341                     case FAILURE_DHCP:
342                         sb.append("DHCP");
343                     default:
344                         sb.append("UNKNOWN");
345                         break;
346                 }
347                 sb.append(", connectivityLevelFailureCode=");
348                 switch(mConnectionEvent.connectivityLevelFailureCode) {
349                     case WifiMetricsProto.ConnectionEvent.HLF_NONE:
350                         sb.append("NONE");
351                         break;
352                     case WifiMetricsProto.ConnectionEvent.HLF_DHCP:
353                         sb.append("DHCP");
354                         break;
355                     case WifiMetricsProto.ConnectionEvent.HLF_NO_INTERNET:
356                         sb.append("NO_INTERNET");
357                         break;
358                     case WifiMetricsProto.ConnectionEvent.HLF_UNWANTED:
359                         sb.append("UNWANTED");
360                         break;
361                     default:
362                         sb.append("UNKNOWN");
363                         break;
364                 }
365                 sb.append(", signalStrength=");
366                 sb.append(mConnectionEvent.signalStrength);
367                 sb.append(", wifiState=");
368                 switch(mWifiState) {
369                     case WifiMetricsProto.WifiLog.WIFI_DISABLED:
370                         sb.append("WIFI_DISABLED");
371                         break;
372                     case WifiMetricsProto.WifiLog.WIFI_DISCONNECTED:
373                         sb.append("WIFI_DISCONNECTED");
374                         break;
375                     case WifiMetricsProto.WifiLog.WIFI_ASSOCIATED:
376                         sb.append("WIFI_ASSOCIATED");
377                         break;
378                     default:
379                         sb.append("WIFI_UNKNOWN");
380                         break;
381                 }
382                 sb.append(", screenOn=");
383                 sb.append(mScreenOn);
384                 sb.append(". mRouterFingerprint: ");
385                 sb.append(mRouterFingerPrint.toString());
386             }
387             return sb.toString();
388         }
389     }
390 
WifiMetrics(Clock clock, Looper looper, WifiAwareMetrics awareMetrics)391     public WifiMetrics(Clock clock, Looper looper, WifiAwareMetrics awareMetrics) {
392         mClock = clock;
393         mCurrentConnectionEvent = null;
394         mScreenOn = true;
395         mWifiState = WifiMetricsProto.WifiLog.WIFI_DISABLED;
396         mRecordStartTimeSec = mClock.getElapsedSinceBootMillis() / 1000;
397         mWifiAwareMetrics = awareMetrics;
398 
399         mHandler = new Handler(looper) {
400             public void handleMessage(Message msg) {
401                 synchronized (mLock) {
402                     processMessage(msg);
403                 }
404             }
405         };
406     }
407 
408     /** Sets internal WifiConfigManager member */
setWifiConfigManager(WifiConfigManager wifiConfigManager)409     public void setWifiConfigManager(WifiConfigManager wifiConfigManager) {
410         mWifiConfigManager = wifiConfigManager;
411     }
412 
413     /** Sets internal WifiNetworkSelector member */
setWifiNetworkSelector(WifiNetworkSelector wifiNetworkSelector)414     public void setWifiNetworkSelector(WifiNetworkSelector wifiNetworkSelector) {
415         mWifiNetworkSelector = wifiNetworkSelector;
416     }
417 
418     /** Sets internal PasspointManager member */
setPasspointManager(PasspointManager passpointManager)419     public void setPasspointManager(PasspointManager passpointManager) {
420         mPasspointManager = passpointManager;
421     }
422 
423     /**
424      * Increment total number of attempts to start a pno scan
425      */
incrementPnoScanStartAttempCount()426     public void incrementPnoScanStartAttempCount() {
427         synchronized (mLock) {
428             mPnoScanMetrics.numPnoScanAttempts++;
429         }
430     }
431 
432     /**
433      * Increment total number of attempts with pno scan failed
434      */
incrementPnoScanFailedCount()435     public void incrementPnoScanFailedCount() {
436         synchronized (mLock) {
437             mPnoScanMetrics.numPnoScanFailed++;
438         }
439     }
440 
441     /**
442      * Increment number of pno scans started successfully over offload
443      */
incrementPnoScanStartedOverOffloadCount()444     public void incrementPnoScanStartedOverOffloadCount() {
445         synchronized (mLock) {
446             mPnoScanMetrics.numPnoScanStartedOverOffload++;
447         }
448     }
449 
450     /**
451      * Increment number of pno scans failed over offload
452      */
incrementPnoScanFailedOverOffloadCount()453     public void incrementPnoScanFailedOverOffloadCount() {
454         synchronized (mLock) {
455             mPnoScanMetrics.numPnoScanFailedOverOffload++;
456         }
457     }
458 
459     /**
460      * Increment number of times pno scan found a result
461      */
incrementPnoFoundNetworkEventCount()462     public void incrementPnoFoundNetworkEventCount() {
463         synchronized (mLock) {
464             mPnoScanMetrics.numPnoFoundNetworkEvents++;
465         }
466     }
467 
468     // Values used for indexing SystemStateEntries
469     private static final int SCREEN_ON = 1;
470     private static final int SCREEN_OFF = 0;
471 
472     /**
473      * Create a new connection event. Call when wifi attempts to make a new network connection
474      * If there is a current 'un-ended' connection event, it will be ended with UNKNOWN connectivity
475      * failure code.
476      * Gathers and sets the RouterFingerPrint data as well
477      *
478      * @param config WifiConfiguration of the config used for the current connection attempt
479      * @param roamType Roam type that caused connection attempt, see WifiMetricsProto.WifiLog.ROAM_X
480      */
startConnectionEvent(WifiConfiguration config, String targetBSSID, int roamType)481     public void startConnectionEvent(WifiConfiguration config, String targetBSSID, int roamType) {
482         synchronized (mLock) {
483             // Check if this is overlapping another current connection event
484             if (mCurrentConnectionEvent != null) {
485                 //Is this new Connection Event the same as the current one
486                 if (mCurrentConnectionEvent.mConfigSsid != null
487                         && mCurrentConnectionEvent.mConfigBssid != null
488                         && config != null
489                         && mCurrentConnectionEvent.mConfigSsid.equals(config.SSID)
490                         && (mCurrentConnectionEvent.mConfigBssid.equals("any")
491                         || mCurrentConnectionEvent.mConfigBssid.equals(targetBSSID))) {
492                     mCurrentConnectionEvent.mConfigBssid = targetBSSID;
493                     // End Connection Event due to new connection attempt to the same network
494                     endConnectionEvent(ConnectionEvent.FAILURE_REDUNDANT_CONNECTION_ATTEMPT,
495                             WifiMetricsProto.ConnectionEvent.HLF_NONE);
496                 } else {
497                     // End Connection Event due to new connection attempt to different network
498                     endConnectionEvent(ConnectionEvent.FAILURE_NEW_CONNECTION_ATTEMPT,
499                             WifiMetricsProto.ConnectionEvent.HLF_NONE);
500                 }
501             }
502             //If past maximum connection events, start removing the oldest
503             while(mConnectionEventList.size() >= MAX_CONNECTION_EVENTS) {
504                 mConnectionEventList.remove(0);
505             }
506             mCurrentConnectionEvent = new ConnectionEvent();
507             mCurrentConnectionEvent.mConnectionEvent.startTimeMillis =
508                     mClock.getWallClockMillis();
509             mCurrentConnectionEvent.mConfigBssid = targetBSSID;
510             mCurrentConnectionEvent.mConnectionEvent.roamType = roamType;
511             mCurrentConnectionEvent.mRouterFingerPrint.updateFromWifiConfiguration(config);
512             mCurrentConnectionEvent.mConfigBssid = "any";
513             mCurrentConnectionEvent.mRealStartTime = mClock.getElapsedSinceBootMillis();
514             mCurrentConnectionEvent.mWifiState = mWifiState;
515             mCurrentConnectionEvent.mScreenOn = mScreenOn;
516             mConnectionEventList.add(mCurrentConnectionEvent);
517             mScanResultRssiTimestampMillis = -1;
518             if (config != null) {
519                 ScanResult candidate = config.getNetworkSelectionStatus().getCandidate();
520                 if (candidate != null) {
521                     // Cache the RSSI of the candidate, as the connection event level is updated
522                     // from other sources (polls, bssid_associations) and delta requires the
523                     // scanResult rssi
524                     mScanResultRssi = candidate.level;
525                     mScanResultRssiTimestampMillis = mClock.getElapsedSinceBootMillis();
526                 }
527             }
528         }
529     }
530 
531     /**
532      * set the RoamType of the current ConnectionEvent (if any)
533      */
setConnectionEventRoamType(int roamType)534     public void setConnectionEventRoamType(int roamType) {
535         synchronized (mLock) {
536             if (mCurrentConnectionEvent != null) {
537                 mCurrentConnectionEvent.mConnectionEvent.roamType = roamType;
538             }
539         }
540     }
541 
542     /**
543      * Set AP related metrics from ScanDetail
544      */
setConnectionScanDetail(ScanDetail scanDetail)545     public void setConnectionScanDetail(ScanDetail scanDetail) {
546         synchronized (mLock) {
547             if (mCurrentConnectionEvent != null && scanDetail != null) {
548                 NetworkDetail networkDetail = scanDetail.getNetworkDetail();
549                 ScanResult scanResult = scanDetail.getScanResult();
550                 //Ensure that we have a networkDetail, and that it corresponds to the currently
551                 //tracked connection attempt
552                 if (networkDetail != null && scanResult != null
553                         && mCurrentConnectionEvent.mConfigSsid != null
554                         && mCurrentConnectionEvent.mConfigSsid
555                         .equals("\"" + networkDetail.getSSID() + "\"")) {
556                     updateMetricsFromNetworkDetail(networkDetail);
557                     updateMetricsFromScanResult(scanResult);
558                 }
559             }
560         }
561     }
562 
563     /**
564      * End a Connection event record. Call when wifi connection attempt succeeds or fails.
565      * If a Connection event has not been started and is active when .end is called, a new one is
566      * created with zero duration.
567      *
568      * @param level2FailureCode Level 2 failure code returned by supplicant
569      * @param connectivityFailureCode WifiMetricsProto.ConnectionEvent.HLF_X
570      */
endConnectionEvent(int level2FailureCode, int connectivityFailureCode)571     public void endConnectionEvent(int level2FailureCode, int connectivityFailureCode) {
572         synchronized (mLock) {
573             if (mCurrentConnectionEvent != null) {
574                 boolean result = (level2FailureCode == 1)
575                         && (connectivityFailureCode == WifiMetricsProto.ConnectionEvent.HLF_NONE);
576                 mCurrentConnectionEvent.mConnectionEvent.connectionResult = result ? 1 : 0;
577                 mCurrentConnectionEvent.mRealEndTime = mClock.getElapsedSinceBootMillis();
578                 mCurrentConnectionEvent.mConnectionEvent.durationTakenToConnectMillis = (int)
579                         (mCurrentConnectionEvent.mRealEndTime
580                         - mCurrentConnectionEvent.mRealStartTime);
581                 mCurrentConnectionEvent.mConnectionEvent.level2FailureCode = level2FailureCode;
582                 mCurrentConnectionEvent.mConnectionEvent.connectivityLevelFailureCode =
583                         connectivityFailureCode;
584                 // ConnectionEvent already added to ConnectionEvents List. Safe to null current here
585                 mCurrentConnectionEvent = null;
586                 if (!result) {
587                     mScanResultRssiTimestampMillis = -1;
588                 }
589             }
590         }
591     }
592 
593     /**
594      * Set ConnectionEvent DTIM Interval (if set), and 802.11 Connection mode, from NetworkDetail
595      */
updateMetricsFromNetworkDetail(NetworkDetail networkDetail)596     private void updateMetricsFromNetworkDetail(NetworkDetail networkDetail) {
597         int dtimInterval = networkDetail.getDtimInterval();
598         if (dtimInterval > 0) {
599             mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.dtim =
600                     dtimInterval;
601         }
602         int connectionWifiMode;
603         switch (networkDetail.getWifiMode()) {
604             case InformationElementUtil.WifiMode.MODE_UNDEFINED:
605                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_UNKNOWN;
606                 break;
607             case InformationElementUtil.WifiMode.MODE_11A:
608                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_A;
609                 break;
610             case InformationElementUtil.WifiMode.MODE_11B:
611                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_B;
612                 break;
613             case InformationElementUtil.WifiMode.MODE_11G:
614                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_G;
615                 break;
616             case InformationElementUtil.WifiMode.MODE_11N:
617                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_N;
618                 break;
619             case InformationElementUtil.WifiMode.MODE_11AC  :
620                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_AC;
621                 break;
622             default:
623                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_OTHER;
624                 break;
625         }
626         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
627                 .routerTechnology = connectionWifiMode;
628     }
629 
630     /**
631      * Set ConnectionEvent RSSI and authentication type from ScanResult
632      */
updateMetricsFromScanResult(ScanResult scanResult)633     private void updateMetricsFromScanResult(ScanResult scanResult) {
634         mCurrentConnectionEvent.mConnectionEvent.signalStrength = scanResult.level;
635         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
636                 WifiMetricsProto.RouterFingerPrint.AUTH_OPEN;
637         mCurrentConnectionEvent.mConfigBssid = scanResult.BSSID;
638         if (scanResult.capabilities != null) {
639             if (ScanResultUtil.isScanResultForWepNetwork(scanResult)) {
640                 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
641                         WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL;
642             } else if (ScanResultUtil.isScanResultForPskNetwork(scanResult)) {
643                 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
644                         WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL;
645             } else if (ScanResultUtil.isScanResultForEapNetwork(scanResult)) {
646                 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
647                         WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE;
648             }
649         }
650         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.channelInfo =
651                 scanResult.frequency;
652     }
653 
setIsLocationEnabled(boolean enabled)654     void setIsLocationEnabled(boolean enabled) {
655         synchronized (mLock) {
656             mWifiLogProto.isLocationEnabled = enabled;
657         }
658     }
659 
setIsScanningAlwaysEnabled(boolean enabled)660     void setIsScanningAlwaysEnabled(boolean enabled) {
661         synchronized (mLock) {
662             mWifiLogProto.isScanningAlwaysEnabled = enabled;
663         }
664     }
665 
666     /**
667      * Increment Non Empty Scan Results count
668      */
incrementNonEmptyScanResultCount()669     public void incrementNonEmptyScanResultCount() {
670         if (DBG) Log.v(TAG, "incrementNonEmptyScanResultCount");
671         synchronized (mLock) {
672             mWifiLogProto.numNonEmptyScanResults++;
673         }
674     }
675 
676     /**
677      * Increment Empty Scan Results count
678      */
incrementEmptyScanResultCount()679     public void incrementEmptyScanResultCount() {
680         if (DBG) Log.v(TAG, "incrementEmptyScanResultCount");
681         synchronized (mLock) {
682             mWifiLogProto.numEmptyScanResults++;
683         }
684     }
685 
686     /**
687      * Increment background scan count
688      */
incrementBackgroundScanCount()689     public void incrementBackgroundScanCount() {
690         if (DBG) Log.v(TAG, "incrementBackgroundScanCount");
691         synchronized (mLock) {
692             mWifiLogProto.numBackgroundScans++;
693         }
694     }
695 
696    /**
697      * Get Background scan count
698      */
getBackgroundScanCount()699     public int getBackgroundScanCount() {
700         synchronized (mLock) {
701             return mWifiLogProto.numBackgroundScans;
702         }
703     }
704 
705     /**
706      * Increment oneshot scan count, and the associated WifiSystemScanStateCount entry
707      */
incrementOneshotScanCount()708     public void incrementOneshotScanCount() {
709         synchronized (mLock) {
710             mWifiLogProto.numOneshotScans++;
711         }
712         incrementWifiSystemScanStateCount(mWifiState, mScreenOn);
713     }
714 
715     /**
716      * Get oneshot scan count
717      */
getOneshotScanCount()718     public int getOneshotScanCount() {
719         synchronized (mLock) {
720             return mWifiLogProto.numOneshotScans;
721         }
722     }
723 
returnCodeToString(int scanReturnCode)724     private String returnCodeToString(int scanReturnCode) {
725         switch(scanReturnCode){
726             case WifiMetricsProto.WifiLog.SCAN_UNKNOWN:
727                 return "SCAN_UNKNOWN";
728             case WifiMetricsProto.WifiLog.SCAN_SUCCESS:
729                 return "SCAN_SUCCESS";
730             case WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED:
731                 return "SCAN_FAILURE_INTERRUPTED";
732             case WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION:
733                 return "SCAN_FAILURE_INVALID_CONFIGURATION";
734             case WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED:
735                 return "FAILURE_WIFI_DISABLED";
736             default:
737                 return "<UNKNOWN>";
738         }
739     }
740 
741     /**
742      * Increment count of scan return code occurrence
743      *
744      * @param scanReturnCode Return code from scan attempt WifiMetricsProto.WifiLog.SCAN_X
745      */
incrementScanReturnEntry(int scanReturnCode, int countToAdd)746     public void incrementScanReturnEntry(int scanReturnCode, int countToAdd) {
747         synchronized (mLock) {
748             if (DBG) Log.v(TAG, "incrementScanReturnEntry " + returnCodeToString(scanReturnCode));
749             int entry = mScanReturnEntries.get(scanReturnCode);
750             entry += countToAdd;
751             mScanReturnEntries.put(scanReturnCode, entry);
752         }
753     }
754     /**
755      * Get the count of this scanReturnCode
756      * @param scanReturnCode that we are getting the count for
757      */
getScanReturnEntry(int scanReturnCode)758     public int getScanReturnEntry(int scanReturnCode) {
759         synchronized (mLock) {
760             return mScanReturnEntries.get(scanReturnCode);
761         }
762     }
763 
wifiSystemStateToString(int state)764     private String wifiSystemStateToString(int state) {
765         switch(state){
766             case WifiMetricsProto.WifiLog.WIFI_UNKNOWN:
767                 return "WIFI_UNKNOWN";
768             case WifiMetricsProto.WifiLog.WIFI_DISABLED:
769                 return "WIFI_DISABLED";
770             case WifiMetricsProto.WifiLog.WIFI_DISCONNECTED:
771                 return "WIFI_DISCONNECTED";
772             case WifiMetricsProto.WifiLog.WIFI_ASSOCIATED:
773                 return "WIFI_ASSOCIATED";
774             default:
775                 return "default";
776         }
777     }
778 
779     /**
780      * Increments the count of scans initiated by each wifi state, accounts for screenOn/Off
781      *
782      * @param state State of the system when scan was initiated, see WifiMetricsProto.WifiLog.WIFI_X
783      * @param screenOn Is the screen on
784      */
incrementWifiSystemScanStateCount(int state, boolean screenOn)785     public void incrementWifiSystemScanStateCount(int state, boolean screenOn) {
786         synchronized (mLock) {
787             if (DBG) {
788                 Log.v(TAG, "incrementWifiSystemScanStateCount " + wifiSystemStateToString(state)
789                         + " " + screenOn);
790             }
791             int index = (state * 2) + (screenOn ? SCREEN_ON : SCREEN_OFF);
792             int entry = mWifiSystemStateEntries.get(index);
793             entry++;
794             mWifiSystemStateEntries.put(index, entry);
795         }
796     }
797 
798     /**
799      * Get the count of this system State Entry
800      */
getSystemStateCount(int state, boolean screenOn)801     public int getSystemStateCount(int state, boolean screenOn) {
802         synchronized (mLock) {
803             int index = state * 2 + (screenOn ? SCREEN_ON : SCREEN_OFF);
804             return mWifiSystemStateEntries.get(index);
805         }
806     }
807 
808     /**
809      * Increment number of times the Watchdog of Last Resort triggered, resetting the wifi stack
810      */
incrementNumLastResortWatchdogTriggers()811     public void incrementNumLastResortWatchdogTriggers() {
812         synchronized (mLock) {
813             mWifiLogProto.numLastResortWatchdogTriggers++;
814         }
815     }
816     /**
817      * @param count number of networks over bad association threshold when watchdog triggered
818      */
addCountToNumLastResortWatchdogBadAssociationNetworksTotal(int count)819     public void addCountToNumLastResortWatchdogBadAssociationNetworksTotal(int count) {
820         synchronized (mLock) {
821             mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal += count;
822         }
823     }
824     /**
825      * @param count number of networks over bad authentication threshold when watchdog triggered
826      */
addCountToNumLastResortWatchdogBadAuthenticationNetworksTotal(int count)827     public void addCountToNumLastResortWatchdogBadAuthenticationNetworksTotal(int count) {
828         synchronized (mLock) {
829             mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal += count;
830         }
831     }
832     /**
833      * @param count number of networks over bad dhcp threshold when watchdog triggered
834      */
addCountToNumLastResortWatchdogBadDhcpNetworksTotal(int count)835     public void addCountToNumLastResortWatchdogBadDhcpNetworksTotal(int count) {
836         synchronized (mLock) {
837             mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal += count;
838         }
839     }
840     /**
841      * @param count number of networks over bad other threshold when watchdog triggered
842      */
addCountToNumLastResortWatchdogBadOtherNetworksTotal(int count)843     public void addCountToNumLastResortWatchdogBadOtherNetworksTotal(int count) {
844         synchronized (mLock) {
845             mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal += count;
846         }
847     }
848     /**
849      * @param count number of networks seen when watchdog triggered
850      */
addCountToNumLastResortWatchdogAvailableNetworksTotal(int count)851     public void addCountToNumLastResortWatchdogAvailableNetworksTotal(int count) {
852         synchronized (mLock) {
853             mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal += count;
854         }
855     }
856     /**
857      * Increment count of triggers with atleast one bad association network
858      */
incrementNumLastResortWatchdogTriggersWithBadAssociation()859     public void incrementNumLastResortWatchdogTriggersWithBadAssociation() {
860         synchronized (mLock) {
861             mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation++;
862         }
863     }
864     /**
865      * Increment count of triggers with atleast one bad authentication network
866      */
incrementNumLastResortWatchdogTriggersWithBadAuthentication()867     public void incrementNumLastResortWatchdogTriggersWithBadAuthentication() {
868         synchronized (mLock) {
869             mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication++;
870         }
871     }
872     /**
873      * Increment count of triggers with atleast one bad dhcp network
874      */
incrementNumLastResortWatchdogTriggersWithBadDhcp()875     public void incrementNumLastResortWatchdogTriggersWithBadDhcp() {
876         synchronized (mLock) {
877             mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp++;
878         }
879     }
880     /**
881      * Increment count of triggers with atleast one bad other network
882      */
incrementNumLastResortWatchdogTriggersWithBadOther()883     public void incrementNumLastResortWatchdogTriggersWithBadOther() {
884         synchronized (mLock) {
885             mWifiLogProto.numLastResortWatchdogTriggersWithBadOther++;
886         }
887     }
888 
889     /**
890      * Increment number of times connectivity watchdog confirmed pno is working
891      */
incrementNumConnectivityWatchdogPnoGood()892     public void incrementNumConnectivityWatchdogPnoGood() {
893         synchronized (mLock) {
894             mWifiLogProto.numConnectivityWatchdogPnoGood++;
895         }
896     }
897     /**
898      * Increment number of times connectivity watchdog found pno not working
899      */
incrementNumConnectivityWatchdogPnoBad()900     public void incrementNumConnectivityWatchdogPnoBad() {
901         synchronized (mLock) {
902             mWifiLogProto.numConnectivityWatchdogPnoBad++;
903         }
904     }
905     /**
906      * Increment number of times connectivity watchdog confirmed background scan is working
907      */
incrementNumConnectivityWatchdogBackgroundGood()908     public void incrementNumConnectivityWatchdogBackgroundGood() {
909         synchronized (mLock) {
910             mWifiLogProto.numConnectivityWatchdogBackgroundGood++;
911         }
912     }
913     /**
914      * Increment number of times connectivity watchdog found background scan not working
915      */
incrementNumConnectivityWatchdogBackgroundBad()916     public void incrementNumConnectivityWatchdogBackgroundBad() {
917         synchronized (mLock) {
918             mWifiLogProto.numConnectivityWatchdogBackgroundBad++;
919         }
920     }
921 
922     /**
923      * Increment various poll related metrics, and cache performance data for StaEvent logging
924      */
handlePollResult(WifiInfo wifiInfo)925     public void handlePollResult(WifiInfo wifiInfo) {
926         mLastPollRssi = wifiInfo.getRssi();
927         mLastPollLinkSpeed = wifiInfo.getLinkSpeed();
928         mLastPollFreq = wifiInfo.getFrequency();
929         incrementRssiPollRssiCount(mLastPollRssi);
930     }
931 
932     /**
933      * Increment occurence count of RSSI level from RSSI poll.
934      * Ignores rssi values outside the bounds of [MIN_RSSI_POLL, MAX_RSSI_POLL]
935      */
incrementRssiPollRssiCount(int rssi)936     public void incrementRssiPollRssiCount(int rssi) {
937         if (!(rssi >= MIN_RSSI_POLL && rssi <= MAX_RSSI_POLL)) {
938             return;
939         }
940         synchronized (mLock) {
941             int count = mRssiPollCounts.get(rssi);
942             mRssiPollCounts.put(rssi, count + 1);
943             maybeIncrementRssiDeltaCount(rssi - mScanResultRssi);
944         }
945     }
946 
947     /**
948      * Increment occurence count of difference between scan result RSSI and the first RSSI poll.
949      * Ignores rssi values outside the bounds of [MIN_RSSI_DELTA, MAX_RSSI_DELTA]
950      * mLock must be held when calling this method.
951      */
maybeIncrementRssiDeltaCount(int rssi)952     private void maybeIncrementRssiDeltaCount(int rssi) {
953         // Check if this RSSI poll is close enough to a scan result RSSI to log a delta value
954         if (mScanResultRssiTimestampMillis >= 0) {
955             long timeDelta = mClock.getElapsedSinceBootMillis() - mScanResultRssiTimestampMillis;
956             if (timeDelta <= TIMEOUT_RSSI_DELTA_MILLIS) {
957                 if (rssi >= MIN_RSSI_DELTA && rssi <= MAX_RSSI_DELTA) {
958                     int count = mRssiDeltaCounts.get(rssi);
959                     mRssiDeltaCounts.put(rssi, count + 1);
960                 }
961             }
962             mScanResultRssiTimestampMillis = -1;
963         }
964     }
965 
966     /**
967      * Increment count of Watchdog successes.
968      */
incrementNumLastResortWatchdogSuccesses()969     public void incrementNumLastResortWatchdogSuccesses() {
970         synchronized (mLock) {
971             mWifiLogProto.numLastResortWatchdogSuccesses++;
972         }
973     }
974 
975     /**
976      * Increments the count of alerts by alert reason.
977      *
978      * @param reason The cause of the alert. The reason values are driver-specific.
979      */
incrementAlertReasonCount(int reason)980     public void incrementAlertReasonCount(int reason) {
981         if (reason > WifiLoggerHal.WIFI_ALERT_REASON_MAX
982                 || reason < WifiLoggerHal.WIFI_ALERT_REASON_MIN) {
983             reason = WifiLoggerHal.WIFI_ALERT_REASON_RESERVED;
984         }
985         synchronized (mLock) {
986             int alertCount = mWifiAlertReasonCounts.get(reason);
987             mWifiAlertReasonCounts.put(reason, alertCount + 1);
988         }
989     }
990 
991     /**
992      * Counts all the different types of networks seen in a set of scan results
993      */
countScanResults(List<ScanDetail> scanDetails)994     public void countScanResults(List<ScanDetail> scanDetails) {
995         if (scanDetails == null) {
996             return;
997         }
998         int totalResults = 0;
999         int openNetworks = 0;
1000         int personalNetworks = 0;
1001         int enterpriseNetworks = 0;
1002         int hiddenNetworks = 0;
1003         int hotspot2r1Networks = 0;
1004         int hotspot2r2Networks = 0;
1005         for (ScanDetail scanDetail : scanDetails) {
1006             NetworkDetail networkDetail = scanDetail.getNetworkDetail();
1007             ScanResult scanResult = scanDetail.getScanResult();
1008             totalResults++;
1009             if (networkDetail != null) {
1010                 if (networkDetail.isHiddenBeaconFrame()) {
1011                     hiddenNetworks++;
1012                 }
1013                 if (networkDetail.getHSRelease() != null) {
1014                     if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) {
1015                         hotspot2r1Networks++;
1016                     } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) {
1017                         hotspot2r2Networks++;
1018                     }
1019                 }
1020             }
1021             if (scanResult != null && scanResult.capabilities != null) {
1022                 if (ScanResultUtil.isScanResultForEapNetwork(scanResult)) {
1023                     enterpriseNetworks++;
1024                 } else if (ScanResultUtil.isScanResultForPskNetwork(scanResult)
1025                         || ScanResultUtil.isScanResultForWepNetwork(scanResult)) {
1026                     personalNetworks++;
1027                 } else {
1028                     openNetworks++;
1029                 }
1030             }
1031         }
1032         synchronized (mLock) {
1033             mWifiLogProto.numTotalScanResults += totalResults;
1034             mWifiLogProto.numOpenNetworkScanResults += openNetworks;
1035             mWifiLogProto.numPersonalNetworkScanResults += personalNetworks;
1036             mWifiLogProto.numEnterpriseNetworkScanResults += enterpriseNetworks;
1037             mWifiLogProto.numHiddenNetworkScanResults += hiddenNetworks;
1038             mWifiLogProto.numHotspot2R1NetworkScanResults += hotspot2r1Networks;
1039             mWifiLogProto.numHotspot2R2NetworkScanResults += hotspot2r2Networks;
1040             mWifiLogProto.numScans++;
1041         }
1042     }
1043 
1044     /**
1045      * Increments occurence of a particular wifi score calculated
1046      * in WifiScoreReport by current connected network. Scores are bounded
1047      * within  [MIN_WIFI_SCORE, MAX_WIFI_SCORE] to limit size of SparseArray
1048      */
incrementWifiScoreCount(int score)1049     public void incrementWifiScoreCount(int score) {
1050         if (score < MIN_WIFI_SCORE || score > MAX_WIFI_SCORE) {
1051             return;
1052         }
1053         synchronized (mLock) {
1054             int count = mWifiScoreCounts.get(score);
1055             mWifiScoreCounts.put(score, count + 1);
1056         }
1057     }
1058 
1059     /**
1060      * Increments occurence of the results from attempting to start SoftAp.
1061      * Maps the |result| and WifiManager |failureCode| constant to proto defined SoftApStartResult
1062      * codes.
1063      */
incrementSoftApStartResult(boolean result, int failureCode)1064     public void incrementSoftApStartResult(boolean result, int failureCode) {
1065         synchronized (mLock) {
1066             if (result) {
1067                 int count = mSoftApManagerReturnCodeCounts.get(
1068                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY);
1069                 mSoftApManagerReturnCodeCounts.put(
1070                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY,
1071                         count + 1);
1072                 return;
1073             }
1074 
1075             // now increment failure modes - if not explicitly handled, dump into the general
1076             // error bucket.
1077             if (failureCode == WifiManager.SAP_START_FAILURE_NO_CHANNEL) {
1078                 int count = mSoftApManagerReturnCodeCounts.get(
1079                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL);
1080                 mSoftApManagerReturnCodeCounts.put(
1081                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL,
1082                         count + 1);
1083             } else {
1084                 // failure mode not tracked at this time...  count as a general error for now.
1085                 int count = mSoftApManagerReturnCodeCounts.get(
1086                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR);
1087                 mSoftApManagerReturnCodeCounts.put(
1088                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR,
1089                         count + 1);
1090             }
1091         }
1092     }
1093 
1094     /**
1095      * Increment number of times the HAL crashed.
1096      */
incrementNumHalCrashes()1097     public void incrementNumHalCrashes() {
1098         synchronized (mLock) {
1099             mWifiLogProto.numHalCrashes++;
1100         }
1101     }
1102 
1103     /**
1104      * Increment number of times the Wificond crashed.
1105      */
incrementNumWificondCrashes()1106     public void incrementNumWificondCrashes() {
1107         synchronized (mLock) {
1108             mWifiLogProto.numWificondCrashes++;
1109         }
1110     }
1111 
1112     /**
1113      * Increment number of times the wifi on failed due to an error in HAL.
1114      */
incrementNumWifiOnFailureDueToHal()1115     public void incrementNumWifiOnFailureDueToHal() {
1116         synchronized (mLock) {
1117             mWifiLogProto.numWifiOnFailureDueToHal++;
1118         }
1119     }
1120 
1121     /**
1122      * Increment number of times the wifi on failed due to an error in wificond.
1123      */
incrementNumWifiOnFailureDueToWificond()1124     public void incrementNumWifiOnFailureDueToWificond() {
1125         synchronized (mLock) {
1126             mWifiLogProto.numWifiOnFailureDueToWificond++;
1127         }
1128     }
1129 
1130     /**
1131      * Increment number of times Passpoint provider being installed.
1132      */
incrementNumPasspointProviderInstallation()1133     public void incrementNumPasspointProviderInstallation() {
1134         synchronized (mLock) {
1135             mWifiLogProto.numPasspointProviderInstallation++;
1136         }
1137     }
1138 
1139     /**
1140      * Increment number of times Passpoint provider is installed successfully.
1141      */
incrementNumPasspointProviderInstallSuccess()1142     public void incrementNumPasspointProviderInstallSuccess() {
1143         synchronized (mLock) {
1144             mWifiLogProto.numPasspointProviderInstallSuccess++;
1145         }
1146     }
1147 
1148     /**
1149      * Increment number of times Passpoint provider being uninstalled.
1150      */
incrementNumPasspointProviderUninstallation()1151     public void incrementNumPasspointProviderUninstallation() {
1152         synchronized (mLock) {
1153             mWifiLogProto.numPasspointProviderUninstallation++;
1154         }
1155     }
1156 
1157     /**
1158      * Increment number of times Passpoint provider is uninstalled successfully.
1159      */
incrementNumPasspointProviderUninstallSuccess()1160     public void incrementNumPasspointProviderUninstallSuccess() {
1161         synchronized (mLock) {
1162             mWifiLogProto.numPasspointProviderUninstallSuccess++;
1163         }
1164     }
1165 
1166     /**
1167      * Increment N-Way network selection decision histograms:
1168      * Counts the size of various sets of scanDetails within a scan, and increment the occurrence
1169      * of that size for the associated histogram. There are ten histograms generated for each
1170      * combination of: {SSID, BSSID} *{Total, Saved, Open, Saved_or_Open, Passpoint}
1171      * Only performs this count if isFullBand is true, otherwise, increments the partial scan count
1172      */
incrementAvailableNetworksHistograms(List<ScanDetail> scanDetails, boolean isFullBand)1173     public void incrementAvailableNetworksHistograms(List<ScanDetail> scanDetails,
1174             boolean isFullBand) {
1175         synchronized (mLock) {
1176             if (mWifiConfigManager == null || mWifiNetworkSelector == null
1177                     || mPasspointManager == null) {
1178                 return;
1179             }
1180             if (!isFullBand) {
1181                 mWifiLogProto.partialAllSingleScanListenerResults++;
1182                 return;
1183             }
1184             Set<ScanResultMatchInfo> ssids = new HashSet<ScanResultMatchInfo>();
1185             int bssids = 0;
1186             Set<ScanResultMatchInfo> openSsids = new HashSet<ScanResultMatchInfo>();
1187             int openBssids = 0;
1188             Set<ScanResultMatchInfo> savedSsids = new HashSet<ScanResultMatchInfo>();
1189             int savedBssids = 0;
1190             // openOrSavedSsids calculated from union of savedSsids & openSsids
1191             int openOrSavedBssids = 0;
1192             Set<PasspointProvider> savedPasspointProviderProfiles =
1193                     new HashSet<PasspointProvider>();
1194             int savedPasspointProviderBssids = 0;
1195             for (ScanDetail scanDetail : scanDetails) {
1196                 NetworkDetail networkDetail = scanDetail.getNetworkDetail();
1197                 ScanResult scanResult = scanDetail.getScanResult();
1198                 if (mWifiNetworkSelector.isSignalTooWeak(scanResult)) {
1199                     continue;
1200                 }
1201                 ScanResultMatchInfo matchInfo = ScanResultMatchInfo.fromScanResult(scanResult);
1202                 Pair<PasspointProvider, PasspointMatch> providerMatch = null;
1203                 PasspointProvider passpointProvider = null;
1204                 if (networkDetail.isInterworking()) {
1205                     providerMatch =
1206                             mPasspointManager.matchProvider(scanResult);
1207                     passpointProvider = providerMatch != null ? providerMatch.first : null;
1208                 }
1209                 ssids.add(matchInfo);
1210                 bssids++;
1211                 boolean isOpen = matchInfo.networkType == ScanResultMatchInfo.NETWORK_TYPE_OPEN;
1212                 WifiConfiguration config =
1213                         mWifiConfigManager.getConfiguredNetworkForScanDetail(scanDetail);
1214                 boolean isSaved = (config != null) && !config.isEphemeral()
1215                         && !config.isPasspoint();
1216                 boolean isSavedPasspoint = passpointProvider != null;
1217                 if (isOpen) {
1218                     openSsids.add(matchInfo);
1219                     openBssids++;
1220                 }
1221                 if (isSaved) {
1222                     savedSsids.add(matchInfo);
1223                     savedBssids++;
1224                 }
1225                 if (isOpen || isSaved) {
1226                     openOrSavedBssids++;
1227                     // Calculate openOrSavedSsids union later
1228                 }
1229                 if (isSavedPasspoint) {
1230                     savedPasspointProviderProfiles.add(passpointProvider);
1231                     savedPasspointProviderBssids++;
1232                 }
1233             }
1234             mWifiLogProto.fullBandAllSingleScanListenerResults++;
1235             incrementTotalScanSsids(mTotalSsidsInScanHistogram, ssids.size());
1236             incrementTotalScanResults(mTotalBssidsInScanHistogram, bssids);
1237             incrementSsid(mAvailableOpenSsidsInScanHistogram, openSsids.size());
1238             incrementBssid(mAvailableOpenBssidsInScanHistogram, openBssids);
1239             incrementSsid(mAvailableSavedSsidsInScanHistogram, savedSsids.size());
1240             incrementBssid(mAvailableSavedBssidsInScanHistogram, savedBssids);
1241             openSsids.addAll(savedSsids); // openSsids = Union(openSsids, savedSsids)
1242             incrementSsid(mAvailableOpenOrSavedSsidsInScanHistogram, openSsids.size());
1243             incrementBssid(mAvailableOpenOrSavedBssidsInScanHistogram, openOrSavedBssids);
1244             incrementSsid(mAvailableSavedPasspointProviderProfilesInScanHistogram,
1245                     savedPasspointProviderProfiles.size());
1246             incrementBssid(mAvailableSavedPasspointProviderBssidsInScanHistogram,
1247                     savedPasspointProviderBssids);
1248         }
1249     }
1250 
1251     /** Increments the occurence of a "Connect to Network" notification. */
incrementConnectToNetworkNotification(int notificationType)1252     public void incrementConnectToNetworkNotification(int notificationType) {
1253         synchronized (mLock) {
1254             int count = mConnectToNetworkNotificationCount.get(notificationType);
1255             mConnectToNetworkNotificationCount.put(notificationType, count + 1);
1256         }
1257     }
1258 
1259     /** Increments the occurence of an "Connect to Network" notification user action. */
incrementConnectToNetworkNotificationAction(int notificationType, int actionType)1260     public void incrementConnectToNetworkNotificationAction(int notificationType, int actionType) {
1261         synchronized (mLock) {
1262             int key = notificationType * CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER
1263                     + actionType;
1264             int count = mConnectToNetworkNotificationActionCount.get(key);
1265             mConnectToNetworkNotificationActionCount.put(key, count + 1);
1266         }
1267     }
1268 
1269     /**
1270      * Sets the number of SSIDs blacklisted from recommendation by the open network notification
1271      * recommender.
1272      */
setOpenNetworkRecommenderBlacklistSize(int size)1273     public void setOpenNetworkRecommenderBlacklistSize(int size) {
1274         synchronized (mLock) {
1275             mOpenNetworkRecommenderBlacklistSize = size;
1276         }
1277     }
1278 
1279     /** Sets if the available network notification feature is enabled. */
setIsWifiNetworksAvailableNotificationEnabled(boolean enabled)1280     public void setIsWifiNetworksAvailableNotificationEnabled(boolean enabled) {
1281         synchronized (mLock) {
1282             mIsWifiNetworksAvailableNotificationOn = enabled;
1283         }
1284     }
1285 
1286     /** Increments the occurence of connection attempts that were initiated unsuccessfully */
incrementNumOpenNetworkRecommendationUpdates()1287     public void incrementNumOpenNetworkRecommendationUpdates() {
1288         synchronized (mLock) {
1289             mNumOpenNetworkRecommendationUpdates++;
1290         }
1291     }
1292 
1293     /** Increments the occurence of connection attempts that were initiated unsuccessfully */
incrementNumOpenNetworkConnectMessageFailedToSend()1294     public void incrementNumOpenNetworkConnectMessageFailedToSend() {
1295         synchronized (mLock) {
1296             mNumOpenNetworkConnectMessageFailedToSend++;
1297         }
1298     }
1299 
1300     public static final String PROTO_DUMP_ARG = "wifiMetricsProto";
1301     public static final String CLEAN_DUMP_ARG = "clean";
1302 
1303     /**
1304      * Dump all WifiMetrics. Collects some metrics from ConfigStore, Settings and WifiManager
1305      * at this time.
1306      *
1307      * @param fd unused
1308      * @param pw PrintWriter for writing dump to
1309      * @param args unused
1310      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)1311     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1312         synchronized (mLock) {
1313             if (args != null && args.length > 0 && PROTO_DUMP_ARG.equals(args[0])) {
1314                 // Dump serialized WifiLog proto
1315                 consolidateProto(true);
1316                 for (ConnectionEvent event : mConnectionEventList) {
1317                     if (mCurrentConnectionEvent != event) {
1318                         //indicate that automatic bug report has been taken for all valid
1319                         //connection events
1320                         event.mConnectionEvent.automaticBugReportTaken = true;
1321                     }
1322                 }
1323                 byte[] wifiMetricsProto = WifiMetricsProto.WifiLog.toByteArray(mWifiLogProto);
1324                 String metricsProtoDump = Base64.encodeToString(wifiMetricsProto, Base64.DEFAULT);
1325                 if (args.length > 1 && CLEAN_DUMP_ARG.equals(args[1])) {
1326                     // Output metrics proto bytes (base64) and nothing else
1327                     pw.print(metricsProtoDump);
1328                 } else {
1329                     // Tag the start and end of the metrics proto bytes
1330                     pw.println("WifiMetrics:");
1331                     pw.println(metricsProtoDump);
1332                     pw.println("EndWifiMetrics");
1333                 }
1334                 clear();
1335             } else {
1336                 pw.println("WifiMetrics:");
1337                 pw.println("mConnectionEvents:");
1338                 for (ConnectionEvent event : mConnectionEventList) {
1339                     String eventLine = event.toString();
1340                     if (event == mCurrentConnectionEvent) {
1341                         eventLine += "CURRENTLY OPEN EVENT";
1342                     }
1343                     pw.println(eventLine);
1344                 }
1345                 pw.println("mWifiLogProto.numSavedNetworks=" + mWifiLogProto.numSavedNetworks);
1346                 pw.println("mWifiLogProto.numOpenNetworks=" + mWifiLogProto.numOpenNetworks);
1347                 pw.println("mWifiLogProto.numPersonalNetworks="
1348                         + mWifiLogProto.numPersonalNetworks);
1349                 pw.println("mWifiLogProto.numEnterpriseNetworks="
1350                         + mWifiLogProto.numEnterpriseNetworks);
1351                 pw.println("mWifiLogProto.numHiddenNetworks=" + mWifiLogProto.numHiddenNetworks);
1352                 pw.println("mWifiLogProto.numPasspointNetworks="
1353                         + mWifiLogProto.numPasspointNetworks);
1354                 pw.println("mWifiLogProto.isLocationEnabled=" + mWifiLogProto.isLocationEnabled);
1355                 pw.println("mWifiLogProto.isScanningAlwaysEnabled="
1356                         + mWifiLogProto.isScanningAlwaysEnabled);
1357                 pw.println("mWifiLogProto.numNetworksAddedByUser="
1358                         + mWifiLogProto.numNetworksAddedByUser);
1359                 pw.println("mWifiLogProto.numNetworksAddedByApps="
1360                         + mWifiLogProto.numNetworksAddedByApps);
1361                 pw.println("mWifiLogProto.numNonEmptyScanResults="
1362                         + mWifiLogProto.numNonEmptyScanResults);
1363                 pw.println("mWifiLogProto.numEmptyScanResults="
1364                         + mWifiLogProto.numEmptyScanResults);
1365                 pw.println("mWifiLogProto.numOneshotScans="
1366                         + mWifiLogProto.numOneshotScans);
1367                 pw.println("mWifiLogProto.numBackgroundScans="
1368                         + mWifiLogProto.numBackgroundScans);
1369 
1370                 pw.println("mScanReturnEntries:");
1371                 pw.println("  SCAN_UNKNOWN: " + getScanReturnEntry(
1372                         WifiMetricsProto.WifiLog.SCAN_UNKNOWN));
1373                 pw.println("  SCAN_SUCCESS: " + getScanReturnEntry(
1374                         WifiMetricsProto.WifiLog.SCAN_SUCCESS));
1375                 pw.println("  SCAN_FAILURE_INTERRUPTED: " + getScanReturnEntry(
1376                         WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED));
1377                 pw.println("  SCAN_FAILURE_INVALID_CONFIGURATION: " + getScanReturnEntry(
1378                         WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION));
1379                 pw.println("  FAILURE_WIFI_DISABLED: " + getScanReturnEntry(
1380                         WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED));
1381 
1382                 pw.println("mSystemStateEntries: <state><screenOn> : <scansInitiated>");
1383                 pw.println("  WIFI_UNKNOWN       ON: "
1384                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, true));
1385                 pw.println("  WIFI_DISABLED      ON: "
1386                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, true));
1387                 pw.println("  WIFI_DISCONNECTED  ON: "
1388                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, true));
1389                 pw.println("  WIFI_ASSOCIATED    ON: "
1390                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, true));
1391                 pw.println("  WIFI_UNKNOWN      OFF: "
1392                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, false));
1393                 pw.println("  WIFI_DISABLED     OFF: "
1394                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, false));
1395                 pw.println("  WIFI_DISCONNECTED OFF: "
1396                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, false));
1397                 pw.println("  WIFI_ASSOCIATED   OFF: "
1398                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, false));
1399                 pw.println("mWifiLogProto.numConnectivityWatchdogPnoGood="
1400                         + mWifiLogProto.numConnectivityWatchdogPnoGood);
1401                 pw.println("mWifiLogProto.numConnectivityWatchdogPnoBad="
1402                         + mWifiLogProto.numConnectivityWatchdogPnoBad);
1403                 pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundGood="
1404                         + mWifiLogProto.numConnectivityWatchdogBackgroundGood);
1405                 pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundBad="
1406                         + mWifiLogProto.numConnectivityWatchdogBackgroundBad);
1407                 pw.println("mWifiLogProto.numLastResortWatchdogTriggers="
1408                         + mWifiLogProto.numLastResortWatchdogTriggers);
1409                 pw.println("mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal="
1410                         + mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal);
1411                 pw.println("mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal="
1412                         + mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal);
1413                 pw.println("mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal="
1414                         + mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal);
1415                 pw.println("mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal="
1416                         + mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal);
1417                 pw.println("mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal="
1418                         + mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal);
1419                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation="
1420                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation);
1421                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication="
1422                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication);
1423                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp="
1424                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp);
1425                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadOther="
1426                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadOther);
1427                 pw.println("mWifiLogProto.numLastResortWatchdogSuccesses="
1428                         + mWifiLogProto.numLastResortWatchdogSuccesses);
1429                 pw.println("mWifiLogProto.recordDurationSec="
1430                         + ((mClock.getElapsedSinceBootMillis() / 1000) - mRecordStartTimeSec));
1431                 pw.println("mWifiLogProto.rssiPollRssiCount: Printing counts for [" + MIN_RSSI_POLL
1432                         + ", " + MAX_RSSI_POLL + "]");
1433                 StringBuilder sb = new StringBuilder();
1434                 for (int i = MIN_RSSI_POLL; i <= MAX_RSSI_POLL; i++) {
1435                     sb.append(mRssiPollCounts.get(i) + " ");
1436                 }
1437                 pw.println("  " + sb.toString());
1438                 pw.println("mWifiLogProto.rssiPollDeltaCount: Printing counts for ["
1439                         + MIN_RSSI_DELTA + ", " + MAX_RSSI_DELTA + "]");
1440                 sb.setLength(0);
1441                 for (int i = MIN_RSSI_DELTA; i <= MAX_RSSI_DELTA; i++) {
1442                     sb.append(mRssiDeltaCounts.get(i) + " ");
1443                 }
1444                 pw.println("  " + sb.toString());
1445                 pw.print("mWifiLogProto.alertReasonCounts=");
1446                 sb.setLength(0);
1447                 for (int i = WifiLoggerHal.WIFI_ALERT_REASON_MIN;
1448                         i <= WifiLoggerHal.WIFI_ALERT_REASON_MAX; i++) {
1449                     int count = mWifiAlertReasonCounts.get(i);
1450                     if (count > 0) {
1451                         sb.append("(" + i + "," + count + "),");
1452                     }
1453                 }
1454                 if (sb.length() > 1) {
1455                     sb.setLength(sb.length() - 1);  // strip trailing comma
1456                     pw.println(sb.toString());
1457                 } else {
1458                     pw.println("()");
1459                 }
1460                 pw.println("mWifiLogProto.numTotalScanResults="
1461                         + mWifiLogProto.numTotalScanResults);
1462                 pw.println("mWifiLogProto.numOpenNetworkScanResults="
1463                         + mWifiLogProto.numOpenNetworkScanResults);
1464                 pw.println("mWifiLogProto.numPersonalNetworkScanResults="
1465                         + mWifiLogProto.numPersonalNetworkScanResults);
1466                 pw.println("mWifiLogProto.numEnterpriseNetworkScanResults="
1467                         + mWifiLogProto.numEnterpriseNetworkScanResults);
1468                 pw.println("mWifiLogProto.numHiddenNetworkScanResults="
1469                         + mWifiLogProto.numHiddenNetworkScanResults);
1470                 pw.println("mWifiLogProto.numHotspot2R1NetworkScanResults="
1471                         + mWifiLogProto.numHotspot2R1NetworkScanResults);
1472                 pw.println("mWifiLogProto.numHotspot2R2NetworkScanResults="
1473                         + mWifiLogProto.numHotspot2R2NetworkScanResults);
1474                 pw.println("mWifiLogProto.numScans=" + mWifiLogProto.numScans);
1475                 pw.println("mWifiLogProto.WifiScoreCount: [" + MIN_WIFI_SCORE + ", "
1476                         + MAX_WIFI_SCORE + "]");
1477                 for (int i = 0; i <= MAX_WIFI_SCORE; i++) {
1478                     pw.print(mWifiScoreCounts.get(i) + " ");
1479                 }
1480                 pw.println(); // add a line after wifi scores
1481                 pw.println("mWifiLogProto.SoftApManagerReturnCodeCounts:");
1482                 pw.println("  SUCCESS: " + mSoftApManagerReturnCodeCounts.get(
1483                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY));
1484                 pw.println("  FAILED_GENERAL_ERROR: " + mSoftApManagerReturnCodeCounts.get(
1485                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR));
1486                 pw.println("  FAILED_NO_CHANNEL: " + mSoftApManagerReturnCodeCounts.get(
1487                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL));
1488                 pw.print("\n");
1489                 pw.println("mWifiLogProto.numHalCrashes="
1490                         + mWifiLogProto.numHalCrashes);
1491                 pw.println("mWifiLogProto.numWificondCrashes="
1492                         + mWifiLogProto.numWificondCrashes);
1493                 pw.println("mWifiLogProto.numWifiOnFailureDueToHal="
1494                         + mWifiLogProto.numWifiOnFailureDueToHal);
1495                 pw.println("mWifiLogProto.numWifiOnFailureDueToWificond="
1496                         + mWifiLogProto.numWifiOnFailureDueToWificond);
1497                 pw.println("StaEventList:");
1498                 for (StaEventWithTime event : mStaEventList) {
1499                     pw.println(event);
1500                 }
1501 
1502                 pw.println("mWifiLogProto.numPasspointProviders="
1503                         + mWifiLogProto.numPasspointProviders);
1504                 pw.println("mWifiLogProto.numPasspointProviderInstallation="
1505                         + mWifiLogProto.numPasspointProviderInstallation);
1506                 pw.println("mWifiLogProto.numPasspointProviderInstallSuccess="
1507                         + mWifiLogProto.numPasspointProviderInstallSuccess);
1508                 pw.println("mWifiLogProto.numPasspointProviderUninstallation="
1509                         + mWifiLogProto.numPasspointProviderUninstallation);
1510                 pw.println("mWifiLogProto.numPasspointProviderUninstallSuccess="
1511                         + mWifiLogProto.numPasspointProviderUninstallSuccess);
1512                 pw.println("mWifiLogProto.numPasspointProvidersSuccessfullyConnected="
1513                         + mWifiLogProto.numPasspointProvidersSuccessfullyConnected);
1514                 pw.println("mTotalSsidsInScanHistogram:"
1515                         + mTotalSsidsInScanHistogram.toString());
1516                 pw.println("mTotalBssidsInScanHistogram:"
1517                         + mTotalBssidsInScanHistogram.toString());
1518                 pw.println("mAvailableOpenSsidsInScanHistogram:"
1519                         + mAvailableOpenSsidsInScanHistogram.toString());
1520                 pw.println("mAvailableOpenBssidsInScanHistogram:"
1521                         + mAvailableOpenBssidsInScanHistogram.toString());
1522                 pw.println("mAvailableSavedSsidsInScanHistogram:"
1523                         + mAvailableSavedSsidsInScanHistogram.toString());
1524                 pw.println("mAvailableSavedBssidsInScanHistogram:"
1525                         + mAvailableSavedBssidsInScanHistogram.toString());
1526                 pw.println("mAvailableOpenOrSavedSsidsInScanHistogram:"
1527                         + mAvailableOpenOrSavedSsidsInScanHistogram.toString());
1528                 pw.println("mAvailableOpenOrSavedBssidsInScanHistogram:"
1529                         + mAvailableOpenOrSavedBssidsInScanHistogram.toString());
1530                 pw.println("mAvailableSavedPasspointProviderProfilesInScanHistogram:"
1531                         + mAvailableSavedPasspointProviderProfilesInScanHistogram.toString());
1532                 pw.println("mAvailableSavedPasspointProviderBssidsInScanHistogram:"
1533                         + mAvailableSavedPasspointProviderBssidsInScanHistogram.toString());
1534                 pw.println("mWifiLogProto.partialAllSingleScanListenerResults="
1535                         + mWifiLogProto.partialAllSingleScanListenerResults);
1536                 pw.println("mWifiLogProto.fullBandAllSingleScanListenerResults="
1537                         + mWifiLogProto.fullBandAllSingleScanListenerResults);
1538                 pw.println("mWifiAwareMetrics:");
1539                 mWifiAwareMetrics.dump(fd, pw, args);
1540 
1541                 pw.println("mPnoScanMetrics.numPnoScanAttempts="
1542                         + mPnoScanMetrics.numPnoScanAttempts);
1543                 pw.println("mPnoScanMetrics.numPnoScanFailed="
1544                         + mPnoScanMetrics.numPnoScanFailed);
1545                 pw.println("mPnoScanMetrics.numPnoScanStartedOverOffload="
1546                         + mPnoScanMetrics.numPnoScanStartedOverOffload);
1547                 pw.println("mPnoScanMetrics.numPnoScanFailedOverOffload="
1548                         + mPnoScanMetrics.numPnoScanFailedOverOffload);
1549                 pw.println("mPnoScanMetrics.numPnoFoundNetworkEvents="
1550                         + mPnoScanMetrics.numPnoFoundNetworkEvents);
1551 
1552                 pw.println("mWifiLogProto.connectToNetworkNotificationCount="
1553                         + mConnectToNetworkNotificationCount.toString());
1554                 pw.println("mWifiLogProto.connectToNetworkNotificationActionCount="
1555                         + mConnectToNetworkNotificationActionCount.toString());
1556                 pw.println("mWifiLogProto.openNetworkRecommenderBlacklistSize="
1557                         + mOpenNetworkRecommenderBlacklistSize);
1558                 pw.println("mWifiLogProto.isWifiNetworksAvailableNotificationOn="
1559                         + mIsWifiNetworksAvailableNotificationOn);
1560                 pw.println("mWifiLogProto.numOpenNetworkRecommendationUpdates="
1561                         + mNumOpenNetworkRecommendationUpdates);
1562                 pw.println("mWifiLogProto.numOpenNetworkConnectMessageFailedToSend="
1563                         + mNumOpenNetworkConnectMessageFailedToSend);
1564             }
1565         }
1566     }
1567 
1568     /**
1569      * Update various counts of saved network types
1570      * @param networks List of WifiConfigurations representing all saved networks, must not be null
1571      */
updateSavedNetworks(List<WifiConfiguration> networks)1572     public void updateSavedNetworks(List<WifiConfiguration> networks) {
1573         synchronized (mLock) {
1574             mWifiLogProto.numSavedNetworks = networks.size();
1575             mWifiLogProto.numOpenNetworks = 0;
1576             mWifiLogProto.numPersonalNetworks = 0;
1577             mWifiLogProto.numEnterpriseNetworks = 0;
1578             mWifiLogProto.numNetworksAddedByUser = 0;
1579             mWifiLogProto.numNetworksAddedByApps = 0;
1580             mWifiLogProto.numHiddenNetworks = 0;
1581             mWifiLogProto.numPasspointNetworks = 0;
1582             for (WifiConfiguration config : networks) {
1583                 if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) {
1584                     mWifiLogProto.numOpenNetworks++;
1585                 } else if (config.isEnterprise()) {
1586                     mWifiLogProto.numEnterpriseNetworks++;
1587                 } else {
1588                     mWifiLogProto.numPersonalNetworks++;
1589                 }
1590                 if (config.selfAdded) {
1591                     mWifiLogProto.numNetworksAddedByUser++;
1592                 } else {
1593                     mWifiLogProto.numNetworksAddedByApps++;
1594                 }
1595                 if (config.hiddenSSID) {
1596                     mWifiLogProto.numHiddenNetworks++;
1597                 }
1598                 if (config.isPasspoint()) {
1599                     mWifiLogProto.numPasspointNetworks++;
1600                 }
1601             }
1602         }
1603     }
1604 
1605     /**
1606      * Update metrics for saved Passpoint profiles.
1607      *
1608      * @param numSavedProfiles The number of saved Passpoint profiles
1609      * @param numConnectedProfiles The number of saved Passpoint profiles that have ever resulted
1610      *                             in a successful network connection
1611      */
updateSavedPasspointProfiles(int numSavedProfiles, int numConnectedProfiles)1612     public void updateSavedPasspointProfiles(int numSavedProfiles, int numConnectedProfiles) {
1613         synchronized (mLock) {
1614             mWifiLogProto.numPasspointProviders = numSavedProfiles;
1615             mWifiLogProto.numPasspointProvidersSuccessfullyConnected = numConnectedProfiles;
1616         }
1617     }
1618 
1619     /**
1620      * append the separate ConnectionEvent, SystemStateEntry and ScanReturnCode collections to their
1621      * respective lists within mWifiLogProto
1622      *
1623      * @param incremental Only include ConnectionEvents created since last automatic bug report
1624      */
consolidateProto(boolean incremental)1625     private void consolidateProto(boolean incremental) {
1626         List<WifiMetricsProto.ConnectionEvent> events = new ArrayList<>();
1627         List<WifiMetricsProto.RssiPollCount> rssis = new ArrayList<>();
1628         List<WifiMetricsProto.RssiPollCount> rssiDeltas = new ArrayList<>();
1629         List<WifiMetricsProto.AlertReasonCount> alertReasons = new ArrayList<>();
1630         List<WifiMetricsProto.WifiScoreCount> scores = new ArrayList<>();
1631         synchronized (mLock) {
1632             for (ConnectionEvent event : mConnectionEventList) {
1633                 // If this is not incremental, dump full ConnectionEvent list
1634                 // Else Dump all un-dumped events except for the current one
1635                 if (!incremental || ((mCurrentConnectionEvent != event)
1636                         && !event.mConnectionEvent.automaticBugReportTaken)) {
1637                     //Get all ConnectionEvents that haven not been dumped as a proto, also exclude
1638                     //the current active un-ended connection event
1639                     events.add(event.mConnectionEvent);
1640                     if (incremental) {
1641                         event.mConnectionEvent.automaticBugReportTaken = true;
1642                     }
1643                 }
1644             }
1645             if (events.size() > 0) {
1646                 mWifiLogProto.connectionEvent = events.toArray(mWifiLogProto.connectionEvent);
1647             }
1648 
1649             //Convert the SparseIntArray of scanReturnEntry integers into ScanReturnEntry proto list
1650             mWifiLogProto.scanReturnEntries =
1651                     new WifiMetricsProto.WifiLog.ScanReturnEntry[mScanReturnEntries.size()];
1652             for (int i = 0; i < mScanReturnEntries.size(); i++) {
1653                 mWifiLogProto.scanReturnEntries[i] = new WifiMetricsProto.WifiLog.ScanReturnEntry();
1654                 mWifiLogProto.scanReturnEntries[i].scanReturnCode = mScanReturnEntries.keyAt(i);
1655                 mWifiLogProto.scanReturnEntries[i].scanResultsCount = mScanReturnEntries.valueAt(i);
1656             }
1657 
1658             // Convert the SparseIntArray of systemStateEntry into WifiSystemStateEntry proto list
1659             // This one is slightly more complex, as the Sparse are indexed with:
1660             //     key: wifiState * 2 + isScreenOn, value: wifiStateCount
1661             mWifiLogProto.wifiSystemStateEntries =
1662                     new WifiMetricsProto.WifiLog
1663                     .WifiSystemStateEntry[mWifiSystemStateEntries.size()];
1664             for (int i = 0; i < mWifiSystemStateEntries.size(); i++) {
1665                 mWifiLogProto.wifiSystemStateEntries[i] =
1666                         new WifiMetricsProto.WifiLog.WifiSystemStateEntry();
1667                 mWifiLogProto.wifiSystemStateEntries[i].wifiState =
1668                         mWifiSystemStateEntries.keyAt(i) / 2;
1669                 mWifiLogProto.wifiSystemStateEntries[i].wifiStateCount =
1670                         mWifiSystemStateEntries.valueAt(i);
1671                 mWifiLogProto.wifiSystemStateEntries[i].isScreenOn =
1672                         (mWifiSystemStateEntries.keyAt(i) % 2) > 0;
1673             }
1674             mWifiLogProto.recordDurationSec = (int) ((mClock.getElapsedSinceBootMillis() / 1000)
1675                     - mRecordStartTimeSec);
1676 
1677             /**
1678              * Convert the SparseIntArray of RSSI poll rssi's and counts to the proto's repeated
1679              * IntKeyVal array.
1680              */
1681             for (int i = 0; i < mRssiPollCounts.size(); i++) {
1682                 WifiMetricsProto.RssiPollCount keyVal = new WifiMetricsProto.RssiPollCount();
1683                 keyVal.rssi = mRssiPollCounts.keyAt(i);
1684                 keyVal.count = mRssiPollCounts.valueAt(i);
1685                 rssis.add(keyVal);
1686             }
1687             mWifiLogProto.rssiPollRssiCount = rssis.toArray(mWifiLogProto.rssiPollRssiCount);
1688 
1689             /**
1690              * Convert the SparseIntArray of RSSI delta rssi's and counts to the proto's repeated
1691              * IntKeyVal array.
1692              */
1693             for (int i = 0; i < mRssiDeltaCounts.size(); i++) {
1694                 WifiMetricsProto.RssiPollCount keyVal = new WifiMetricsProto.RssiPollCount();
1695                 keyVal.rssi = mRssiDeltaCounts.keyAt(i);
1696                 keyVal.count = mRssiDeltaCounts.valueAt(i);
1697                 rssiDeltas.add(keyVal);
1698             }
1699             mWifiLogProto.rssiPollDeltaCount = rssiDeltas.toArray(mWifiLogProto.rssiPollDeltaCount);
1700 
1701             /**
1702              * Convert the SparseIntArray of alert reasons and counts to the proto's repeated
1703              * IntKeyVal array.
1704              */
1705             for (int i = 0; i < mWifiAlertReasonCounts.size(); i++) {
1706                 WifiMetricsProto.AlertReasonCount keyVal = new WifiMetricsProto.AlertReasonCount();
1707                 keyVal.reason = mWifiAlertReasonCounts.keyAt(i);
1708                 keyVal.count = mWifiAlertReasonCounts.valueAt(i);
1709                 alertReasons.add(keyVal);
1710             }
1711             mWifiLogProto.alertReasonCount = alertReasons.toArray(mWifiLogProto.alertReasonCount);
1712 
1713             /**
1714             *  Convert the SparseIntArray of Wifi Score and counts to proto's repeated
1715             * IntKeyVal array.
1716             */
1717             for (int score = 0; score < mWifiScoreCounts.size(); score++) {
1718                 WifiMetricsProto.WifiScoreCount keyVal = new WifiMetricsProto.WifiScoreCount();
1719                 keyVal.score = mWifiScoreCounts.keyAt(score);
1720                 keyVal.count = mWifiScoreCounts.valueAt(score);
1721                 scores.add(keyVal);
1722             }
1723             mWifiLogProto.wifiScoreCount = scores.toArray(mWifiLogProto.wifiScoreCount);
1724 
1725             /**
1726              * Convert the SparseIntArray of SoftAp Return codes and counts to proto's repeated
1727              * IntKeyVal array.
1728              */
1729             int codeCounts = mSoftApManagerReturnCodeCounts.size();
1730             mWifiLogProto.softApReturnCode = new WifiMetricsProto.SoftApReturnCodeCount[codeCounts];
1731             for (int sapCode = 0; sapCode < codeCounts; sapCode++) {
1732                 mWifiLogProto.softApReturnCode[sapCode] =
1733                         new WifiMetricsProto.SoftApReturnCodeCount();
1734                 mWifiLogProto.softApReturnCode[sapCode].startResult =
1735                         mSoftApManagerReturnCodeCounts.keyAt(sapCode);
1736                 mWifiLogProto.softApReturnCode[sapCode].count =
1737                         mSoftApManagerReturnCodeCounts.valueAt(sapCode);
1738             }
1739 
1740             /**
1741              * Convert StaEventList to array of StaEvents
1742              */
1743             mWifiLogProto.staEventList = new StaEvent[mStaEventList.size()];
1744             for (int i = 0; i < mStaEventList.size(); i++) {
1745                 mWifiLogProto.staEventList[i] = mStaEventList.get(i).staEvent;
1746             }
1747             mWifiLogProto.totalSsidsInScanHistogram =
1748                     makeNumConnectableNetworksBucketArray(mTotalSsidsInScanHistogram);
1749             mWifiLogProto.totalBssidsInScanHistogram =
1750                     makeNumConnectableNetworksBucketArray(mTotalBssidsInScanHistogram);
1751             mWifiLogProto.availableOpenSsidsInScanHistogram =
1752                     makeNumConnectableNetworksBucketArray(mAvailableOpenSsidsInScanHistogram);
1753             mWifiLogProto.availableOpenBssidsInScanHistogram =
1754                     makeNumConnectableNetworksBucketArray(mAvailableOpenBssidsInScanHistogram);
1755             mWifiLogProto.availableSavedSsidsInScanHistogram =
1756                     makeNumConnectableNetworksBucketArray(mAvailableSavedSsidsInScanHistogram);
1757             mWifiLogProto.availableSavedBssidsInScanHistogram =
1758                     makeNumConnectableNetworksBucketArray(mAvailableSavedBssidsInScanHistogram);
1759             mWifiLogProto.availableOpenOrSavedSsidsInScanHistogram =
1760                     makeNumConnectableNetworksBucketArray(
1761                     mAvailableOpenOrSavedSsidsInScanHistogram);
1762             mWifiLogProto.availableOpenOrSavedBssidsInScanHistogram =
1763                     makeNumConnectableNetworksBucketArray(
1764                     mAvailableOpenOrSavedBssidsInScanHistogram);
1765             mWifiLogProto.availableSavedPasspointProviderProfilesInScanHistogram =
1766                     makeNumConnectableNetworksBucketArray(
1767                     mAvailableSavedPasspointProviderProfilesInScanHistogram);
1768             mWifiLogProto.availableSavedPasspointProviderBssidsInScanHistogram =
1769                     makeNumConnectableNetworksBucketArray(
1770                     mAvailableSavedPasspointProviderBssidsInScanHistogram);
1771             mWifiLogProto.wifiAwareLog = mWifiAwareMetrics.consolidateProto();
1772 
1773             mWifiLogProto.pnoScanMetrics = mPnoScanMetrics;
1774 
1775             /**
1776              * Convert the SparseIntArray of "Connect to Network" notification types and counts to
1777              * proto's repeated IntKeyVal array.
1778              */
1779             ConnectToNetworkNotificationAndActionCount[] notificationCountArray =
1780                     new ConnectToNetworkNotificationAndActionCount[
1781                             mConnectToNetworkNotificationCount.size()];
1782             for (int i = 0; i < mConnectToNetworkNotificationCount.size(); i++) {
1783                 ConnectToNetworkNotificationAndActionCount keyVal =
1784                         new ConnectToNetworkNotificationAndActionCount();
1785                 keyVal.notification = mConnectToNetworkNotificationCount.keyAt(i);
1786                 keyVal.recommender =
1787                         ConnectToNetworkNotificationAndActionCount.RECOMMENDER_OPEN;
1788                 keyVal.count = mConnectToNetworkNotificationCount.valueAt(i);
1789                 notificationCountArray[i] = keyVal;
1790             }
1791             mWifiLogProto.connectToNetworkNotificationCount = notificationCountArray;
1792 
1793             /**
1794              * Convert the SparseIntArray of "Connect to Network" notification types and counts to
1795              * proto's repeated IntKeyVal array.
1796              */
1797             ConnectToNetworkNotificationAndActionCount[] notificationActionCountArray =
1798                     new ConnectToNetworkNotificationAndActionCount[
1799                             mConnectToNetworkNotificationActionCount.size()];
1800             for (int i = 0; i < mConnectToNetworkNotificationActionCount.size(); i++) {
1801                 ConnectToNetworkNotificationAndActionCount keyVal =
1802                         new ConnectToNetworkNotificationAndActionCount();
1803                 int key = mConnectToNetworkNotificationActionCount.keyAt(i);
1804                 keyVal.notification = key / CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER;
1805                 keyVal.action = key % CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER;
1806                 keyVal.recommender =
1807                         ConnectToNetworkNotificationAndActionCount.RECOMMENDER_OPEN;
1808                 keyVal.count = mConnectToNetworkNotificationActionCount.valueAt(i);
1809                 notificationActionCountArray[i] = keyVal;
1810             }
1811             mWifiLogProto.connectToNetworkNotificationActionCount = notificationActionCountArray;
1812 
1813             mWifiLogProto.openNetworkRecommenderBlacklistSize =
1814                     mOpenNetworkRecommenderBlacklistSize;
1815             mWifiLogProto.isWifiNetworksAvailableNotificationOn =
1816                     mIsWifiNetworksAvailableNotificationOn;
1817             mWifiLogProto.numOpenNetworkRecommendationUpdates =
1818                     mNumOpenNetworkRecommendationUpdates;
1819             mWifiLogProto.numOpenNetworkConnectMessageFailedToSend =
1820                     mNumOpenNetworkConnectMessageFailedToSend;
1821         }
1822     }
1823 
makeNumConnectableNetworksBucketArray( SparseIntArray sia)1824     private WifiMetricsProto.NumConnectableNetworksBucket[] makeNumConnectableNetworksBucketArray(
1825             SparseIntArray sia) {
1826         WifiMetricsProto.NumConnectableNetworksBucket[] array =
1827                 new WifiMetricsProto.NumConnectableNetworksBucket[sia.size()];
1828         for (int i = 0; i < sia.size(); i++) {
1829             WifiMetricsProto.NumConnectableNetworksBucket keyVal =
1830                     new WifiMetricsProto.NumConnectableNetworksBucket();
1831             keyVal.numConnectableNetworks = sia.keyAt(i);
1832             keyVal.count = sia.valueAt(i);
1833             array[i] = keyVal;
1834         }
1835         return array;
1836     }
1837 
1838     /**
1839      * Clear all WifiMetrics, except for currentConnectionEvent and Open Network Notification
1840      * feature enabled state, blacklist size.
1841      */
clear()1842     private void clear() {
1843         synchronized (mLock) {
1844             mConnectionEventList.clear();
1845             if (mCurrentConnectionEvent != null) {
1846                 mConnectionEventList.add(mCurrentConnectionEvent);
1847             }
1848             mScanReturnEntries.clear();
1849             mWifiSystemStateEntries.clear();
1850             mRecordStartTimeSec = mClock.getElapsedSinceBootMillis() / 1000;
1851             mRssiPollCounts.clear();
1852             mRssiDeltaCounts.clear();
1853             mWifiAlertReasonCounts.clear();
1854             mWifiScoreCounts.clear();
1855             mWifiLogProto.clear();
1856             mScanResultRssiTimestampMillis = -1;
1857             mSoftApManagerReturnCodeCounts.clear();
1858             mStaEventList.clear();
1859             mWifiAwareMetrics.clear();
1860             mTotalSsidsInScanHistogram.clear();
1861             mTotalBssidsInScanHistogram.clear();
1862             mAvailableOpenSsidsInScanHistogram.clear();
1863             mAvailableOpenBssidsInScanHistogram.clear();
1864             mAvailableSavedSsidsInScanHistogram.clear();
1865             mAvailableSavedBssidsInScanHistogram.clear();
1866             mAvailableOpenOrSavedSsidsInScanHistogram.clear();
1867             mAvailableOpenOrSavedBssidsInScanHistogram.clear();
1868             mAvailableSavedPasspointProviderProfilesInScanHistogram.clear();
1869             mAvailableSavedPasspointProviderBssidsInScanHistogram.clear();
1870             mPnoScanMetrics.clear();
1871             mConnectToNetworkNotificationCount.clear();
1872             mConnectToNetworkNotificationActionCount.clear();
1873             mNumOpenNetworkRecommendationUpdates = 0;
1874             mNumOpenNetworkConnectMessageFailedToSend = 0;
1875         }
1876     }
1877 
1878     /**
1879      *  Set screen state (On/Off)
1880      */
setScreenState(boolean screenOn)1881     public void setScreenState(boolean screenOn) {
1882         synchronized (mLock) {
1883             mScreenOn = screenOn;
1884         }
1885     }
1886 
1887     /**
1888      *  Set wifi state (WIFI_UNKNOWN, WIFI_DISABLED, WIFI_DISCONNECTED, WIFI_ASSOCIATED)
1889      */
setWifiState(int wifiState)1890     public void setWifiState(int wifiState) {
1891         synchronized (mLock) {
1892             mWifiState = wifiState;
1893         }
1894     }
1895 
1896     /**
1897      * Message handler for interesting WifiMonitor messages. Generates StaEvents
1898      */
processMessage(Message msg)1899     private void processMessage(Message msg) {
1900         StaEvent event = new StaEvent();
1901         boolean logEvent = true;
1902         switch (msg.what) {
1903             case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
1904                 event.type = StaEvent.TYPE_ASSOCIATION_REJECTION_EVENT;
1905                 event.associationTimedOut = msg.arg1 > 0 ? true : false;
1906                 event.status = msg.arg2;
1907                 break;
1908             case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
1909                 event.type = StaEvent.TYPE_AUTHENTICATION_FAILURE_EVENT;
1910                 switch (msg.arg2) {
1911                     case WifiManager.ERROR_AUTH_FAILURE_NONE:
1912                         event.authFailureReason = StaEvent.AUTH_FAILURE_NONE;
1913                         break;
1914                     case WifiManager.ERROR_AUTH_FAILURE_TIMEOUT:
1915                         event.authFailureReason = StaEvent.AUTH_FAILURE_TIMEOUT;
1916                         break;
1917                     case WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD:
1918                         event.authFailureReason = StaEvent.AUTH_FAILURE_WRONG_PSWD;
1919                         break;
1920                     case WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE:
1921                         event.authFailureReason = StaEvent.AUTH_FAILURE_EAP_FAILURE;
1922                         break;
1923                     default:
1924                         break;
1925                 }
1926                 break;
1927             case WifiMonitor.NETWORK_CONNECTION_EVENT:
1928                 event.type = StaEvent.TYPE_NETWORK_CONNECTION_EVENT;
1929                 break;
1930             case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
1931                 event.type = StaEvent.TYPE_NETWORK_DISCONNECTION_EVENT;
1932                 event.reason = msg.arg2;
1933                 event.localGen = msg.arg1 == 0 ? false : true;
1934                 break;
1935             case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
1936                 logEvent = false;
1937                 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
1938                 mSupplicantStateChangeBitmask |= supplicantStateToBit(stateChangeResult.state);
1939                 break;
1940             case WifiStateMachine.CMD_ASSOCIATED_BSSID:
1941                 event.type = StaEvent.TYPE_CMD_ASSOCIATED_BSSID;
1942                 break;
1943             case WifiStateMachine.CMD_TARGET_BSSID:
1944                 event.type = StaEvent.TYPE_CMD_TARGET_BSSID;
1945                 break;
1946             default:
1947                 return;
1948         }
1949         if (logEvent) {
1950             addStaEvent(event);
1951         }
1952     }
1953     /**
1954      * Log a StaEvent from WifiStateMachine. The StaEvent must not be one of the supplicant
1955      * generated event types, which are logged through 'sendMessage'
1956      * @param type StaEvent.EventType describing the event
1957      */
logStaEvent(int type)1958     public void logStaEvent(int type) {
1959         logStaEvent(type, StaEvent.DISCONNECT_UNKNOWN, null);
1960     }
1961     /**
1962      * Log a StaEvent from WifiStateMachine. The StaEvent must not be one of the supplicant
1963      * generated event types, which are logged through 'sendMessage'
1964      * @param type StaEvent.EventType describing the event
1965      * @param config WifiConfiguration for a framework initiated connection attempt
1966      */
logStaEvent(int type, WifiConfiguration config)1967     public void logStaEvent(int type, WifiConfiguration config) {
1968         logStaEvent(type, StaEvent.DISCONNECT_UNKNOWN, config);
1969     }
1970     /**
1971      * Log a StaEvent from WifiStateMachine. The StaEvent must not be one of the supplicant
1972      * generated event types, which are logged through 'sendMessage'
1973      * @param type StaEvent.EventType describing the event
1974      * @param frameworkDisconnectReason StaEvent.FrameworkDisconnectReason explaining why framework
1975      *                                  initiated a FRAMEWORK_DISCONNECT
1976      */
logStaEvent(int type, int frameworkDisconnectReason)1977     public void logStaEvent(int type, int frameworkDisconnectReason) {
1978         logStaEvent(type, frameworkDisconnectReason, null);
1979     }
1980     /**
1981      * Log a StaEvent from WifiStateMachine. The StaEvent must not be one of the supplicant
1982      * generated event types, which are logged through 'sendMessage'
1983      * @param type StaEvent.EventType describing the event
1984      * @param frameworkDisconnectReason StaEvent.FrameworkDisconnectReason explaining why framework
1985      *                                  initiated a FRAMEWORK_DISCONNECT
1986      * @param config WifiConfiguration for a framework initiated connection attempt
1987      */
logStaEvent(int type, int frameworkDisconnectReason, WifiConfiguration config)1988     public void logStaEvent(int type, int frameworkDisconnectReason, WifiConfiguration config) {
1989         switch (type) {
1990             case StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL:
1991             case StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST:
1992             case StaEvent.TYPE_CMD_IP_REACHABILITY_LOST:
1993             case StaEvent.TYPE_CMD_START_CONNECT:
1994             case StaEvent.TYPE_CMD_START_ROAM:
1995             case StaEvent.TYPE_CONNECT_NETWORK:
1996             case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK:
1997             case StaEvent.TYPE_FRAMEWORK_DISCONNECT:
1998                 break;
1999             default:
2000                 Log.e(TAG, "Unknown StaEvent:" + type);
2001                 return;
2002         }
2003         StaEvent event = new StaEvent();
2004         event.type = type;
2005         if (frameworkDisconnectReason != StaEvent.DISCONNECT_UNKNOWN) {
2006             event.frameworkDisconnectReason = frameworkDisconnectReason;
2007         }
2008         event.configInfo = createConfigInfo(config);
2009         addStaEvent(event);
2010     }
2011 
addStaEvent(StaEvent staEvent)2012     private void addStaEvent(StaEvent staEvent) {
2013         staEvent.startTimeMillis = mClock.getElapsedSinceBootMillis();
2014         staEvent.lastRssi = mLastPollRssi;
2015         staEvent.lastFreq = mLastPollFreq;
2016         staEvent.lastLinkSpeed = mLastPollLinkSpeed;
2017         staEvent.supplicantStateChangesBitmask = mSupplicantStateChangeBitmask;
2018         mSupplicantStateChangeBitmask = 0;
2019         mLastPollRssi = -127;
2020         mLastPollFreq = -1;
2021         mLastPollLinkSpeed = -1;
2022         mStaEventList.add(new StaEventWithTime(staEvent, mClock.getWallClockMillis()));
2023         // Prune StaEventList if it gets too long
2024         if (mStaEventList.size() > MAX_STA_EVENTS) mStaEventList.remove();
2025     }
2026 
createConfigInfo(WifiConfiguration config)2027     private ConfigInfo createConfigInfo(WifiConfiguration config) {
2028         if (config == null) return null;
2029         ConfigInfo info = new ConfigInfo();
2030         info.allowedKeyManagement = bitSetToInt(config.allowedKeyManagement);
2031         info.allowedProtocols = bitSetToInt(config.allowedProtocols);
2032         info.allowedAuthAlgorithms = bitSetToInt(config.allowedAuthAlgorithms);
2033         info.allowedPairwiseCiphers = bitSetToInt(config.allowedPairwiseCiphers);
2034         info.allowedGroupCiphers = bitSetToInt(config.allowedGroupCiphers);
2035         info.hiddenSsid = config.hiddenSSID;
2036         info.isPasspoint = config.isPasspoint();
2037         info.isEphemeral = config.isEphemeral();
2038         info.hasEverConnected = config.getNetworkSelectionStatus().getHasEverConnected();
2039         ScanResult candidate = config.getNetworkSelectionStatus().getCandidate();
2040         if (candidate != null) {
2041             info.scanRssi = candidate.level;
2042             info.scanFreq = candidate.frequency;
2043         }
2044         return info;
2045     }
2046 
getHandler()2047     public Handler getHandler() {
2048         return mHandler;
2049     }
2050 
getWifiAwareMetrics()2051     public WifiAwareMetrics getWifiAwareMetrics() {
2052         return mWifiAwareMetrics;
2053     }
2054 
2055     // Rather than generate a StaEvent for each SUPPLICANT_STATE_CHANGE, cache these in a bitmask
2056     // and attach it to the next event which is generated.
2057     private int mSupplicantStateChangeBitmask = 0;
2058 
2059     /**
2060      * Converts a SupplicantState value to a single bit, with position defined by
2061      * {@code StaEvent.SupplicantState}
2062      */
supplicantStateToBit(SupplicantState state)2063     public static int supplicantStateToBit(SupplicantState state) {
2064         switch(state) {
2065             case DISCONNECTED:
2066                 return 1 << StaEvent.STATE_DISCONNECTED;
2067             case INTERFACE_DISABLED:
2068                 return 1 << StaEvent.STATE_INTERFACE_DISABLED;
2069             case INACTIVE:
2070                 return 1 << StaEvent.STATE_INACTIVE;
2071             case SCANNING:
2072                 return 1 << StaEvent.STATE_SCANNING;
2073             case AUTHENTICATING:
2074                 return 1 << StaEvent.STATE_AUTHENTICATING;
2075             case ASSOCIATING:
2076                 return 1 << StaEvent.STATE_ASSOCIATING;
2077             case ASSOCIATED:
2078                 return 1 << StaEvent.STATE_ASSOCIATED;
2079             case FOUR_WAY_HANDSHAKE:
2080                 return 1 << StaEvent.STATE_FOUR_WAY_HANDSHAKE;
2081             case GROUP_HANDSHAKE:
2082                 return 1 << StaEvent.STATE_GROUP_HANDSHAKE;
2083             case COMPLETED:
2084                 return 1 << StaEvent.STATE_COMPLETED;
2085             case DORMANT:
2086                 return 1 << StaEvent.STATE_DORMANT;
2087             case UNINITIALIZED:
2088                 return 1 << StaEvent.STATE_UNINITIALIZED;
2089             case INVALID:
2090                 return 1 << StaEvent.STATE_INVALID;
2091             default:
2092                 Log.wtf(TAG, "Got unknown supplicant state: " + state.ordinal());
2093                 return 0;
2094         }
2095     }
2096 
supplicantStateChangesBitmaskToString(int mask)2097     private static String supplicantStateChangesBitmaskToString(int mask) {
2098         StringBuilder sb = new StringBuilder();
2099         sb.append("supplicantStateChangeEvents: {");
2100         if ((mask & (1 << StaEvent.STATE_DISCONNECTED)) > 0) sb.append(" DISCONNECTED");
2101         if ((mask & (1 << StaEvent.STATE_INTERFACE_DISABLED)) > 0) sb.append(" INTERFACE_DISABLED");
2102         if ((mask & (1 << StaEvent.STATE_INACTIVE)) > 0) sb.append(" INACTIVE");
2103         if ((mask & (1 << StaEvent.STATE_SCANNING)) > 0) sb.append(" SCANNING");
2104         if ((mask & (1 << StaEvent.STATE_AUTHENTICATING)) > 0) sb.append(" AUTHENTICATING");
2105         if ((mask & (1 << StaEvent.STATE_ASSOCIATING)) > 0) sb.append(" ASSOCIATING");
2106         if ((mask & (1 << StaEvent.STATE_ASSOCIATED)) > 0) sb.append(" ASSOCIATED");
2107         if ((mask & (1 << StaEvent.STATE_FOUR_WAY_HANDSHAKE)) > 0) sb.append(" FOUR_WAY_HANDSHAKE");
2108         if ((mask & (1 << StaEvent.STATE_GROUP_HANDSHAKE)) > 0) sb.append(" GROUP_HANDSHAKE");
2109         if ((mask & (1 << StaEvent.STATE_COMPLETED)) > 0) sb.append(" COMPLETED");
2110         if ((mask & (1 << StaEvent.STATE_DORMANT)) > 0) sb.append(" DORMANT");
2111         if ((mask & (1 << StaEvent.STATE_UNINITIALIZED)) > 0) sb.append(" UNINITIALIZED");
2112         if ((mask & (1 << StaEvent.STATE_INVALID)) > 0) sb.append(" INVALID");
2113         sb.append("}");
2114         return sb.toString();
2115     }
2116 
2117     /**
2118      * Returns a human readable string from a Sta Event. Only adds information relevant to the event
2119      * type.
2120      */
staEventToString(StaEvent event)2121     public static String staEventToString(StaEvent event) {
2122         if (event == null) return "<NULL>";
2123         StringBuilder sb = new StringBuilder();
2124         switch (event.type) {
2125             case StaEvent.TYPE_ASSOCIATION_REJECTION_EVENT:
2126                 sb.append("ASSOCIATION_REJECTION_EVENT")
2127                         .append(" timedOut=").append(event.associationTimedOut)
2128                         .append(" status=").append(event.status).append(":")
2129                         .append(ISupplicantStaIfaceCallback.StatusCode.toString(event.status));
2130                 break;
2131             case StaEvent.TYPE_AUTHENTICATION_FAILURE_EVENT:
2132                 sb.append("AUTHENTICATION_FAILURE_EVENT reason=").append(event.authFailureReason)
2133                         .append(":").append(authFailureReasonToString(event.authFailureReason));
2134                 break;
2135             case StaEvent.TYPE_NETWORK_CONNECTION_EVENT:
2136                 sb.append("NETWORK_CONNECTION_EVENT");
2137                 break;
2138             case StaEvent.TYPE_NETWORK_DISCONNECTION_EVENT:
2139                 sb.append("NETWORK_DISCONNECTION_EVENT")
2140                         .append(" local_gen=").append(event.localGen)
2141                         .append(" reason=").append(event.reason).append(":")
2142                         .append(ISupplicantStaIfaceCallback.ReasonCode.toString(
2143                                 (event.reason >= 0 ? event.reason : -1 * event.reason)));
2144                 break;
2145             case StaEvent.TYPE_CMD_ASSOCIATED_BSSID:
2146                 sb.append("CMD_ASSOCIATED_BSSID");
2147                 break;
2148             case StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL:
2149                 sb.append("CMD_IP_CONFIGURATION_SUCCESSFUL");
2150                 break;
2151             case StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST:
2152                 sb.append("CMD_IP_CONFIGURATION_LOST");
2153                 break;
2154             case StaEvent.TYPE_CMD_IP_REACHABILITY_LOST:
2155                 sb.append("CMD_IP_REACHABILITY_LOST");
2156                 break;
2157             case StaEvent.TYPE_CMD_TARGET_BSSID:
2158                 sb.append("CMD_TARGET_BSSID");
2159                 break;
2160             case StaEvent.TYPE_CMD_START_CONNECT:
2161                 sb.append("CMD_START_CONNECT");
2162                 break;
2163             case StaEvent.TYPE_CMD_START_ROAM:
2164                 sb.append("CMD_START_ROAM");
2165                 break;
2166             case StaEvent.TYPE_CONNECT_NETWORK:
2167                 sb.append("CONNECT_NETWORK");
2168                 break;
2169             case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK:
2170                 sb.append("NETWORK_AGENT_VALID_NETWORK");
2171                 break;
2172             case StaEvent.TYPE_FRAMEWORK_DISCONNECT:
2173                 sb.append("FRAMEWORK_DISCONNECT")
2174                         .append(" reason=")
2175                         .append(frameworkDisconnectReasonToString(event.frameworkDisconnectReason));
2176                 break;
2177             default:
2178                 sb.append("UNKNOWN " + event.type + ":");
2179                 break;
2180         }
2181         if (event.lastRssi != -127) sb.append(" lastRssi=").append(event.lastRssi);
2182         if (event.lastFreq != -1) sb.append(" lastFreq=").append(event.lastFreq);
2183         if (event.lastLinkSpeed != -1) sb.append(" lastLinkSpeed=").append(event.lastLinkSpeed);
2184         if (event.supplicantStateChangesBitmask != 0) {
2185             sb.append(", ").append(supplicantStateChangesBitmaskToString(
2186                     event.supplicantStateChangesBitmask));
2187         }
2188         if (event.configInfo != null) {
2189             sb.append(", ").append(configInfoToString(event.configInfo));
2190         }
2191 
2192         return sb.toString();
2193     }
2194 
authFailureReasonToString(int authFailureReason)2195     private static String authFailureReasonToString(int authFailureReason) {
2196         switch (authFailureReason) {
2197             case StaEvent.AUTH_FAILURE_NONE:
2198                 return "ERROR_AUTH_FAILURE_NONE";
2199             case StaEvent.AUTH_FAILURE_TIMEOUT:
2200                 return "ERROR_AUTH_FAILURE_TIMEOUT";
2201             case StaEvent.AUTH_FAILURE_WRONG_PSWD:
2202                 return "ERROR_AUTH_FAILURE_WRONG_PSWD";
2203             case StaEvent.AUTH_FAILURE_EAP_FAILURE:
2204                 return "ERROR_AUTH_FAILURE_EAP_FAILURE";
2205             default:
2206                 return "";
2207         }
2208     }
2209 
frameworkDisconnectReasonToString(int frameworkDisconnectReason)2210     private static String frameworkDisconnectReasonToString(int frameworkDisconnectReason) {
2211         switch (frameworkDisconnectReason) {
2212             case StaEvent.DISCONNECT_API:
2213                 return "DISCONNECT_API";
2214             case StaEvent.DISCONNECT_GENERIC:
2215                 return "DISCONNECT_GENERIC";
2216             case StaEvent.DISCONNECT_UNWANTED:
2217                 return "DISCONNECT_UNWANTED";
2218             case StaEvent.DISCONNECT_ROAM_WATCHDOG_TIMER:
2219                 return "DISCONNECT_ROAM_WATCHDOG_TIMER";
2220             case StaEvent.DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST:
2221                 return "DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST";
2222             case StaEvent.DISCONNECT_RESET_SIM_NETWORKS:
2223                 return "DISCONNECT_RESET_SIM_NETWORKS";
2224             default:
2225                 return "DISCONNECT_UNKNOWN=" + frameworkDisconnectReason;
2226         }
2227     }
2228 
configInfoToString(ConfigInfo info)2229     private static String configInfoToString(ConfigInfo info) {
2230         StringBuilder sb = new StringBuilder();
2231         sb.append("ConfigInfo:")
2232                 .append(" allowed_key_management=").append(info.allowedKeyManagement)
2233                 .append(" allowed_protocols=").append(info.allowedProtocols)
2234                 .append(" allowed_auth_algorithms=").append(info.allowedAuthAlgorithms)
2235                 .append(" allowed_pairwise_ciphers=").append(info.allowedPairwiseCiphers)
2236                 .append(" allowed_group_ciphers=").append(info.allowedGroupCiphers)
2237                 .append(" hidden_ssid=").append(info.hiddenSsid)
2238                 .append(" is_passpoint=").append(info.isPasspoint)
2239                 .append(" is_ephemeral=").append(info.isEphemeral)
2240                 .append(" has_ever_connected=").append(info.hasEverConnected)
2241                 .append(" scan_rssi=").append(info.scanRssi)
2242                 .append(" scan_freq=").append(info.scanFreq);
2243         return sb.toString();
2244     }
2245 
2246     public static final int MAX_STA_EVENTS = 512;
2247     private LinkedList<StaEventWithTime> mStaEventList = new LinkedList<StaEventWithTime>();
2248     private int mLastPollRssi = -127;
2249     private int mLastPollLinkSpeed = -1;
2250     private int mLastPollFreq = -1;
2251 
2252     /**
2253      * Converts the first 31 bits of a BitSet to a little endian int
2254      */
bitSetToInt(BitSet bits)2255     private static int bitSetToInt(BitSet bits) {
2256         int value = 0;
2257         int nBits = bits.length() < 31 ? bits.length() : 31;
2258         for (int i = 0; i < nBits; i++) {
2259             value += bits.get(i) ? (1 << i) : 0;
2260         }
2261         return value;
2262     }
2263     private void incrementSsid(SparseIntArray sia, int element) {
2264         increment(sia, Math.min(element, MAX_CONNECTABLE_SSID_NETWORK_BUCKET));
2265     }
2266     private void incrementBssid(SparseIntArray sia, int element) {
2267         increment(sia, Math.min(element, MAX_CONNECTABLE_BSSID_NETWORK_BUCKET));
2268     }
2269     private void incrementTotalScanResults(SparseIntArray sia, int element) {
2270         increment(sia, Math.min(element, MAX_TOTAL_SCAN_RESULTS_BUCKET));
2271     }
2272     private void incrementTotalScanSsids(SparseIntArray sia, int element) {
2273         increment(sia, Math.min(element, MAX_TOTAL_SCAN_RESULT_SSIDS_BUCKET));
2274     }
2275     private void increment(SparseIntArray sia, int element) {
2276         int count = sia.get(element);
2277         sia.put(element, count + 1);
2278     }
2279 
2280     private static class StaEventWithTime {
2281         public StaEvent staEvent;
2282         public long wallClockMillis;
2283 
2284         StaEventWithTime(StaEvent event, long wallClockMillis) {
2285             staEvent = event;
2286             this.wallClockMillis = wallClockMillis;
2287         }
2288 
2289         public String toString() {
2290             StringBuilder sb = new StringBuilder();
2291             Calendar c = Calendar.getInstance();
2292             c.setTimeInMillis(wallClockMillis);
2293             if (wallClockMillis != 0) {
2294                 sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
2295             } else {
2296                 sb.append("                  ");
2297             }
2298             sb.append(" ").append(staEventToString(staEvent));
2299             return sb.toString();
2300         }
2301     }
2302 }
2303