Home | History | Annotate | Download | only in wifi
      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.internal.annotations.VisibleForTesting;
     35 import com.android.server.wifi.aware.WifiAwareMetrics;
     36 import com.android.server.wifi.hotspot2.ANQPNetworkKey;
     37 import com.android.server.wifi.hotspot2.NetworkDetail;
     38 import com.android.server.wifi.hotspot2.PasspointManager;
     39 import com.android.server.wifi.hotspot2.PasspointMatch;
     40 import com.android.server.wifi.hotspot2.PasspointProvider;
     41 import com.android.server.wifi.hotspot2.Utils;
     42 import com.android.server.wifi.nano.WifiMetricsProto;
     43 import com.android.server.wifi.nano.WifiMetricsProto.ConnectToNetworkNotificationAndActionCount;
     44 import com.android.server.wifi.nano.WifiMetricsProto.PnoScanMetrics;
     45 import com.android.server.wifi.nano.WifiMetricsProto.SoftApConnectedClientsEvent;
     46 import com.android.server.wifi.nano.WifiMetricsProto.StaEvent;
     47 import com.android.server.wifi.nano.WifiMetricsProto.StaEvent.ConfigInfo;
     48 import com.android.server.wifi.nano.WifiMetricsProto.WpsMetrics;
     49 import com.android.server.wifi.rtt.RttMetrics;
     50 import com.android.server.wifi.util.InformationElementUtil;
     51 import com.android.server.wifi.util.ScanResultUtil;
     52 
     53 import org.json.JSONArray;
     54 import org.json.JSONException;
     55 import org.json.JSONObject;
     56 
     57 import java.io.FileDescriptor;
     58 import java.io.PrintWriter;
     59 import java.util.ArrayList;
     60 import java.util.BitSet;
     61 import java.util.Calendar;
     62 import java.util.HashMap;
     63 import java.util.HashSet;
     64 import java.util.LinkedList;
     65 import java.util.List;
     66 import java.util.Map;
     67 import java.util.Set;
     68 
     69 /**
     70  * Provides storage for wireless connectivity metrics, as they are generated.
     71  * Metrics logged by this class include:
     72  *   Aggregated connection stats (num of connections, num of failures, ...)
     73  *   Discrete connection event stats (time, duration, failure codes, ...)
     74  *   Router details (technology type, authentication type, ...)
     75  *   Scan stats
     76  */
     77 public class WifiMetrics {
     78     private static final String TAG = "WifiMetrics";
     79     private static final boolean DBG = false;
     80     /**
     81      * Clamp the RSSI poll counts to values between [MIN,MAX]_RSSI_POLL
     82      */
     83     private static final int MAX_RSSI_POLL = 0;
     84     private static final int MIN_RSSI_POLL = -127;
     85     public static final int MAX_RSSI_DELTA = 127;
     86     public static final int MIN_RSSI_DELTA = -127;
     87     /** Maximum time period between ScanResult and RSSI poll to generate rssi delta datapoint */
     88     public static final long TIMEOUT_RSSI_DELTA_MILLIS =  3000;
     89     private static final int MIN_WIFI_SCORE = 0;
     90     private static final int MAX_WIFI_SCORE = NetworkAgent.WIFI_BASE_SCORE;
     91     @VisibleForTesting
     92     static final int LOW_WIFI_SCORE = 50; // Mobile data score
     93     private final Object mLock = new Object();
     94     private static final int MAX_CONNECTION_EVENTS = 256;
     95     // Largest bucket in the NumConnectableNetworkCount histogram,
     96     // anything large will be stored in this bucket
     97     public static final int MAX_CONNECTABLE_SSID_NETWORK_BUCKET = 20;
     98     public static final int MAX_CONNECTABLE_BSSID_NETWORK_BUCKET = 50;
     99     public static final int MAX_TOTAL_SCAN_RESULT_SSIDS_BUCKET = 100;
    100     public static final int MAX_TOTAL_SCAN_RESULTS_BUCKET = 250;
    101     public static final int MAX_TOTAL_PASSPOINT_APS_BUCKET = 50;
    102     public static final int MAX_TOTAL_PASSPOINT_UNIQUE_ESS_BUCKET = 20;
    103     public static final int MAX_PASSPOINT_APS_PER_UNIQUE_ESS_BUCKET = 50;
    104     public static final int MAX_TOTAL_80211MC_APS_BUCKET = 20;
    105     private static final int CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER = 1000;
    106     // Max limit for number of soft AP related events, extra events will be dropped.
    107     private static final int MAX_NUM_SOFT_AP_EVENTS = 256;
    108     private Clock mClock;
    109     private boolean mScreenOn;
    110     private int mWifiState;
    111     private WifiAwareMetrics mWifiAwareMetrics;
    112     private RttMetrics mRttMetrics;
    113     private final PnoScanMetrics mPnoScanMetrics = new PnoScanMetrics();
    114     private final WpsMetrics mWpsMetrics = new WpsMetrics();
    115     private Handler mHandler;
    116     private ScoringParams mScoringParams;
    117     private WifiConfigManager mWifiConfigManager;
    118     private WifiNetworkSelector mWifiNetworkSelector;
    119     private PasspointManager mPasspointManager;
    120     /**
    121      * Metrics are stored within an instance of the WifiLog proto during runtime,
    122      * The ConnectionEvent, SystemStateEntries & ScanReturnEntries metrics are stored during
    123      * runtime in member lists of this WifiMetrics class, with the final WifiLog proto being pieced
    124      * together at dump-time
    125      */
    126     private final WifiMetricsProto.WifiLog mWifiLogProto = new WifiMetricsProto.WifiLog();
    127     /**
    128      * Session information that gets logged for every Wifi connection attempt.
    129      */
    130     private final List<ConnectionEvent> mConnectionEventList = new ArrayList<>();
    131     /**
    132      * The latest started (but un-ended) connection attempt
    133      */
    134     private ConnectionEvent mCurrentConnectionEvent;
    135     /**
    136      * Count of number of times each scan return code, indexed by WifiLog.ScanReturnCode
    137      */
    138     private final SparseIntArray mScanReturnEntries = new SparseIntArray();
    139     /**
    140      * Mapping of system state to the counts of scans requested in that wifi state * screenOn
    141      * combination. Indexed by WifiLog.WifiState * (1 + screenOn)
    142      */
    143     private final SparseIntArray mWifiSystemStateEntries = new SparseIntArray();
    144     /** Mapping of channel frequency to its RSSI distribution histogram **/
    145     private final Map<Integer, SparseIntArray> mRssiPollCountsMap = new HashMap<>();
    146     /** Mapping of RSSI scan-poll delta values to counts. */
    147     private final SparseIntArray mRssiDeltaCounts = new SparseIntArray();
    148     /** RSSI of the scan result for the last connection event*/
    149     private int mScanResultRssi = 0;
    150     /** Boot-relative timestamp when the last candidate scanresult was received, used to calculate
    151         RSSI deltas. -1 designates no candidate scanResult being tracked */
    152     private long mScanResultRssiTimestampMillis = -1;
    153     /** Mapping of alert reason to the respective alert count. */
    154     private final SparseIntArray mWifiAlertReasonCounts = new SparseIntArray();
    155     /**
    156      * Records the getElapsedSinceBootMillis (in seconds) that represents the beginning of data
    157      * capture for for this WifiMetricsProto
    158      */
    159     private long mRecordStartTimeSec;
    160     /** Mapping of Wifi Scores to counts */
    161     private final SparseIntArray mWifiScoreCounts = new SparseIntArray();
    162     /** Mapping of SoftApManager start SoftAp return codes to counts */
    163     private final SparseIntArray mSoftApManagerReturnCodeCounts = new SparseIntArray();
    164 
    165     private final SparseIntArray mTotalSsidsInScanHistogram = new SparseIntArray();
    166     private final SparseIntArray mTotalBssidsInScanHistogram = new SparseIntArray();
    167     private final SparseIntArray mAvailableOpenSsidsInScanHistogram = new SparseIntArray();
    168     private final SparseIntArray mAvailableOpenBssidsInScanHistogram = new SparseIntArray();
    169     private final SparseIntArray mAvailableSavedSsidsInScanHistogram = new SparseIntArray();
    170     private final SparseIntArray mAvailableSavedBssidsInScanHistogram = new SparseIntArray();
    171     private final SparseIntArray mAvailableOpenOrSavedSsidsInScanHistogram = new SparseIntArray();
    172     private final SparseIntArray mAvailableOpenOrSavedBssidsInScanHistogram = new SparseIntArray();
    173     private final SparseIntArray mAvailableSavedPasspointProviderProfilesInScanHistogram =
    174             new SparseIntArray();
    175     private final SparseIntArray mAvailableSavedPasspointProviderBssidsInScanHistogram =
    176             new SparseIntArray();
    177 
    178     /** Mapping of "Connect to Network" notifications to counts. */
    179     private final SparseIntArray mConnectToNetworkNotificationCount = new SparseIntArray();
    180     /** Mapping of "Connect to Network" notification user actions to counts. */
    181     private final SparseIntArray mConnectToNetworkNotificationActionCount = new SparseIntArray();
    182     private int mOpenNetworkRecommenderBlacklistSize = 0;
    183     private boolean mIsWifiNetworksAvailableNotificationOn = false;
    184     private int mNumOpenNetworkConnectMessageFailedToSend = 0;
    185     private int mNumOpenNetworkRecommendationUpdates = 0;
    186     /** List of soft AP events related to number of connected clients in tethered mode */
    187     private final List<SoftApConnectedClientsEvent> mSoftApEventListTethered = new ArrayList<>();
    188     /** List of soft AP events related to number of connected clients in local only mode */
    189     private final List<SoftApConnectedClientsEvent> mSoftApEventListLocalOnly = new ArrayList<>();
    190 
    191     private final SparseIntArray mObservedHotspotR1ApInScanHistogram = new SparseIntArray();
    192     private final SparseIntArray mObservedHotspotR2ApInScanHistogram = new SparseIntArray();
    193     private final SparseIntArray mObservedHotspotR1EssInScanHistogram = new SparseIntArray();
    194     private final SparseIntArray mObservedHotspotR2EssInScanHistogram = new SparseIntArray();
    195     private final SparseIntArray mObservedHotspotR1ApsPerEssInScanHistogram = new SparseIntArray();
    196     private final SparseIntArray mObservedHotspotR2ApsPerEssInScanHistogram = new SparseIntArray();
    197 
    198     private final SparseIntArray mObserved80211mcApInScanHistogram = new SparseIntArray();
    199 
    200     /** Wifi power metrics*/
    201     private WifiPowerMetrics mWifiPowerMetrics = new WifiPowerMetrics();
    202 
    203     /** Wifi Wake metrics */
    204     private final WifiWakeMetrics mWifiWakeMetrics = new WifiWakeMetrics();
    205 
    206     private boolean mIsMacRandomizationOn = false;
    207 
    208     class RouterFingerPrint {
    209         private WifiMetricsProto.RouterFingerPrint mRouterFingerPrintProto;
    210         RouterFingerPrint() {
    211             mRouterFingerPrintProto = new WifiMetricsProto.RouterFingerPrint();
    212         }
    213 
    214         public String toString() {
    215             StringBuilder sb = new StringBuilder();
    216             synchronized (mLock) {
    217                 sb.append("mConnectionEvent.roamType=" + mRouterFingerPrintProto.roamType);
    218                 sb.append(", mChannelInfo=" + mRouterFingerPrintProto.channelInfo);
    219                 sb.append(", mDtim=" + mRouterFingerPrintProto.dtim);
    220                 sb.append(", mAuthentication=" + mRouterFingerPrintProto.authentication);
    221                 sb.append(", mHidden=" + mRouterFingerPrintProto.hidden);
    222                 sb.append(", mRouterTechnology=" + mRouterFingerPrintProto.routerTechnology);
    223                 sb.append(", mSupportsIpv6=" + mRouterFingerPrintProto.supportsIpv6);
    224             }
    225             return sb.toString();
    226         }
    227         public void updateFromWifiConfiguration(WifiConfiguration config) {
    228             synchronized (mLock) {
    229                 if (config != null) {
    230                     // Is this a hidden network
    231                     mRouterFingerPrintProto.hidden = config.hiddenSSID;
    232                     // Config may not have a valid dtimInterval set yet, in which case dtim will be zero
    233                     // (These are only populated from beacon frame scan results, which are returned as
    234                     // scan results from the chip far less frequently than Probe-responses)
    235                     if (config.dtimInterval > 0) {
    236                         mRouterFingerPrintProto.dtim = config.dtimInterval;
    237                     }
    238                     mCurrentConnectionEvent.mConfigSsid = config.SSID;
    239                     // Get AuthType information from config (We do this again from ScanResult after
    240                     // associating with BSSID)
    241                     if (config.allowedKeyManagement != null
    242                             && config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) {
    243                         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
    244                                 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_OPEN;
    245                     } else if (config.isEnterprise()) {
    246                         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
    247                                 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE;
    248                     } else {
    249                         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
    250                                 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL;
    251                     }
    252                     mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
    253                             .passpoint = config.isPasspoint();
    254                     // If there's a ScanResult candidate associated with this config already, get it and
    255                     // log (more accurate) metrics from it
    256                     ScanResult candidate = config.getNetworkSelectionStatus().getCandidate();
    257                     if (candidate != null) {
    258                         updateMetricsFromScanResult(candidate);
    259                     }
    260                 }
    261             }
    262         }
    263     }
    264 
    265     /**
    266      * Log event, tracking the start time, end time and result of a wireless connection attempt.
    267      */
    268     class ConnectionEvent {
    269         WifiMetricsProto.ConnectionEvent mConnectionEvent;
    270         //<TODO> Move these constants into a wifi.proto Enum, and create a new Failure Type field
    271         //covering more than just l2 failures. see b/27652362
    272         /**
    273          * Failure codes, used for the 'level_2_failure_code' Connection event field (covers a lot
    274          * more failures than just l2 though, since the proto does not have a place to log
    275          * framework failures)
    276          */
    277         // Failure is unknown
    278         public static final int FAILURE_UNKNOWN = 0;
    279         // NONE
    280         public static final int FAILURE_NONE = 1;
    281         // ASSOCIATION_REJECTION_EVENT
    282         public static final int FAILURE_ASSOCIATION_REJECTION = 2;
    283         // AUTHENTICATION_FAILURE_EVENT
    284         public static final int FAILURE_AUTHENTICATION_FAILURE = 3;
    285         // SSID_TEMP_DISABLED (Also Auth failure)
    286         public static final int FAILURE_SSID_TEMP_DISABLED = 4;
    287         // reconnect() or reassociate() call to WifiNative failed
    288         public static final int FAILURE_CONNECT_NETWORK_FAILED = 5;
    289         // NETWORK_DISCONNECTION_EVENT
    290         public static final int FAILURE_NETWORK_DISCONNECTION = 6;
    291         // NEW_CONNECTION_ATTEMPT before previous finished
    292         public static final int FAILURE_NEW_CONNECTION_ATTEMPT = 7;
    293         // New connection attempt to the same network & bssid
    294         public static final int FAILURE_REDUNDANT_CONNECTION_ATTEMPT = 8;
    295         // Roam Watchdog timer triggered (Roaming timed out)
    296         public static final int FAILURE_ROAM_TIMEOUT = 9;
    297         // DHCP failure
    298         public static final int FAILURE_DHCP = 10;
    299         // ASSOCIATION_TIMED_OUT
    300         public static final int FAILURE_ASSOCIATION_TIMED_OUT = 11;
    301 
    302         RouterFingerPrint mRouterFingerPrint;
    303         private long mRealStartTime;
    304         private long mRealEndTime;
    305         private String mConfigSsid;
    306         private String mConfigBssid;
    307         private int mWifiState;
    308         private boolean mScreenOn;
    309 
    310         private ConnectionEvent() {
    311             mConnectionEvent = new WifiMetricsProto.ConnectionEvent();
    312             mRealEndTime = 0;
    313             mRealStartTime = 0;
    314             mRouterFingerPrint = new RouterFingerPrint();
    315             mConnectionEvent.routerFingerprint = mRouterFingerPrint.mRouterFingerPrintProto;
    316             mConfigSsid = "<NULL>";
    317             mConfigBssid = "<NULL>";
    318             mWifiState = WifiMetricsProto.WifiLog.WIFI_UNKNOWN;
    319             mScreenOn = false;
    320         }
    321 
    322         public String toString() {
    323             StringBuilder sb = new StringBuilder();
    324             sb.append("startTime=");
    325             Calendar c = Calendar.getInstance();
    326             synchronized (mLock) {
    327                 c.setTimeInMillis(mConnectionEvent.startTimeMillis);
    328                 sb.append(mConnectionEvent.startTimeMillis == 0 ? "            <null>" :
    329                         String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
    330                 sb.append(", SSID=");
    331                 sb.append(mConfigSsid);
    332                 sb.append(", BSSID=");
    333                 sb.append(mConfigBssid);
    334                 sb.append(", durationMillis=");
    335                 sb.append(mConnectionEvent.durationTakenToConnectMillis);
    336                 sb.append(", roamType=");
    337                 switch(mConnectionEvent.roamType) {
    338                     case 1:
    339                         sb.append("ROAM_NONE");
    340                         break;
    341                     case 2:
    342                         sb.append("ROAM_DBDC");
    343                         break;
    344                     case 3:
    345                         sb.append("ROAM_ENTERPRISE");
    346                         break;
    347                     case 4:
    348                         sb.append("ROAM_USER_SELECTED");
    349                         break;
    350                     case 5:
    351                         sb.append("ROAM_UNRELATED");
    352                         break;
    353                     default:
    354                         sb.append("ROAM_UNKNOWN");
    355                 }
    356                 sb.append(", connectionResult=");
    357                 sb.append(mConnectionEvent.connectionResult);
    358                 sb.append(", level2FailureCode=");
    359                 switch(mConnectionEvent.level2FailureCode) {
    360                     case FAILURE_NONE:
    361                         sb.append("NONE");
    362                         break;
    363                     case FAILURE_ASSOCIATION_REJECTION:
    364                         sb.append("ASSOCIATION_REJECTION");
    365                         break;
    366                     case FAILURE_AUTHENTICATION_FAILURE:
    367                         sb.append("AUTHENTICATION_FAILURE");
    368                         break;
    369                     case FAILURE_SSID_TEMP_DISABLED:
    370                         sb.append("SSID_TEMP_DISABLED");
    371                         break;
    372                     case FAILURE_CONNECT_NETWORK_FAILED:
    373                         sb.append("CONNECT_NETWORK_FAILED");
    374                         break;
    375                     case FAILURE_NETWORK_DISCONNECTION:
    376                         sb.append("NETWORK_DISCONNECTION");
    377                         break;
    378                     case FAILURE_NEW_CONNECTION_ATTEMPT:
    379                         sb.append("NEW_CONNECTION_ATTEMPT");
    380                         break;
    381                     case FAILURE_REDUNDANT_CONNECTION_ATTEMPT:
    382                         sb.append("REDUNDANT_CONNECTION_ATTEMPT");
    383                         break;
    384                     case FAILURE_ROAM_TIMEOUT:
    385                         sb.append("ROAM_TIMEOUT");
    386                         break;
    387                     case FAILURE_DHCP:
    388                         sb.append("DHCP");
    389                         break;
    390                     case FAILURE_ASSOCIATION_TIMED_OUT:
    391                         sb.append("ASSOCIATION_TIMED_OUT");
    392                         break;
    393                     default:
    394                         sb.append("UNKNOWN");
    395                         break;
    396                 }
    397                 sb.append(", connectivityLevelFailureCode=");
    398                 switch(mConnectionEvent.connectivityLevelFailureCode) {
    399                     case WifiMetricsProto.ConnectionEvent.HLF_NONE:
    400                         sb.append("NONE");
    401                         break;
    402                     case WifiMetricsProto.ConnectionEvent.HLF_DHCP:
    403                         sb.append("DHCP");
    404                         break;
    405                     case WifiMetricsProto.ConnectionEvent.HLF_NO_INTERNET:
    406                         sb.append("NO_INTERNET");
    407                         break;
    408                     case WifiMetricsProto.ConnectionEvent.HLF_UNWANTED:
    409                         sb.append("UNWANTED");
    410                         break;
    411                     default:
    412                         sb.append("UNKNOWN");
    413                         break;
    414                 }
    415                 sb.append(", signalStrength=");
    416                 sb.append(mConnectionEvent.signalStrength);
    417                 sb.append(", wifiState=");
    418                 switch(mWifiState) {
    419                     case WifiMetricsProto.WifiLog.WIFI_DISABLED:
    420                         sb.append("WIFI_DISABLED");
    421                         break;
    422                     case WifiMetricsProto.WifiLog.WIFI_DISCONNECTED:
    423                         sb.append("WIFI_DISCONNECTED");
    424                         break;
    425                     case WifiMetricsProto.WifiLog.WIFI_ASSOCIATED:
    426                         sb.append("WIFI_ASSOCIATED");
    427                         break;
    428                     default:
    429                         sb.append("WIFI_UNKNOWN");
    430                         break;
    431                 }
    432                 sb.append(", screenOn=");
    433                 sb.append(mScreenOn);
    434                 sb.append(". mRouterFingerprint: ");
    435                 sb.append(mRouterFingerPrint.toString());
    436             }
    437             return sb.toString();
    438         }
    439     }
    440 
    441     public WifiMetrics(Clock clock, Looper looper, WifiAwareMetrics awareMetrics,
    442             RttMetrics rttMetrics) {
    443         mClock = clock;
    444         mCurrentConnectionEvent = null;
    445         mScreenOn = true;
    446         mWifiState = WifiMetricsProto.WifiLog.WIFI_DISABLED;
    447         mRecordStartTimeSec = mClock.getElapsedSinceBootMillis() / 1000;
    448         mWifiAwareMetrics = awareMetrics;
    449         mRttMetrics = rttMetrics;
    450 
    451         mHandler = new Handler(looper) {
    452             public void handleMessage(Message msg) {
    453                 synchronized (mLock) {
    454                     processMessage(msg);
    455                 }
    456             }
    457         };
    458     }
    459 
    460     /** Sets internal ScoringParams member */
    461     public void setScoringParams(ScoringParams scoringParams) {
    462         mScoringParams = scoringParams;
    463     }
    464 
    465     /** Sets internal WifiConfigManager member */
    466     public void setWifiConfigManager(WifiConfigManager wifiConfigManager) {
    467         mWifiConfigManager = wifiConfigManager;
    468     }
    469 
    470     /** Sets internal WifiNetworkSelector member */
    471     public void setWifiNetworkSelector(WifiNetworkSelector wifiNetworkSelector) {
    472         mWifiNetworkSelector = wifiNetworkSelector;
    473     }
    474 
    475     /** Sets internal PasspointManager member */
    476     public void setPasspointManager(PasspointManager passpointManager) {
    477         mPasspointManager = passpointManager;
    478     }
    479 
    480     /**
    481      * Increment total number of attempts to start a pno scan
    482      */
    483     public void incrementPnoScanStartAttempCount() {
    484         synchronized (mLock) {
    485             mPnoScanMetrics.numPnoScanAttempts++;
    486         }
    487     }
    488 
    489     /**
    490      * Increment total number of attempts with pno scan failed
    491      */
    492     public void incrementPnoScanFailedCount() {
    493         synchronized (mLock) {
    494             mPnoScanMetrics.numPnoScanFailed++;
    495         }
    496     }
    497 
    498     /**
    499      * Increment number of pno scans started successfully over offload
    500      */
    501     public void incrementPnoScanStartedOverOffloadCount() {
    502         synchronized (mLock) {
    503             mPnoScanMetrics.numPnoScanStartedOverOffload++;
    504         }
    505     }
    506 
    507     /**
    508      * Increment number of pno scans failed over offload
    509      */
    510     public void incrementPnoScanFailedOverOffloadCount() {
    511         synchronized (mLock) {
    512             mPnoScanMetrics.numPnoScanFailedOverOffload++;
    513         }
    514     }
    515 
    516     /**
    517      * Increment number of times pno scan found a result
    518      */
    519     public void incrementPnoFoundNetworkEventCount() {
    520         synchronized (mLock) {
    521             mPnoScanMetrics.numPnoFoundNetworkEvents++;
    522         }
    523     }
    524 
    525     /**
    526      * Increment total number of wps connection attempts
    527      */
    528     public void incrementWpsAttemptCount() {
    529         synchronized (mLock) {
    530             mWpsMetrics.numWpsAttempts++;
    531         }
    532     }
    533 
    534     /**
    535      * Increment total number of wps connection success
    536      */
    537     public void incrementWpsSuccessCount() {
    538         synchronized (mLock) {
    539             mWpsMetrics.numWpsSuccess++;
    540         }
    541     }
    542 
    543     /**
    544      * Increment total number of wps failure on start
    545      */
    546     public void incrementWpsStartFailureCount() {
    547         synchronized (mLock) {
    548             mWpsMetrics.numWpsStartFailure++;
    549         }
    550     }
    551 
    552     /**
    553      * Increment total number of wps overlap failure
    554      */
    555     public void incrementWpsOverlapFailureCount() {
    556         synchronized (mLock) {
    557             mWpsMetrics.numWpsOverlapFailure++;
    558         }
    559     }
    560 
    561     /**
    562      * Increment total number of wps timeout failure
    563      */
    564     public void incrementWpsTimeoutFailureCount() {
    565         synchronized (mLock) {
    566             mWpsMetrics.numWpsTimeoutFailure++;
    567         }
    568     }
    569 
    570     /**
    571      * Increment total number of other wps failure during connection
    572      */
    573     public void incrementWpsOtherConnectionFailureCount() {
    574         synchronized (mLock) {
    575             mWpsMetrics.numWpsOtherConnectionFailure++;
    576         }
    577     }
    578 
    579     /**
    580      * Increment total number of supplicant failure after wps
    581      */
    582     public void incrementWpsSupplicantFailureCount() {
    583         synchronized (mLock) {
    584             mWpsMetrics.numWpsSupplicantFailure++;
    585         }
    586     }
    587 
    588     /**
    589      * Increment total number of wps cancellation
    590      */
    591     public void incrementWpsCancellationCount() {
    592         synchronized (mLock) {
    593             mWpsMetrics.numWpsCancellation++;
    594         }
    595     }
    596 
    597     // Values used for indexing SystemStateEntries
    598     private static final int SCREEN_ON = 1;
    599     private static final int SCREEN_OFF = 0;
    600 
    601     /**
    602      * Create a new connection event. Call when wifi attempts to make a new network connection
    603      * If there is a current 'un-ended' connection event, it will be ended with UNKNOWN connectivity
    604      * failure code.
    605      * Gathers and sets the RouterFingerPrint data as well
    606      *
    607      * @param config WifiConfiguration of the config used for the current connection attempt
    608      * @param roamType Roam type that caused connection attempt, see WifiMetricsProto.WifiLog.ROAM_X
    609      */
    610     public void startConnectionEvent(WifiConfiguration config, String targetBSSID, int roamType) {
    611         synchronized (mLock) {
    612             // Check if this is overlapping another current connection event
    613             if (mCurrentConnectionEvent != null) {
    614                 //Is this new Connection Event the same as the current one
    615                 if (mCurrentConnectionEvent.mConfigSsid != null
    616                         && mCurrentConnectionEvent.mConfigBssid != null
    617                         && config != null
    618                         && mCurrentConnectionEvent.mConfigSsid.equals(config.SSID)
    619                         && (mCurrentConnectionEvent.mConfigBssid.equals("any")
    620                         || mCurrentConnectionEvent.mConfigBssid.equals(targetBSSID))) {
    621                     mCurrentConnectionEvent.mConfigBssid = targetBSSID;
    622                     // End Connection Event due to new connection attempt to the same network
    623                     endConnectionEvent(ConnectionEvent.FAILURE_REDUNDANT_CONNECTION_ATTEMPT,
    624                             WifiMetricsProto.ConnectionEvent.HLF_NONE);
    625                 } else {
    626                     // End Connection Event due to new connection attempt to different network
    627                     endConnectionEvent(ConnectionEvent.FAILURE_NEW_CONNECTION_ATTEMPT,
    628                             WifiMetricsProto.ConnectionEvent.HLF_NONE);
    629                 }
    630             }
    631             //If past maximum connection events, start removing the oldest
    632             while(mConnectionEventList.size() >= MAX_CONNECTION_EVENTS) {
    633                 mConnectionEventList.remove(0);
    634             }
    635             mCurrentConnectionEvent = new ConnectionEvent();
    636             mCurrentConnectionEvent.mConnectionEvent.startTimeMillis =
    637                     mClock.getWallClockMillis();
    638             mCurrentConnectionEvent.mConfigBssid = targetBSSID;
    639             mCurrentConnectionEvent.mConnectionEvent.roamType = roamType;
    640             mCurrentConnectionEvent.mRouterFingerPrint.updateFromWifiConfiguration(config);
    641             mCurrentConnectionEvent.mConfigBssid = "any";
    642             mCurrentConnectionEvent.mRealStartTime = mClock.getElapsedSinceBootMillis();
    643             mCurrentConnectionEvent.mWifiState = mWifiState;
    644             mCurrentConnectionEvent.mScreenOn = mScreenOn;
    645             mConnectionEventList.add(mCurrentConnectionEvent);
    646             mScanResultRssiTimestampMillis = -1;
    647             if (config != null) {
    648                 ScanResult candidate = config.getNetworkSelectionStatus().getCandidate();
    649                 if (candidate != null) {
    650                     // Cache the RSSI of the candidate, as the connection event level is updated
    651                     // from other sources (polls, bssid_associations) and delta requires the
    652                     // scanResult rssi
    653                     mScanResultRssi = candidate.level;
    654                     mScanResultRssiTimestampMillis = mClock.getElapsedSinceBootMillis();
    655                 }
    656             }
    657         }
    658     }
    659 
    660     /**
    661      * set the RoamType of the current ConnectionEvent (if any)
    662      */
    663     public void setConnectionEventRoamType(int roamType) {
    664         synchronized (mLock) {
    665             if (mCurrentConnectionEvent != null) {
    666                 mCurrentConnectionEvent.mConnectionEvent.roamType = roamType;
    667             }
    668         }
    669     }
    670 
    671     /**
    672      * Set AP related metrics from ScanDetail
    673      */
    674     public void setConnectionScanDetail(ScanDetail scanDetail) {
    675         synchronized (mLock) {
    676             if (mCurrentConnectionEvent != null && scanDetail != null) {
    677                 NetworkDetail networkDetail = scanDetail.getNetworkDetail();
    678                 ScanResult scanResult = scanDetail.getScanResult();
    679                 //Ensure that we have a networkDetail, and that it corresponds to the currently
    680                 //tracked connection attempt
    681                 if (networkDetail != null && scanResult != null
    682                         && mCurrentConnectionEvent.mConfigSsid != null
    683                         && mCurrentConnectionEvent.mConfigSsid
    684                         .equals("\"" + networkDetail.getSSID() + "\"")) {
    685                     updateMetricsFromNetworkDetail(networkDetail);
    686                     updateMetricsFromScanResult(scanResult);
    687                 }
    688             }
    689         }
    690     }
    691 
    692     /**
    693      * End a Connection event record. Call when wifi connection attempt succeeds or fails.
    694      * If a Connection event has not been started and is active when .end is called, a new one is
    695      * created with zero duration.
    696      *
    697      * @param level2FailureCode Level 2 failure code returned by supplicant
    698      * @param connectivityFailureCode WifiMetricsProto.ConnectionEvent.HLF_X
    699      */
    700     public void endConnectionEvent(int level2FailureCode, int connectivityFailureCode) {
    701         synchronized (mLock) {
    702             if (mCurrentConnectionEvent != null) {
    703                 boolean result = (level2FailureCode == 1)
    704                         && (connectivityFailureCode == WifiMetricsProto.ConnectionEvent.HLF_NONE);
    705                 mCurrentConnectionEvent.mConnectionEvent.connectionResult = result ? 1 : 0;
    706                 mCurrentConnectionEvent.mRealEndTime = mClock.getElapsedSinceBootMillis();
    707                 mCurrentConnectionEvent.mConnectionEvent.durationTakenToConnectMillis = (int)
    708                         (mCurrentConnectionEvent.mRealEndTime
    709                         - mCurrentConnectionEvent.mRealStartTime);
    710                 mCurrentConnectionEvent.mConnectionEvent.level2FailureCode = level2FailureCode;
    711                 mCurrentConnectionEvent.mConnectionEvent.connectivityLevelFailureCode =
    712                         connectivityFailureCode;
    713                 // ConnectionEvent already added to ConnectionEvents List. Safe to null current here
    714                 mCurrentConnectionEvent = null;
    715                 if (!result) {
    716                     mScanResultRssiTimestampMillis = -1;
    717                 }
    718             }
    719         }
    720     }
    721 
    722     /**
    723      * Set ConnectionEvent DTIM Interval (if set), and 802.11 Connection mode, from NetworkDetail
    724      */
    725     private void updateMetricsFromNetworkDetail(NetworkDetail networkDetail) {
    726         int dtimInterval = networkDetail.getDtimInterval();
    727         if (dtimInterval > 0) {
    728             mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.dtim =
    729                     dtimInterval;
    730         }
    731         int connectionWifiMode;
    732         switch (networkDetail.getWifiMode()) {
    733             case InformationElementUtil.WifiMode.MODE_UNDEFINED:
    734                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_UNKNOWN;
    735                 break;
    736             case InformationElementUtil.WifiMode.MODE_11A:
    737                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_A;
    738                 break;
    739             case InformationElementUtil.WifiMode.MODE_11B:
    740                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_B;
    741                 break;
    742             case InformationElementUtil.WifiMode.MODE_11G:
    743                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_G;
    744                 break;
    745             case InformationElementUtil.WifiMode.MODE_11N:
    746                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_N;
    747                 break;
    748             case InformationElementUtil.WifiMode.MODE_11AC  :
    749                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_AC;
    750                 break;
    751             default:
    752                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_OTHER;
    753                 break;
    754         }
    755         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
    756                 .routerTechnology = connectionWifiMode;
    757     }
    758 
    759     /**
    760      * Set ConnectionEvent RSSI and authentication type from ScanResult
    761      */
    762     private void updateMetricsFromScanResult(ScanResult scanResult) {
    763         mCurrentConnectionEvent.mConnectionEvent.signalStrength = scanResult.level;
    764         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
    765                 WifiMetricsProto.RouterFingerPrint.AUTH_OPEN;
    766         mCurrentConnectionEvent.mConfigBssid = scanResult.BSSID;
    767         if (scanResult.capabilities != null) {
    768             if (ScanResultUtil.isScanResultForWepNetwork(scanResult)) {
    769                 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
    770                         WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL;
    771             } else if (ScanResultUtil.isScanResultForPskNetwork(scanResult)) {
    772                 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
    773                         WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL;
    774             } else if (ScanResultUtil.isScanResultForEapNetwork(scanResult)) {
    775                 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
    776                         WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE;
    777             }
    778         }
    779         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.channelInfo =
    780                 scanResult.frequency;
    781     }
    782 
    783     void setIsLocationEnabled(boolean enabled) {
    784         synchronized (mLock) {
    785             mWifiLogProto.isLocationEnabled = enabled;
    786         }
    787     }
    788 
    789     void setIsScanningAlwaysEnabled(boolean enabled) {
    790         synchronized (mLock) {
    791             mWifiLogProto.isScanningAlwaysEnabled = enabled;
    792         }
    793     }
    794 
    795     /**
    796      * Increment Non Empty Scan Results count
    797      */
    798     public void incrementNonEmptyScanResultCount() {
    799         if (DBG) Log.v(TAG, "incrementNonEmptyScanResultCount");
    800         synchronized (mLock) {
    801             mWifiLogProto.numNonEmptyScanResults++;
    802         }
    803     }
    804 
    805     /**
    806      * Increment Empty Scan Results count
    807      */
    808     public void incrementEmptyScanResultCount() {
    809         if (DBG) Log.v(TAG, "incrementEmptyScanResultCount");
    810         synchronized (mLock) {
    811             mWifiLogProto.numEmptyScanResults++;
    812         }
    813     }
    814 
    815     /**
    816      * Increment background scan count
    817      */
    818     public void incrementBackgroundScanCount() {
    819         if (DBG) Log.v(TAG, "incrementBackgroundScanCount");
    820         synchronized (mLock) {
    821             mWifiLogProto.numBackgroundScans++;
    822         }
    823     }
    824 
    825    /**
    826      * Get Background scan count
    827      */
    828     public int getBackgroundScanCount() {
    829         synchronized (mLock) {
    830             return mWifiLogProto.numBackgroundScans;
    831         }
    832     }
    833 
    834     /**
    835      * Increment oneshot scan count, and the associated WifiSystemScanStateCount entry
    836      */
    837     public void incrementOneshotScanCount() {
    838         synchronized (mLock) {
    839             mWifiLogProto.numOneshotScans++;
    840         }
    841         incrementWifiSystemScanStateCount(mWifiState, mScreenOn);
    842     }
    843 
    844     /**
    845      * Increment connectivity oneshot scan count.
    846      */
    847     public void incrementConnectivityOneshotScanCount() {
    848         synchronized (mLock) {
    849             mWifiLogProto.numConnectivityOneshotScans++;
    850         }
    851     }
    852 
    853     /**
    854      * Get oneshot scan count
    855      */
    856     public int getOneshotScanCount() {
    857         synchronized (mLock) {
    858             return mWifiLogProto.numOneshotScans;
    859         }
    860     }
    861 
    862     /**
    863      * Get connectivity oneshot scan count
    864      */
    865     public int getConnectivityOneshotScanCount() {
    866         synchronized (mLock) {
    867             return mWifiLogProto.numConnectivityOneshotScans;
    868         }
    869     }
    870 
    871     /**
    872      * Increment oneshot scan count for external apps.
    873      */
    874     public void incrementExternalAppOneshotScanRequestsCount() {
    875         synchronized (mLock) {
    876             mWifiLogProto.numExternalAppOneshotScanRequests++;
    877         }
    878     }
    879     /**
    880      * Increment oneshot scan throttle count for external foreground apps.
    881      */
    882     public void incrementExternalForegroundAppOneshotScanRequestsThrottledCount() {
    883         synchronized (mLock) {
    884             mWifiLogProto.numExternalForegroundAppOneshotScanRequestsThrottled++;
    885         }
    886     }
    887 
    888     /**
    889      * Increment oneshot scan throttle count for external background apps.
    890      */
    891     public void incrementExternalBackgroundAppOneshotScanRequestsThrottledCount() {
    892         synchronized (mLock) {
    893             mWifiLogProto.numExternalBackgroundAppOneshotScanRequestsThrottled++;
    894         }
    895     }
    896 
    897     private String returnCodeToString(int scanReturnCode) {
    898         switch(scanReturnCode){
    899             case WifiMetricsProto.WifiLog.SCAN_UNKNOWN:
    900                 return "SCAN_UNKNOWN";
    901             case WifiMetricsProto.WifiLog.SCAN_SUCCESS:
    902                 return "SCAN_SUCCESS";
    903             case WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED:
    904                 return "SCAN_FAILURE_INTERRUPTED";
    905             case WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION:
    906                 return "SCAN_FAILURE_INVALID_CONFIGURATION";
    907             case WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED:
    908                 return "FAILURE_WIFI_DISABLED";
    909             default:
    910                 return "<UNKNOWN>";
    911         }
    912     }
    913 
    914     /**
    915      * Increment count of scan return code occurrence
    916      *
    917      * @param scanReturnCode Return code from scan attempt WifiMetricsProto.WifiLog.SCAN_X
    918      */
    919     public void incrementScanReturnEntry(int scanReturnCode, int countToAdd) {
    920         synchronized (mLock) {
    921             if (DBG) Log.v(TAG, "incrementScanReturnEntry " + returnCodeToString(scanReturnCode));
    922             int entry = mScanReturnEntries.get(scanReturnCode);
    923             entry += countToAdd;
    924             mScanReturnEntries.put(scanReturnCode, entry);
    925         }
    926     }
    927     /**
    928      * Get the count of this scanReturnCode
    929      * @param scanReturnCode that we are getting the count for
    930      */
    931     public int getScanReturnEntry(int scanReturnCode) {
    932         synchronized (mLock) {
    933             return mScanReturnEntries.get(scanReturnCode);
    934         }
    935     }
    936 
    937     private String wifiSystemStateToString(int state) {
    938         switch(state){
    939             case WifiMetricsProto.WifiLog.WIFI_UNKNOWN:
    940                 return "WIFI_UNKNOWN";
    941             case WifiMetricsProto.WifiLog.WIFI_DISABLED:
    942                 return "WIFI_DISABLED";
    943             case WifiMetricsProto.WifiLog.WIFI_DISCONNECTED:
    944                 return "WIFI_DISCONNECTED";
    945             case WifiMetricsProto.WifiLog.WIFI_ASSOCIATED:
    946                 return "WIFI_ASSOCIATED";
    947             default:
    948                 return "default";
    949         }
    950     }
    951 
    952     /**
    953      * Increments the count of scans initiated by each wifi state, accounts for screenOn/Off
    954      *
    955      * @param state State of the system when scan was initiated, see WifiMetricsProto.WifiLog.WIFI_X
    956      * @param screenOn Is the screen on
    957      */
    958     public void incrementWifiSystemScanStateCount(int state, boolean screenOn) {
    959         synchronized (mLock) {
    960             if (DBG) {
    961                 Log.v(TAG, "incrementWifiSystemScanStateCount " + wifiSystemStateToString(state)
    962                         + " " + screenOn);
    963             }
    964             int index = (state * 2) + (screenOn ? SCREEN_ON : SCREEN_OFF);
    965             int entry = mWifiSystemStateEntries.get(index);
    966             entry++;
    967             mWifiSystemStateEntries.put(index, entry);
    968         }
    969     }
    970 
    971     /**
    972      * Get the count of this system State Entry
    973      */
    974     public int getSystemStateCount(int state, boolean screenOn) {
    975         synchronized (mLock) {
    976             int index = state * 2 + (screenOn ? SCREEN_ON : SCREEN_OFF);
    977             return mWifiSystemStateEntries.get(index);
    978         }
    979     }
    980 
    981     /**
    982      * Increment number of times the Watchdog of Last Resort triggered, resetting the wifi stack
    983      */
    984     public void incrementNumLastResortWatchdogTriggers() {
    985         synchronized (mLock) {
    986             mWifiLogProto.numLastResortWatchdogTriggers++;
    987         }
    988     }
    989     /**
    990      * @param count number of networks over bad association threshold when watchdog triggered
    991      */
    992     public void addCountToNumLastResortWatchdogBadAssociationNetworksTotal(int count) {
    993         synchronized (mLock) {
    994             mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal += count;
    995         }
    996     }
    997     /**
    998      * @param count number of networks over bad authentication threshold when watchdog triggered
    999      */
   1000     public void addCountToNumLastResortWatchdogBadAuthenticationNetworksTotal(int count) {
   1001         synchronized (mLock) {
   1002             mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal += count;
   1003         }
   1004     }
   1005     /**
   1006      * @param count number of networks over bad dhcp threshold when watchdog triggered
   1007      */
   1008     public void addCountToNumLastResortWatchdogBadDhcpNetworksTotal(int count) {
   1009         synchronized (mLock) {
   1010             mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal += count;
   1011         }
   1012     }
   1013     /**
   1014      * @param count number of networks over bad other threshold when watchdog triggered
   1015      */
   1016     public void addCountToNumLastResortWatchdogBadOtherNetworksTotal(int count) {
   1017         synchronized (mLock) {
   1018             mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal += count;
   1019         }
   1020     }
   1021     /**
   1022      * @param count number of networks seen when watchdog triggered
   1023      */
   1024     public void addCountToNumLastResortWatchdogAvailableNetworksTotal(int count) {
   1025         synchronized (mLock) {
   1026             mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal += count;
   1027         }
   1028     }
   1029     /**
   1030      * Increment count of triggers with atleast one bad association network
   1031      */
   1032     public void incrementNumLastResortWatchdogTriggersWithBadAssociation() {
   1033         synchronized (mLock) {
   1034             mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation++;
   1035         }
   1036     }
   1037     /**
   1038      * Increment count of triggers with atleast one bad authentication network
   1039      */
   1040     public void incrementNumLastResortWatchdogTriggersWithBadAuthentication() {
   1041         synchronized (mLock) {
   1042             mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication++;
   1043         }
   1044     }
   1045     /**
   1046      * Increment count of triggers with atleast one bad dhcp network
   1047      */
   1048     public void incrementNumLastResortWatchdogTriggersWithBadDhcp() {
   1049         synchronized (mLock) {
   1050             mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp++;
   1051         }
   1052     }
   1053     /**
   1054      * Increment count of triggers with atleast one bad other network
   1055      */
   1056     public void incrementNumLastResortWatchdogTriggersWithBadOther() {
   1057         synchronized (mLock) {
   1058             mWifiLogProto.numLastResortWatchdogTriggersWithBadOther++;
   1059         }
   1060     }
   1061 
   1062     /**
   1063      * Increment number of times connectivity watchdog confirmed pno is working
   1064      */
   1065     public void incrementNumConnectivityWatchdogPnoGood() {
   1066         synchronized (mLock) {
   1067             mWifiLogProto.numConnectivityWatchdogPnoGood++;
   1068         }
   1069     }
   1070     /**
   1071      * Increment number of times connectivity watchdog found pno not working
   1072      */
   1073     public void incrementNumConnectivityWatchdogPnoBad() {
   1074         synchronized (mLock) {
   1075             mWifiLogProto.numConnectivityWatchdogPnoBad++;
   1076         }
   1077     }
   1078     /**
   1079      * Increment number of times connectivity watchdog confirmed background scan is working
   1080      */
   1081     public void incrementNumConnectivityWatchdogBackgroundGood() {
   1082         synchronized (mLock) {
   1083             mWifiLogProto.numConnectivityWatchdogBackgroundGood++;
   1084         }
   1085     }
   1086     /**
   1087      * Increment number of times connectivity watchdog found background scan not working
   1088      */
   1089     public void incrementNumConnectivityWatchdogBackgroundBad() {
   1090         synchronized (mLock) {
   1091             mWifiLogProto.numConnectivityWatchdogBackgroundBad++;
   1092         }
   1093     }
   1094 
   1095     /**
   1096      * Increment various poll related metrics, and cache performance data for StaEvent logging
   1097      */
   1098     public void handlePollResult(WifiInfo wifiInfo) {
   1099         mLastPollRssi = wifiInfo.getRssi();
   1100         mLastPollLinkSpeed = wifiInfo.getLinkSpeed();
   1101         mLastPollFreq = wifiInfo.getFrequency();
   1102         incrementRssiPollRssiCount(mLastPollFreq, mLastPollRssi);
   1103     }
   1104 
   1105     /**
   1106      * Increment occurence count of RSSI level from RSSI poll for the given frequency.
   1107      * @param frequency (MHz)
   1108      * @param rssi
   1109      */
   1110     @VisibleForTesting
   1111     public void incrementRssiPollRssiCount(int frequency, int rssi) {
   1112         if (!(rssi >= MIN_RSSI_POLL && rssi <= MAX_RSSI_POLL)) {
   1113             return;
   1114         }
   1115         synchronized (mLock) {
   1116             if (!mRssiPollCountsMap.containsKey(frequency)) {
   1117                 mRssiPollCountsMap.put(frequency, new SparseIntArray());
   1118             }
   1119             SparseIntArray sparseIntArray = mRssiPollCountsMap.get(frequency);
   1120             int count = sparseIntArray.get(rssi);
   1121             sparseIntArray.put(rssi, count + 1);
   1122             maybeIncrementRssiDeltaCount(rssi - mScanResultRssi);
   1123         }
   1124     }
   1125 
   1126     /**
   1127      * Increment occurence count of difference between scan result RSSI and the first RSSI poll.
   1128      * Ignores rssi values outside the bounds of [MIN_RSSI_DELTA, MAX_RSSI_DELTA]
   1129      * mLock must be held when calling this method.
   1130      */
   1131     private void maybeIncrementRssiDeltaCount(int rssi) {
   1132         // Check if this RSSI poll is close enough to a scan result RSSI to log a delta value
   1133         if (mScanResultRssiTimestampMillis >= 0) {
   1134             long timeDelta = mClock.getElapsedSinceBootMillis() - mScanResultRssiTimestampMillis;
   1135             if (timeDelta <= TIMEOUT_RSSI_DELTA_MILLIS) {
   1136                 if (rssi >= MIN_RSSI_DELTA && rssi <= MAX_RSSI_DELTA) {
   1137                     int count = mRssiDeltaCounts.get(rssi);
   1138                     mRssiDeltaCounts.put(rssi, count + 1);
   1139                 }
   1140             }
   1141             mScanResultRssiTimestampMillis = -1;
   1142         }
   1143     }
   1144 
   1145     /**
   1146      * Increment count of Watchdog successes.
   1147      */
   1148     public void incrementNumLastResortWatchdogSuccesses() {
   1149         synchronized (mLock) {
   1150             mWifiLogProto.numLastResortWatchdogSuccesses++;
   1151         }
   1152     }
   1153 
   1154     /**
   1155      * Increment the count of network connection failures that happened after watchdog has been
   1156      * triggered.
   1157      */
   1158     public void incrementWatchdogTotalConnectionFailureCountAfterTrigger() {
   1159         synchronized (mLock) {
   1160             mWifiLogProto.watchdogTotalConnectionFailureCountAfterTrigger++;
   1161         }
   1162     }
   1163 
   1164     /**
   1165      * Sets the time taken for wifi to connect after a watchdog triggers a restart.
   1166      * @param milliseconds
   1167      */
   1168     public void setWatchdogSuccessTimeDurationMs(long ms) {
   1169         synchronized (mLock) {
   1170             mWifiLogProto.watchdogTriggerToConnectionSuccessDurationMs = ms;
   1171         }
   1172     }
   1173 
   1174     /**
   1175      * Increments the count of alerts by alert reason.
   1176      *
   1177      * @param reason The cause of the alert. The reason values are driver-specific.
   1178      */
   1179     public void incrementAlertReasonCount(int reason) {
   1180         if (reason > WifiLoggerHal.WIFI_ALERT_REASON_MAX
   1181                 || reason < WifiLoggerHal.WIFI_ALERT_REASON_MIN) {
   1182             reason = WifiLoggerHal.WIFI_ALERT_REASON_RESERVED;
   1183         }
   1184         synchronized (mLock) {
   1185             int alertCount = mWifiAlertReasonCounts.get(reason);
   1186             mWifiAlertReasonCounts.put(reason, alertCount + 1);
   1187         }
   1188     }
   1189 
   1190     /**
   1191      * Counts all the different types of networks seen in a set of scan results
   1192      */
   1193     public void countScanResults(List<ScanDetail> scanDetails) {
   1194         if (scanDetails == null) {
   1195             return;
   1196         }
   1197         int totalResults = 0;
   1198         int openNetworks = 0;
   1199         int personalNetworks = 0;
   1200         int enterpriseNetworks = 0;
   1201         int hiddenNetworks = 0;
   1202         int hotspot2r1Networks = 0;
   1203         int hotspot2r2Networks = 0;
   1204         for (ScanDetail scanDetail : scanDetails) {
   1205             NetworkDetail networkDetail = scanDetail.getNetworkDetail();
   1206             ScanResult scanResult = scanDetail.getScanResult();
   1207             totalResults++;
   1208             if (networkDetail != null) {
   1209                 if (networkDetail.isHiddenBeaconFrame()) {
   1210                     hiddenNetworks++;
   1211                 }
   1212                 if (networkDetail.getHSRelease() != null) {
   1213                     if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) {
   1214                         hotspot2r1Networks++;
   1215                     } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) {
   1216                         hotspot2r2Networks++;
   1217                     }
   1218                 }
   1219             }
   1220             if (scanResult != null && scanResult.capabilities != null) {
   1221                 if (ScanResultUtil.isScanResultForEapNetwork(scanResult)) {
   1222                     enterpriseNetworks++;
   1223                 } else if (ScanResultUtil.isScanResultForPskNetwork(scanResult)
   1224                         || ScanResultUtil.isScanResultForWepNetwork(scanResult)) {
   1225                     personalNetworks++;
   1226                 } else {
   1227                     openNetworks++;
   1228                 }
   1229             }
   1230         }
   1231         synchronized (mLock) {
   1232             mWifiLogProto.numTotalScanResults += totalResults;
   1233             mWifiLogProto.numOpenNetworkScanResults += openNetworks;
   1234             mWifiLogProto.numPersonalNetworkScanResults += personalNetworks;
   1235             mWifiLogProto.numEnterpriseNetworkScanResults += enterpriseNetworks;
   1236             mWifiLogProto.numHiddenNetworkScanResults += hiddenNetworks;
   1237             mWifiLogProto.numHotspot2R1NetworkScanResults += hotspot2r1Networks;
   1238             mWifiLogProto.numHotspot2R2NetworkScanResults += hotspot2r2Networks;
   1239             mWifiLogProto.numScans++;
   1240         }
   1241     }
   1242 
   1243     private boolean mWifiWins = false; // Based on scores, use wifi instead of mobile data?
   1244 
   1245     /**
   1246      * Increments occurence of a particular wifi score calculated
   1247      * in WifiScoreReport by current connected network. Scores are bounded
   1248      * within  [MIN_WIFI_SCORE, MAX_WIFI_SCORE] to limit size of SparseArray.
   1249      *
   1250      * Also records events when the current score breaches significant thresholds.
   1251      */
   1252     public void incrementWifiScoreCount(int score) {
   1253         if (score < MIN_WIFI_SCORE || score > MAX_WIFI_SCORE) {
   1254             return;
   1255         }
   1256         synchronized (mLock) {
   1257             int count = mWifiScoreCounts.get(score);
   1258             mWifiScoreCounts.put(score, count + 1);
   1259 
   1260             boolean wifiWins = mWifiWins;
   1261             if (mWifiWins && score < LOW_WIFI_SCORE) {
   1262                 wifiWins = false;
   1263             } else if (!mWifiWins && score > LOW_WIFI_SCORE) {
   1264                 wifiWins = true;
   1265             }
   1266             mLastScore = score;
   1267             if (wifiWins != mWifiWins) {
   1268                 mWifiWins = wifiWins;
   1269                 StaEvent event = new StaEvent();
   1270                 event.type = StaEvent.TYPE_SCORE_BREACH;
   1271                 addStaEvent(event);
   1272             }
   1273         }
   1274     }
   1275 
   1276     /**
   1277      * Increments occurence of the results from attempting to start SoftAp.
   1278      * Maps the |result| and WifiManager |failureCode| constant to proto defined SoftApStartResult
   1279      * codes.
   1280      */
   1281     public void incrementSoftApStartResult(boolean result, int failureCode) {
   1282         synchronized (mLock) {
   1283             if (result) {
   1284                 int count = mSoftApManagerReturnCodeCounts.get(
   1285                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY);
   1286                 mSoftApManagerReturnCodeCounts.put(
   1287                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY,
   1288                         count + 1);
   1289                 return;
   1290             }
   1291 
   1292             // now increment failure modes - if not explicitly handled, dump into the general
   1293             // error bucket.
   1294             if (failureCode == WifiManager.SAP_START_FAILURE_NO_CHANNEL) {
   1295                 int count = mSoftApManagerReturnCodeCounts.get(
   1296                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL);
   1297                 mSoftApManagerReturnCodeCounts.put(
   1298                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL,
   1299                         count + 1);
   1300             } else {
   1301                 // failure mode not tracked at this time...  count as a general error for now.
   1302                 int count = mSoftApManagerReturnCodeCounts.get(
   1303                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR);
   1304                 mSoftApManagerReturnCodeCounts.put(
   1305                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR,
   1306                         count + 1);
   1307             }
   1308         }
   1309     }
   1310 
   1311     /**
   1312      * Adds a record indicating the current up state of soft AP
   1313      */
   1314     public void addSoftApUpChangedEvent(boolean isUp, int mode) {
   1315         SoftApConnectedClientsEvent event = new SoftApConnectedClientsEvent();
   1316         event.eventType = isUp ? SoftApConnectedClientsEvent.SOFT_AP_UP :
   1317                 SoftApConnectedClientsEvent.SOFT_AP_DOWN;
   1318         event.numConnectedClients = 0;
   1319         addSoftApConnectedClientsEvent(event, mode);
   1320     }
   1321 
   1322     /**
   1323      * Adds a record for current number of associated stations to soft AP
   1324      */
   1325     public void addSoftApNumAssociatedStationsChangedEvent(int numStations, int mode) {
   1326         SoftApConnectedClientsEvent event = new SoftApConnectedClientsEvent();
   1327         event.eventType = SoftApConnectedClientsEvent.NUM_CLIENTS_CHANGED;
   1328         event.numConnectedClients = numStations;
   1329         addSoftApConnectedClientsEvent(event, mode);
   1330     }
   1331 
   1332     /**
   1333      * Adds a record to the corresponding event list based on mode param
   1334      */
   1335     private void addSoftApConnectedClientsEvent(SoftApConnectedClientsEvent event, int mode) {
   1336         synchronized (mLock) {
   1337             List<SoftApConnectedClientsEvent> softApEventList;
   1338             switch (mode) {
   1339                 case WifiManager.IFACE_IP_MODE_TETHERED:
   1340                     softApEventList = mSoftApEventListTethered;
   1341                     break;
   1342                 case WifiManager.IFACE_IP_MODE_LOCAL_ONLY:
   1343                     softApEventList = mSoftApEventListLocalOnly;
   1344                     break;
   1345                 default:
   1346                     return;
   1347             }
   1348 
   1349             if (softApEventList.size() > MAX_NUM_SOFT_AP_EVENTS) {
   1350                 return;
   1351             }
   1352 
   1353             event.timeStampMillis = mClock.getElapsedSinceBootMillis();
   1354             softApEventList.add(event);
   1355         }
   1356     }
   1357 
   1358     /**
   1359      * Updates current soft AP events with channel info
   1360      */
   1361     public void addSoftApChannelSwitchedEvent(int frequency, int bandwidth, int mode) {
   1362         synchronized (mLock) {
   1363             List<SoftApConnectedClientsEvent> softApEventList;
   1364             switch (mode) {
   1365                 case WifiManager.IFACE_IP_MODE_TETHERED:
   1366                     softApEventList = mSoftApEventListTethered;
   1367                     break;
   1368                 case WifiManager.IFACE_IP_MODE_LOCAL_ONLY:
   1369                     softApEventList = mSoftApEventListLocalOnly;
   1370                     break;
   1371                 default:
   1372                     return;
   1373             }
   1374 
   1375             for (int index = softApEventList.size() - 1; index >= 0; index--) {
   1376                 SoftApConnectedClientsEvent event = softApEventList.get(index);
   1377 
   1378                 if (event != null && event.eventType == SoftApConnectedClientsEvent.SOFT_AP_UP) {
   1379                     event.channelFrequency = frequency;
   1380                     event.channelBandwidth = bandwidth;
   1381                     break;
   1382                 }
   1383             }
   1384         }
   1385     }
   1386 
   1387     /**
   1388      * Increment number of times the HAL crashed.
   1389      */
   1390     public void incrementNumHalCrashes() {
   1391         synchronized (mLock) {
   1392             mWifiLogProto.numHalCrashes++;
   1393         }
   1394     }
   1395 
   1396     /**
   1397      * Increment number of times the Wificond crashed.
   1398      */
   1399     public void incrementNumWificondCrashes() {
   1400         synchronized (mLock) {
   1401             mWifiLogProto.numWificondCrashes++;
   1402         }
   1403     }
   1404 
   1405     /**
   1406      * Increment number of times the supplicant crashed.
   1407      */
   1408     public void incrementNumSupplicantCrashes() {
   1409         synchronized (mLock) {
   1410             mWifiLogProto.numSupplicantCrashes++;
   1411         }
   1412     }
   1413 
   1414     /**
   1415      * Increment number of times the hostapd crashed.
   1416      */
   1417     public void incrementNumHostapdCrashes() {
   1418         synchronized (mLock) {
   1419             mWifiLogProto.numHostapdCrashes++;
   1420         }
   1421     }
   1422 
   1423     /**
   1424      * Increment number of times the wifi on failed due to an error in HAL.
   1425      */
   1426     public void incrementNumSetupClientInterfaceFailureDueToHal() {
   1427         synchronized (mLock) {
   1428             mWifiLogProto.numSetupClientInterfaceFailureDueToHal++;
   1429         }
   1430     }
   1431 
   1432     /**
   1433      * Increment number of times the wifi on failed due to an error in wificond.
   1434      */
   1435     public void incrementNumSetupClientInterfaceFailureDueToWificond() {
   1436         synchronized (mLock) {
   1437             mWifiLogProto.numSetupClientInterfaceFailureDueToWificond++;
   1438         }
   1439     }
   1440 
   1441     /**
   1442      * Increment number of times the wifi on failed due to an error in supplicant.
   1443      */
   1444     public void incrementNumSetupClientInterfaceFailureDueToSupplicant() {
   1445         synchronized (mLock) {
   1446             mWifiLogProto.numSetupClientInterfaceFailureDueToSupplicant++;
   1447         }
   1448     }
   1449 
   1450     /**
   1451      * Increment number of times the SoftAp on failed due to an error in HAL.
   1452      */
   1453     public void incrementNumSetupSoftApInterfaceFailureDueToHal() {
   1454         synchronized (mLock) {
   1455             mWifiLogProto.numSetupSoftApInterfaceFailureDueToHal++;
   1456         }
   1457     }
   1458 
   1459     /**
   1460      * Increment number of times the SoftAp on failed due to an error in wificond.
   1461      */
   1462     public void incrementNumSetupSoftApInterfaceFailureDueToWificond() {
   1463         synchronized (mLock) {
   1464             mWifiLogProto.numSetupSoftApInterfaceFailureDueToWificond++;
   1465         }
   1466     }
   1467 
   1468     /**
   1469      * Increment number of times the SoftAp on failed due to an error in hostapd.
   1470      */
   1471     public void incrementNumSetupSoftApInterfaceFailureDueToHostapd() {
   1472         synchronized (mLock) {
   1473             mWifiLogProto.numSetupSoftApInterfaceFailureDueToHostapd++;
   1474         }
   1475     }
   1476 
   1477     /**
   1478      * Increment number of times we got client interface down.
   1479      */
   1480     public void incrementNumClientInterfaceDown() {
   1481         synchronized (mLock) {
   1482             mWifiLogProto.numClientInterfaceDown++;
   1483         }
   1484     }
   1485 
   1486     /**
   1487      * Increment number of times we got client interface down.
   1488      */
   1489     public void incrementNumSoftApInterfaceDown() {
   1490         synchronized (mLock) {
   1491             mWifiLogProto.numSoftApInterfaceDown++;
   1492         }
   1493     }
   1494 
   1495     /**
   1496      * Increment number of times Passpoint provider being installed.
   1497      */
   1498     public void incrementNumPasspointProviderInstallation() {
   1499         synchronized (mLock) {
   1500             mWifiLogProto.numPasspointProviderInstallation++;
   1501         }
   1502     }
   1503 
   1504     /**
   1505      * Increment number of times Passpoint provider is installed successfully.
   1506      */
   1507     public void incrementNumPasspointProviderInstallSuccess() {
   1508         synchronized (mLock) {
   1509             mWifiLogProto.numPasspointProviderInstallSuccess++;
   1510         }
   1511     }
   1512 
   1513     /**
   1514      * Increment number of times Passpoint provider being uninstalled.
   1515      */
   1516     public void incrementNumPasspointProviderUninstallation() {
   1517         synchronized (mLock) {
   1518             mWifiLogProto.numPasspointProviderUninstallation++;
   1519         }
   1520     }
   1521 
   1522     /**
   1523      * Increment number of times Passpoint provider is uninstalled successfully.
   1524      */
   1525     public void incrementNumPasspointProviderUninstallSuccess() {
   1526         synchronized (mLock) {
   1527             mWifiLogProto.numPasspointProviderUninstallSuccess++;
   1528         }
   1529     }
   1530 
   1531     /**
   1532      * Increment number of times we detected a radio mode change to MCC.
   1533      */
   1534     public void incrementNumRadioModeChangeToMcc() {
   1535         synchronized (mLock) {
   1536             mWifiLogProto.numRadioModeChangeToMcc++;
   1537         }
   1538     }
   1539 
   1540     /**
   1541      * Increment number of times we detected a radio mode change to SCC.
   1542      */
   1543     public void incrementNumRadioModeChangeToScc() {
   1544         synchronized (mLock) {
   1545             mWifiLogProto.numRadioModeChangeToScc++;
   1546         }
   1547     }
   1548 
   1549     /**
   1550      * Increment number of times we detected a radio mode change to SBS.
   1551      */
   1552     public void incrementNumRadioModeChangeToSbs() {
   1553         synchronized (mLock) {
   1554             mWifiLogProto.numRadioModeChangeToSbs++;
   1555         }
   1556     }
   1557 
   1558     /**
   1559      * Increment number of times we detected a radio mode change to DBS.
   1560      */
   1561     public void incrementNumRadioModeChangeToDbs() {
   1562         synchronized (mLock) {
   1563             mWifiLogProto.numRadioModeChangeToDbs++;
   1564         }
   1565     }
   1566 
   1567     /**
   1568      * Increment number of times we detected a channel did not satisfy user band preference.
   1569      */
   1570     public void incrementNumSoftApUserBandPreferenceUnsatisfied() {
   1571         synchronized (mLock) {
   1572             mWifiLogProto.numSoftApUserBandPreferenceUnsatisfied++;
   1573         }
   1574     }
   1575 
   1576     /**
   1577      * Increment N-Way network selection decision histograms:
   1578      * Counts the size of various sets of scanDetails within a scan, and increment the occurrence
   1579      * of that size for the associated histogram. There are ten histograms generated for each
   1580      * combination of: {SSID, BSSID} *{Total, Saved, Open, Saved_or_Open, Passpoint}
   1581      * Only performs this count if isFullBand is true, otherwise, increments the partial scan count
   1582      */
   1583     public void incrementAvailableNetworksHistograms(List<ScanDetail> scanDetails,
   1584             boolean isFullBand) {
   1585         synchronized (mLock) {
   1586             if (mWifiConfigManager == null || mWifiNetworkSelector == null
   1587                     || mPasspointManager == null) {
   1588                 return;
   1589             }
   1590             if (!isFullBand) {
   1591                 mWifiLogProto.partialAllSingleScanListenerResults++;
   1592                 return;
   1593             }
   1594             Set<ScanResultMatchInfo> ssids = new HashSet<ScanResultMatchInfo>();
   1595             int bssids = 0;
   1596             Set<ScanResultMatchInfo> openSsids = new HashSet<ScanResultMatchInfo>();
   1597             int openBssids = 0;
   1598             Set<ScanResultMatchInfo> savedSsids = new HashSet<ScanResultMatchInfo>();
   1599             int savedBssids = 0;
   1600             // openOrSavedSsids calculated from union of savedSsids & openSsids
   1601             int openOrSavedBssids = 0;
   1602             Set<PasspointProvider> savedPasspointProviderProfiles =
   1603                     new HashSet<PasspointProvider>();
   1604             int savedPasspointProviderBssids = 0;
   1605             int passpointR1Aps = 0;
   1606             int passpointR2Aps = 0;
   1607             Map<ANQPNetworkKey, Integer> passpointR1UniqueEss = new HashMap<>();
   1608             Map<ANQPNetworkKey, Integer> passpointR2UniqueEss = new HashMap<>();
   1609             int supporting80211mcAps = 0;
   1610             for (ScanDetail scanDetail : scanDetails) {
   1611                 NetworkDetail networkDetail = scanDetail.getNetworkDetail();
   1612                 ScanResult scanResult = scanDetail.getScanResult();
   1613 
   1614                 // statistics to be collected for ALL APs (irrespective of signal power)
   1615                 if (networkDetail.is80211McResponderSupport()) {
   1616                     supporting80211mcAps++;
   1617                 }
   1618 
   1619                 ScanResultMatchInfo matchInfo = ScanResultMatchInfo.fromScanResult(scanResult);
   1620                 Pair<PasspointProvider, PasspointMatch> providerMatch = null;
   1621                 PasspointProvider passpointProvider = null;
   1622                 if (networkDetail.isInterworking()) {
   1623                     providerMatch =
   1624                             mPasspointManager.matchProvider(scanResult);
   1625                     passpointProvider = providerMatch != null ? providerMatch.first : null;
   1626 
   1627                     if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) {
   1628                         passpointR1Aps++;
   1629                     } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) {
   1630                         passpointR2Aps++;
   1631                     }
   1632 
   1633                     long bssid = 0;
   1634                     boolean validBssid = false;
   1635                     try {
   1636                         bssid = Utils.parseMac(scanResult.BSSID);
   1637                         validBssid = true;
   1638                     } catch (IllegalArgumentException e) {
   1639                         Log.e(TAG,
   1640                                 "Invalid BSSID provided in the scan result: " + scanResult.BSSID);
   1641                     }
   1642                     if (validBssid) {
   1643                         ANQPNetworkKey uniqueEss = ANQPNetworkKey.buildKey(scanResult.SSID, bssid,
   1644                                 scanResult.hessid, networkDetail.getAnqpDomainID());
   1645                         if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) {
   1646                             Integer countObj = passpointR1UniqueEss.get(uniqueEss);
   1647                             int count = countObj == null ? 0 : countObj;
   1648                             passpointR1UniqueEss.put(uniqueEss, count + 1);
   1649                         } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) {
   1650                             Integer countObj = passpointR2UniqueEss.get(uniqueEss);
   1651                             int count = countObj == null ? 0 : countObj;
   1652                             passpointR2UniqueEss.put(uniqueEss, count + 1);
   1653                         }
   1654                     }
   1655 
   1656                 }
   1657 
   1658                 if (mWifiNetworkSelector.isSignalTooWeak(scanResult)) {
   1659                     continue;
   1660                 }
   1661 
   1662                 // statistics to be collected ONLY for those APs with sufficient signal power
   1663 
   1664                 ssids.add(matchInfo);
   1665                 bssids++;
   1666                 boolean isOpen = matchInfo.networkType == ScanResultMatchInfo.NETWORK_TYPE_OPEN;
   1667                 WifiConfiguration config =
   1668                         mWifiConfigManager.getConfiguredNetworkForScanDetail(scanDetail);
   1669                 boolean isSaved = (config != null) && !config.isEphemeral()
   1670                         && !config.isPasspoint();
   1671                 boolean isSavedPasspoint = passpointProvider != null;
   1672                 if (isOpen) {
   1673                     openSsids.add(matchInfo);
   1674                     openBssids++;
   1675                 }
   1676                 if (isSaved) {
   1677                     savedSsids.add(matchInfo);
   1678                     savedBssids++;
   1679                 }
   1680                 if (isOpen || isSaved) {
   1681                     openOrSavedBssids++;
   1682                     // Calculate openOrSavedSsids union later
   1683                 }
   1684                 if (isSavedPasspoint) {
   1685                     savedPasspointProviderProfiles.add(passpointProvider);
   1686                     savedPasspointProviderBssids++;
   1687                 }
   1688             }
   1689             mWifiLogProto.fullBandAllSingleScanListenerResults++;
   1690             incrementTotalScanSsids(mTotalSsidsInScanHistogram, ssids.size());
   1691             incrementTotalScanResults(mTotalBssidsInScanHistogram, bssids);
   1692             incrementSsid(mAvailableOpenSsidsInScanHistogram, openSsids.size());
   1693             incrementBssid(mAvailableOpenBssidsInScanHistogram, openBssids);
   1694             incrementSsid(mAvailableSavedSsidsInScanHistogram, savedSsids.size());
   1695             incrementBssid(mAvailableSavedBssidsInScanHistogram, savedBssids);
   1696             openSsids.addAll(savedSsids); // openSsids = Union(openSsids, savedSsids)
   1697             incrementSsid(mAvailableOpenOrSavedSsidsInScanHistogram, openSsids.size());
   1698             incrementBssid(mAvailableOpenOrSavedBssidsInScanHistogram, openOrSavedBssids);
   1699             incrementSsid(mAvailableSavedPasspointProviderProfilesInScanHistogram,
   1700                     savedPasspointProviderProfiles.size());
   1701             incrementBssid(mAvailableSavedPasspointProviderBssidsInScanHistogram,
   1702                     savedPasspointProviderBssids);
   1703             incrementTotalPasspointAps(mObservedHotspotR1ApInScanHistogram, passpointR1Aps);
   1704             incrementTotalPasspointAps(mObservedHotspotR2ApInScanHistogram, passpointR2Aps);
   1705             incrementTotalUniquePasspointEss(mObservedHotspotR1EssInScanHistogram,
   1706                     passpointR1UniqueEss.size());
   1707             incrementTotalUniquePasspointEss(mObservedHotspotR2EssInScanHistogram,
   1708                     passpointR2UniqueEss.size());
   1709             for (Integer count : passpointR1UniqueEss.values()) {
   1710                 incrementPasspointPerUniqueEss(mObservedHotspotR1ApsPerEssInScanHistogram, count);
   1711             }
   1712             for (Integer count : passpointR2UniqueEss.values()) {
   1713                 incrementPasspointPerUniqueEss(mObservedHotspotR2ApsPerEssInScanHistogram, count);
   1714             }
   1715             increment80211mcAps(mObserved80211mcApInScanHistogram, supporting80211mcAps);
   1716         }
   1717     }
   1718 
   1719     /**
   1720      * TODO: (b/72443859) Use notifierTag param to separate metrics for OpenNetworkNotifier and
   1721      * CarrierNetworkNotifier, for this method and all other related metrics.
   1722      */
   1723     /** Increments the occurence of a "Connect to Network" notification. */
   1724     public void incrementConnectToNetworkNotification(String notifierTag, int notificationType) {
   1725         synchronized (mLock) {
   1726             int count = mConnectToNetworkNotificationCount.get(notificationType);
   1727             mConnectToNetworkNotificationCount.put(notificationType, count + 1);
   1728         }
   1729     }
   1730 
   1731     /** Increments the occurence of an "Connect to Network" notification user action. */
   1732     public void incrementConnectToNetworkNotificationAction(String notifierTag,
   1733             int notificationType, int actionType) {
   1734         synchronized (mLock) {
   1735             int key = notificationType * CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER
   1736                     + actionType;
   1737             int count = mConnectToNetworkNotificationActionCount.get(key);
   1738             mConnectToNetworkNotificationActionCount.put(key, count + 1);
   1739         }
   1740     }
   1741 
   1742     /**
   1743      * Sets the number of SSIDs blacklisted from recommendation by the open network notification
   1744      * recommender.
   1745      */
   1746     public void setNetworkRecommenderBlacklistSize(String notifierTag, int size) {
   1747         synchronized (mLock) {
   1748             mOpenNetworkRecommenderBlacklistSize = size;
   1749         }
   1750     }
   1751 
   1752     /** Sets if the available network notification feature is enabled. */
   1753     public void setIsWifiNetworksAvailableNotificationEnabled(String notifierTag, boolean enabled) {
   1754         synchronized (mLock) {
   1755             mIsWifiNetworksAvailableNotificationOn = enabled;
   1756         }
   1757     }
   1758 
   1759     /** Increments the occurence of connection attempts that were initiated unsuccessfully */
   1760     public void incrementNumNetworkRecommendationUpdates(String notifierTag) {
   1761         synchronized (mLock) {
   1762             mNumOpenNetworkRecommendationUpdates++;
   1763         }
   1764     }
   1765 
   1766     /** Increments the occurence of connection attempts that were initiated unsuccessfully */
   1767     public void incrementNumNetworkConnectMessageFailedToSend(String notifierTag) {
   1768         synchronized (mLock) {
   1769             mNumOpenNetworkConnectMessageFailedToSend++;
   1770         }
   1771     }
   1772 
   1773     /** Sets if Connected MAC Randomization feature is enabled */
   1774     public void setIsMacRandomizationOn(boolean enabled) {
   1775         synchronized (mLock) {
   1776             mIsMacRandomizationOn = enabled;
   1777         }
   1778     }
   1779 
   1780     public static final String PROTO_DUMP_ARG = "wifiMetricsProto";
   1781     public static final String CLEAN_DUMP_ARG = "clean";
   1782 
   1783     /**
   1784      * Dump all WifiMetrics. Collects some metrics from ConfigStore, Settings and WifiManager
   1785      * at this time.
   1786      *
   1787      * @param fd unused
   1788      * @param pw PrintWriter for writing dump to
   1789      * @param args [wifiMetricsProto [clean]]
   1790      */
   1791     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1792         synchronized (mLock) {
   1793             consolidateScoringParams();
   1794             if (args != null && args.length > 0 && PROTO_DUMP_ARG.equals(args[0])) {
   1795                 // Dump serialized WifiLog proto
   1796                 consolidateProto(true);
   1797                 for (ConnectionEvent event : mConnectionEventList) {
   1798                     if (mCurrentConnectionEvent != event) {
   1799                         //indicate that automatic bug report has been taken for all valid
   1800                         //connection events
   1801                         event.mConnectionEvent.automaticBugReportTaken = true;
   1802                     }
   1803                 }
   1804                 byte[] wifiMetricsProto = WifiMetricsProto.WifiLog.toByteArray(mWifiLogProto);
   1805                 String metricsProtoDump = Base64.encodeToString(wifiMetricsProto, Base64.DEFAULT);
   1806                 if (args.length > 1 && CLEAN_DUMP_ARG.equals(args[1])) {
   1807                     // Output metrics proto bytes (base64) and nothing else
   1808                     pw.print(metricsProtoDump);
   1809                 } else {
   1810                     // Tag the start and end of the metrics proto bytes
   1811                     pw.println("WifiMetrics:");
   1812                     pw.println(metricsProtoDump);
   1813                     pw.println("EndWifiMetrics");
   1814                 }
   1815                 clear();
   1816             } else {
   1817                 pw.println("WifiMetrics:");
   1818                 pw.println("mConnectionEvents:");
   1819                 for (ConnectionEvent event : mConnectionEventList) {
   1820                     String eventLine = event.toString();
   1821                     if (event == mCurrentConnectionEvent) {
   1822                         eventLine += "CURRENTLY OPEN EVENT";
   1823                     }
   1824                     pw.println(eventLine);
   1825                 }
   1826                 pw.println("mWifiLogProto.numSavedNetworks=" + mWifiLogProto.numSavedNetworks);
   1827                 pw.println("mWifiLogProto.numOpenNetworks=" + mWifiLogProto.numOpenNetworks);
   1828                 pw.println("mWifiLogProto.numPersonalNetworks="
   1829                         + mWifiLogProto.numPersonalNetworks);
   1830                 pw.println("mWifiLogProto.numEnterpriseNetworks="
   1831                         + mWifiLogProto.numEnterpriseNetworks);
   1832                 pw.println("mWifiLogProto.numHiddenNetworks=" + mWifiLogProto.numHiddenNetworks);
   1833                 pw.println("mWifiLogProto.numPasspointNetworks="
   1834                         + mWifiLogProto.numPasspointNetworks);
   1835                 pw.println("mWifiLogProto.isLocationEnabled=" + mWifiLogProto.isLocationEnabled);
   1836                 pw.println("mWifiLogProto.isScanningAlwaysEnabled="
   1837                         + mWifiLogProto.isScanningAlwaysEnabled);
   1838                 pw.println("mWifiLogProto.numNetworksAddedByUser="
   1839                         + mWifiLogProto.numNetworksAddedByUser);
   1840                 pw.println("mWifiLogProto.numNetworksAddedByApps="
   1841                         + mWifiLogProto.numNetworksAddedByApps);
   1842                 pw.println("mWifiLogProto.numNonEmptyScanResults="
   1843                         + mWifiLogProto.numNonEmptyScanResults);
   1844                 pw.println("mWifiLogProto.numEmptyScanResults="
   1845                         + mWifiLogProto.numEmptyScanResults);
   1846                 pw.println("mWifiLogProto.numConnecitvityOneshotScans="
   1847                         + mWifiLogProto.numConnectivityOneshotScans);
   1848                 pw.println("mWifiLogProto.numOneshotScans="
   1849                         + mWifiLogProto.numOneshotScans);
   1850                 pw.println("mWifiLogProto.numBackgroundScans="
   1851                         + mWifiLogProto.numBackgroundScans);
   1852                 pw.println("mWifiLogProto.numExternalAppOneshotScanRequests="
   1853                         + mWifiLogProto.numExternalAppOneshotScanRequests);
   1854                 pw.println("mWifiLogProto.numExternalForegroundAppOneshotScanRequestsThrottled="
   1855                         + mWifiLogProto.numExternalForegroundAppOneshotScanRequestsThrottled);
   1856                 pw.println("mWifiLogProto.numExternalBackgroundAppOneshotScanRequestsThrottled="
   1857                         + mWifiLogProto.numExternalBackgroundAppOneshotScanRequestsThrottled);
   1858 
   1859                 pw.println("mScanReturnEntries:");
   1860                 pw.println("  SCAN_UNKNOWN: " + getScanReturnEntry(
   1861                         WifiMetricsProto.WifiLog.SCAN_UNKNOWN));
   1862                 pw.println("  SCAN_SUCCESS: " + getScanReturnEntry(
   1863                         WifiMetricsProto.WifiLog.SCAN_SUCCESS));
   1864                 pw.println("  SCAN_FAILURE_INTERRUPTED: " + getScanReturnEntry(
   1865                         WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED));
   1866                 pw.println("  SCAN_FAILURE_INVALID_CONFIGURATION: " + getScanReturnEntry(
   1867                         WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION));
   1868                 pw.println("  FAILURE_WIFI_DISABLED: " + getScanReturnEntry(
   1869                         WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED));
   1870 
   1871                 pw.println("mSystemStateEntries: <state><screenOn> : <scansInitiated>");
   1872                 pw.println("  WIFI_UNKNOWN       ON: "
   1873                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, true));
   1874                 pw.println("  WIFI_DISABLED      ON: "
   1875                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, true));
   1876                 pw.println("  WIFI_DISCONNECTED  ON: "
   1877                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, true));
   1878                 pw.println("  WIFI_ASSOCIATED    ON: "
   1879                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, true));
   1880                 pw.println("  WIFI_UNKNOWN      OFF: "
   1881                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, false));
   1882                 pw.println("  WIFI_DISABLED     OFF: "
   1883                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, false));
   1884                 pw.println("  WIFI_DISCONNECTED OFF: "
   1885                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, false));
   1886                 pw.println("  WIFI_ASSOCIATED   OFF: "
   1887                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, false));
   1888                 pw.println("mWifiLogProto.numConnectivityWatchdogPnoGood="
   1889                         + mWifiLogProto.numConnectivityWatchdogPnoGood);
   1890                 pw.println("mWifiLogProto.numConnectivityWatchdogPnoBad="
   1891                         + mWifiLogProto.numConnectivityWatchdogPnoBad);
   1892                 pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundGood="
   1893                         + mWifiLogProto.numConnectivityWatchdogBackgroundGood);
   1894                 pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundBad="
   1895                         + mWifiLogProto.numConnectivityWatchdogBackgroundBad);
   1896                 pw.println("mWifiLogProto.numLastResortWatchdogTriggers="
   1897                         + mWifiLogProto.numLastResortWatchdogTriggers);
   1898                 pw.println("mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal="
   1899                         + mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal);
   1900                 pw.println("mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal="
   1901                         + mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal);
   1902                 pw.println("mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal="
   1903                         + mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal);
   1904                 pw.println("mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal="
   1905                         + mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal);
   1906                 pw.println("mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal="
   1907                         + mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal);
   1908                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation="
   1909                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation);
   1910                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication="
   1911                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication);
   1912                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp="
   1913                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp);
   1914                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadOther="
   1915                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadOther);
   1916                 pw.println("mWifiLogProto.numLastResortWatchdogSuccesses="
   1917                         + mWifiLogProto.numLastResortWatchdogSuccesses);
   1918                 pw.println("mWifiLogProto.recordDurationSec="
   1919                         + ((mClock.getElapsedSinceBootMillis() / 1000) - mRecordStartTimeSec));
   1920 
   1921                 try {
   1922                     JSONObject rssiMap = new JSONObject();
   1923                     for (Map.Entry<Integer, SparseIntArray> entry : mRssiPollCountsMap.entrySet()) {
   1924                         int frequency = entry.getKey();
   1925                         final SparseIntArray histogram = entry.getValue();
   1926                         JSONArray histogramElements = new JSONArray();
   1927                         for (int i = MIN_RSSI_POLL; i <= MAX_RSSI_POLL; i++) {
   1928                             int count = histogram.get(i);
   1929                             if (count == 0) {
   1930                                 continue;
   1931                             }
   1932                             JSONObject histogramElement = new JSONObject();
   1933                             histogramElement.put(Integer.toString(i), count);
   1934                             histogramElements.put(histogramElement);
   1935                         }
   1936                         rssiMap.put(Integer.toString(frequency), histogramElements);
   1937                     }
   1938                     pw.println("mWifiLogProto.rssiPollCount: " + rssiMap.toString());
   1939                 } catch (JSONException e) {
   1940                     pw.println("JSONException occurred: " + e.getMessage());
   1941                 }
   1942 
   1943                 pw.println("mWifiLogProto.rssiPollDeltaCount: Printing counts for ["
   1944                         + MIN_RSSI_DELTA + ", " + MAX_RSSI_DELTA + "]");
   1945                 StringBuilder sb = new StringBuilder();
   1946                 for (int i = MIN_RSSI_DELTA; i <= MAX_RSSI_DELTA; i++) {
   1947                     sb.append(mRssiDeltaCounts.get(i) + " ");
   1948                 }
   1949                 pw.println("  " + sb.toString());
   1950                 pw.print("mWifiLogProto.alertReasonCounts=");
   1951                 sb.setLength(0);
   1952                 for (int i = WifiLoggerHal.WIFI_ALERT_REASON_MIN;
   1953                         i <= WifiLoggerHal.WIFI_ALERT_REASON_MAX; i++) {
   1954                     int count = mWifiAlertReasonCounts.get(i);
   1955                     if (count > 0) {
   1956                         sb.append("(" + i + "," + count + "),");
   1957                     }
   1958                 }
   1959                 if (sb.length() > 1) {
   1960                     sb.setLength(sb.length() - 1);  // strip trailing comma
   1961                     pw.println(sb.toString());
   1962                 } else {
   1963                     pw.println("()");
   1964                 }
   1965                 pw.println("mWifiLogProto.numTotalScanResults="
   1966                         + mWifiLogProto.numTotalScanResults);
   1967                 pw.println("mWifiLogProto.numOpenNetworkScanResults="
   1968                         + mWifiLogProto.numOpenNetworkScanResults);
   1969                 pw.println("mWifiLogProto.numPersonalNetworkScanResults="
   1970                         + mWifiLogProto.numPersonalNetworkScanResults);
   1971                 pw.println("mWifiLogProto.numEnterpriseNetworkScanResults="
   1972                         + mWifiLogProto.numEnterpriseNetworkScanResults);
   1973                 pw.println("mWifiLogProto.numHiddenNetworkScanResults="
   1974                         + mWifiLogProto.numHiddenNetworkScanResults);
   1975                 pw.println("mWifiLogProto.numHotspot2R1NetworkScanResults="
   1976                         + mWifiLogProto.numHotspot2R1NetworkScanResults);
   1977                 pw.println("mWifiLogProto.numHotspot2R2NetworkScanResults="
   1978                         + mWifiLogProto.numHotspot2R2NetworkScanResults);
   1979                 pw.println("mWifiLogProto.numScans=" + mWifiLogProto.numScans);
   1980                 pw.println("mWifiLogProto.WifiScoreCount: [" + MIN_WIFI_SCORE + ", "
   1981                         + MAX_WIFI_SCORE + "]");
   1982                 for (int i = 0; i <= MAX_WIFI_SCORE; i++) {
   1983                     pw.print(mWifiScoreCounts.get(i) + " ");
   1984                 }
   1985                 pw.println(); // add a line after wifi scores
   1986                 pw.println("mWifiLogProto.SoftApManagerReturnCodeCounts:");
   1987                 pw.println("  SUCCESS: " + mSoftApManagerReturnCodeCounts.get(
   1988                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY));
   1989                 pw.println("  FAILED_GENERAL_ERROR: " + mSoftApManagerReturnCodeCounts.get(
   1990                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR));
   1991                 pw.println("  FAILED_NO_CHANNEL: " + mSoftApManagerReturnCodeCounts.get(
   1992                         WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL));
   1993                 pw.print("\n");
   1994                 pw.println("mWifiLogProto.numHalCrashes="
   1995                         + mWifiLogProto.numHalCrashes);
   1996                 pw.println("mWifiLogProto.numWificondCrashes="
   1997                         + mWifiLogProto.numWificondCrashes);
   1998                 pw.println("mWifiLogProto.numSupplicantCrashes="
   1999                         + mWifiLogProto.numSupplicantCrashes);
   2000                 pw.println("mWifiLogProto.numHostapdCrashes="
   2001                         + mWifiLogProto.numHostapdCrashes);
   2002                 pw.println("mWifiLogProto.numSetupClientInterfaceFailureDueToHal="
   2003                         + mWifiLogProto.numSetupClientInterfaceFailureDueToHal);
   2004                 pw.println("mWifiLogProto.numSetupClientInterfaceFailureDueToWificond="
   2005                         + mWifiLogProto.numSetupClientInterfaceFailureDueToWificond);
   2006                 pw.println("mWifiLogProto.numSetupClientInterfaceFailureDueToSupplicant="
   2007                         + mWifiLogProto.numSetupClientInterfaceFailureDueToSupplicant);
   2008                 pw.println("mWifiLogProto.numSetupSoftApInterfaceFailureDueToHal="
   2009                         + mWifiLogProto.numSetupSoftApInterfaceFailureDueToHal);
   2010                 pw.println("mWifiLogProto.numSetupSoftApInterfaceFailureDueToWificond="
   2011                         + mWifiLogProto.numSetupSoftApInterfaceFailureDueToWificond);
   2012                 pw.println("mWifiLogProto.numSetupSoftApInterfaceFailureDueToHostapd="
   2013                         + mWifiLogProto.numSetupSoftApInterfaceFailureDueToHostapd);
   2014                 pw.println("StaEventList:");
   2015                 for (StaEventWithTime event : mStaEventList) {
   2016                     pw.println(event);
   2017                 }
   2018 
   2019                 pw.println("mWifiLogProto.numPasspointProviders="
   2020                         + mWifiLogProto.numPasspointProviders);
   2021                 pw.println("mWifiLogProto.numPasspointProviderInstallation="
   2022                         + mWifiLogProto.numPasspointProviderInstallation);
   2023                 pw.println("mWifiLogProto.numPasspointProviderInstallSuccess="
   2024                         + mWifiLogProto.numPasspointProviderInstallSuccess);
   2025                 pw.println("mWifiLogProto.numPasspointProviderUninstallation="
   2026                         + mWifiLogProto.numPasspointProviderUninstallation);
   2027                 pw.println("mWifiLogProto.numPasspointProviderUninstallSuccess="
   2028                         + mWifiLogProto.numPasspointProviderUninstallSuccess);
   2029                 pw.println("mWifiLogProto.numPasspointProvidersSuccessfullyConnected="
   2030                         + mWifiLogProto.numPasspointProvidersSuccessfullyConnected);
   2031                 pw.println("mWifiLogProto.numRadioModeChangeToMcc="
   2032                         + mWifiLogProto.numRadioModeChangeToMcc);
   2033                 pw.println("mWifiLogProto.numRadioModeChangeToScc="
   2034                         + mWifiLogProto.numRadioModeChangeToScc);
   2035                 pw.println("mWifiLogProto.numRadioModeChangeToSbs="
   2036                         + mWifiLogProto.numRadioModeChangeToSbs);
   2037                 pw.println("mWifiLogProto.numRadioModeChangeToDbs="
   2038                         + mWifiLogProto.numRadioModeChangeToDbs);
   2039                 pw.println("mWifiLogProto.numSoftApUserBandPreferenceUnsatisfied="
   2040                         + mWifiLogProto.numSoftApUserBandPreferenceUnsatisfied);
   2041                 pw.println("mTotalSsidsInScanHistogram:"
   2042                         + mTotalSsidsInScanHistogram.toString());
   2043                 pw.println("mTotalBssidsInScanHistogram:"
   2044                         + mTotalBssidsInScanHistogram.toString());
   2045                 pw.println("mAvailableOpenSsidsInScanHistogram:"
   2046                         + mAvailableOpenSsidsInScanHistogram.toString());
   2047                 pw.println("mAvailableOpenBssidsInScanHistogram:"
   2048                         + mAvailableOpenBssidsInScanHistogram.toString());
   2049                 pw.println("mAvailableSavedSsidsInScanHistogram:"
   2050                         + mAvailableSavedSsidsInScanHistogram.toString());
   2051                 pw.println("mAvailableSavedBssidsInScanHistogram:"
   2052                         + mAvailableSavedBssidsInScanHistogram.toString());
   2053                 pw.println("mAvailableOpenOrSavedSsidsInScanHistogram:"
   2054                         + mAvailableOpenOrSavedSsidsInScanHistogram.toString());
   2055                 pw.println("mAvailableOpenOrSavedBssidsInScanHistogram:"
   2056                         + mAvailableOpenOrSavedBssidsInScanHistogram.toString());
   2057                 pw.println("mAvailableSavedPasspointProviderProfilesInScanHistogram:"
   2058                         + mAvailableSavedPasspointProviderProfilesInScanHistogram.toString());
   2059                 pw.println("mAvailableSavedPasspointProviderBssidsInScanHistogram:"
   2060                         + mAvailableSavedPasspointProviderBssidsInScanHistogram.toString());
   2061                 pw.println("mWifiLogProto.partialAllSingleScanListenerResults="
   2062                         + mWifiLogProto.partialAllSingleScanListenerResults);
   2063                 pw.println("mWifiLogProto.fullBandAllSingleScanListenerResults="
   2064                         + mWifiLogProto.fullBandAllSingleScanListenerResults);
   2065                 pw.println("mWifiAwareMetrics:");
   2066                 mWifiAwareMetrics.dump(fd, pw, args);
   2067                 pw.println("mRttMetrics:");
   2068                 mRttMetrics.dump(fd, pw, args);
   2069 
   2070                 pw.println("mPnoScanMetrics.numPnoScanAttempts="
   2071                         + mPnoScanMetrics.numPnoScanAttempts);
   2072                 pw.println("mPnoScanMetrics.numPnoScanFailed="
   2073                         + mPnoScanMetrics.numPnoScanFailed);
   2074                 pw.println("mPnoScanMetrics.numPnoScanStartedOverOffload="
   2075                         + mPnoScanMetrics.numPnoScanStartedOverOffload);
   2076                 pw.println("mPnoScanMetrics.numPnoScanFailedOverOffload="
   2077                         + mPnoScanMetrics.numPnoScanFailedOverOffload);
   2078                 pw.println("mPnoScanMetrics.numPnoFoundNetworkEvents="
   2079                         + mPnoScanMetrics.numPnoFoundNetworkEvents);
   2080 
   2081                 pw.println("mWifiLogProto.connectToNetworkNotificationCount="
   2082                         + mConnectToNetworkNotificationCount.toString());
   2083                 pw.println("mWifiLogProto.connectToNetworkNotificationActionCount="
   2084                         + mConnectToNetworkNotificationActionCount.toString());
   2085                 pw.println("mWifiLogProto.openNetworkRecommenderBlacklistSize="
   2086                         + mOpenNetworkRecommenderBlacklistSize);
   2087                 pw.println("mWifiLogProto.isWifiNetworksAvailableNotificationOn="
   2088                         + mIsWifiNetworksAvailableNotificationOn);
   2089                 pw.println("mWifiLogProto.numOpenNetworkRecommendationUpdates="
   2090                         + mNumOpenNetworkRecommendationUpdates);
   2091                 pw.println("mWifiLogProto.numOpenNetworkConnectMessageFailedToSend="
   2092                         + mNumOpenNetworkConnectMessageFailedToSend);
   2093 
   2094                 pw.println("mWifiLogProto.observedHotspotR1ApInScanHistogram="
   2095                         + mObservedHotspotR1ApInScanHistogram);
   2096                 pw.println("mWifiLogProto.observedHotspotR2ApInScanHistogram="
   2097                         + mObservedHotspotR2ApInScanHistogram);
   2098                 pw.println("mWifiLogProto.observedHotspotR1EssInScanHistogram="
   2099                         + mObservedHotspotR1EssInScanHistogram);
   2100                 pw.println("mWifiLogProto.observedHotspotR2EssInScanHistogram="
   2101                         + mObservedHotspotR2EssInScanHistogram);
   2102                 pw.println("mWifiLogProto.observedHotspotR1ApsPerEssInScanHistogram="
   2103                         + mObservedHotspotR1ApsPerEssInScanHistogram);
   2104                 pw.println("mWifiLogProto.observedHotspotR2ApsPerEssInScanHistogram="
   2105                         + mObservedHotspotR2ApsPerEssInScanHistogram);
   2106 
   2107                 pw.println("mWifiLogProto.observed80211mcSupportingApsInScanHistogram"
   2108                         + mObserved80211mcApInScanHistogram);
   2109 
   2110                 pw.println("mSoftApTetheredEvents:");
   2111                 for (SoftApConnectedClientsEvent event : mSoftApEventListTethered) {
   2112                     StringBuilder eventLine = new StringBuilder();
   2113                     eventLine.append("event_type=" + event.eventType);
   2114                     eventLine.append(",time_stamp_millis=" + event.timeStampMillis);
   2115                     eventLine.append(",num_connected_clients=" + event.numConnectedClients);
   2116                     eventLine.append(",channel_frequency=" + event.channelFrequency);
   2117                     eventLine.append(",channel_bandwidth=" + event.channelBandwidth);
   2118                     pw.println(eventLine.toString());
   2119                 }
   2120                 pw.println("mSoftApLocalOnlyEvents:");
   2121                 for (SoftApConnectedClientsEvent event : mSoftApEventListLocalOnly) {
   2122                     StringBuilder eventLine = new StringBuilder();
   2123                     eventLine.append("event_type=" + event.eventType);
   2124                     eventLine.append(",time_stamp_millis=" + event.timeStampMillis);
   2125                     eventLine.append(",num_connected_clients=" + event.numConnectedClients);
   2126                     eventLine.append(",channel_frequency=" + event.channelFrequency);
   2127                     eventLine.append(",channel_bandwidth=" + event.channelBandwidth);
   2128                     pw.println(eventLine.toString());
   2129                 }
   2130 
   2131                 pw.println("mWpsMetrics.numWpsAttempts="
   2132                         + mWpsMetrics.numWpsAttempts);
   2133                 pw.println("mWpsMetrics.numWpsSuccess="
   2134                         + mWpsMetrics.numWpsSuccess);
   2135                 pw.println("mWpsMetrics.numWpsStartFailure="
   2136                         + mWpsMetrics.numWpsStartFailure);
   2137                 pw.println("mWpsMetrics.numWpsOverlapFailure="
   2138                         + mWpsMetrics.numWpsOverlapFailure);
   2139                 pw.println("mWpsMetrics.numWpsTimeoutFailure="
   2140                         + mWpsMetrics.numWpsTimeoutFailure);
   2141                 pw.println("mWpsMetrics.numWpsOtherConnectionFailure="
   2142                         + mWpsMetrics.numWpsOtherConnectionFailure);
   2143                 pw.println("mWpsMetrics.numWpsSupplicantFailure="
   2144                         + mWpsMetrics.numWpsSupplicantFailure);
   2145                 pw.println("mWpsMetrics.numWpsCancellation="
   2146                         + mWpsMetrics.numWpsCancellation);
   2147 
   2148                 mWifiPowerMetrics.dump(pw);
   2149                 mWifiWakeMetrics.dump(pw);
   2150 
   2151                 pw.println("mWifiLogProto.isMacRandomizationOn=" + mIsMacRandomizationOn);
   2152                 pw.println("mWifiLogProto.scoreExperimentId=" + mWifiLogProto.scoreExperimentId);
   2153             }
   2154         }
   2155     }
   2156 
   2157     /**
   2158      * Update various counts of saved network types
   2159      * @param networks List of WifiConfigurations representing all saved networks, must not be null
   2160      */
   2161     public void updateSavedNetworks(List<WifiConfiguration> networks) {
   2162         synchronized (mLock) {
   2163             mWifiLogProto.numSavedNetworks = networks.size();
   2164             mWifiLogProto.numOpenNetworks = 0;
   2165             mWifiLogProto.numPersonalNetworks = 0;
   2166             mWifiLogProto.numEnterpriseNetworks = 0;
   2167             mWifiLogProto.numNetworksAddedByUser = 0;
   2168             mWifiLogProto.numNetworksAddedByApps = 0;
   2169             mWifiLogProto.numHiddenNetworks = 0;
   2170             mWifiLogProto.numPasspointNetworks = 0;
   2171             for (WifiConfiguration config : networks) {
   2172                 if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) {
   2173                     mWifiLogProto.numOpenNetworks++;
   2174                 } else if (config.isEnterprise()) {
   2175                     mWifiLogProto.numEnterpriseNetworks++;
   2176                 } else {
   2177                     mWifiLogProto.numPersonalNetworks++;
   2178                 }
   2179                 if (config.selfAdded) {
   2180                     mWifiLogProto.numNetworksAddedByUser++;
   2181                 } else {
   2182                     mWifiLogProto.numNetworksAddedByApps++;
   2183                 }
   2184                 if (config.hiddenSSID) {
   2185                     mWifiLogProto.numHiddenNetworks++;
   2186                 }
   2187                 if (config.isPasspoint()) {
   2188                     mWifiLogProto.numPasspointNetworks++;
   2189                 }
   2190             }
   2191         }
   2192     }
   2193 
   2194     /**
   2195      * Update metrics for saved Passpoint profiles.
   2196      *
   2197      * @param numSavedProfiles The number of saved Passpoint profiles
   2198      * @param numConnectedProfiles The number of saved Passpoint profiles that have ever resulted
   2199      *                             in a successful network connection
   2200      */
   2201     public void updateSavedPasspointProfiles(int numSavedProfiles, int numConnectedProfiles) {
   2202         synchronized (mLock) {
   2203             mWifiLogProto.numPasspointProviders = numSavedProfiles;
   2204             mWifiLogProto.numPasspointProvidersSuccessfullyConnected = numConnectedProfiles;
   2205         }
   2206     }
   2207 
   2208     /**
   2209      * append the separate ConnectionEvent, SystemStateEntry and ScanReturnCode collections to their
   2210      * respective lists within mWifiLogProto
   2211      *
   2212      * @param incremental Only include ConnectionEvents created since last automatic bug report
   2213      */
   2214     private void consolidateProto(boolean incremental) {
   2215         List<WifiMetricsProto.ConnectionEvent> events = new ArrayList<>();
   2216         List<WifiMetricsProto.RssiPollCount> rssis = new ArrayList<>();
   2217         List<WifiMetricsProto.RssiPollCount> rssiDeltas = new ArrayList<>();
   2218         List<WifiMetricsProto.AlertReasonCount> alertReasons = new ArrayList<>();
   2219         List<WifiMetricsProto.WifiScoreCount> scores = new ArrayList<>();
   2220         synchronized (mLock) {
   2221             for (ConnectionEvent event : mConnectionEventList) {
   2222                 // If this is not incremental, dump full ConnectionEvent list
   2223                 // Else Dump all un-dumped events except for the current one
   2224                 if (!incremental || ((mCurrentConnectionEvent != event)
   2225                         && !event.mConnectionEvent.automaticBugReportTaken)) {
   2226                     //Get all ConnectionEvents that haven not been dumped as a proto, also exclude
   2227                     //the current active un-ended connection event
   2228                     events.add(event.mConnectionEvent);
   2229                     if (incremental) {
   2230                         event.mConnectionEvent.automaticBugReportTaken = true;
   2231                     }
   2232                 }
   2233             }
   2234             if (events.size() > 0) {
   2235                 mWifiLogProto.connectionEvent = events.toArray(mWifiLogProto.connectionEvent);
   2236             }
   2237 
   2238             //Convert the SparseIntArray of scanReturnEntry integers into ScanReturnEntry proto list
   2239             mWifiLogProto.scanReturnEntries =
   2240                     new WifiMetricsProto.WifiLog.ScanReturnEntry[mScanReturnEntries.size()];
   2241             for (int i = 0; i < mScanReturnEntries.size(); i++) {
   2242                 mWifiLogProto.scanReturnEntries[i] = new WifiMetricsProto.WifiLog.ScanReturnEntry();
   2243                 mWifiLogProto.scanReturnEntries[i].scanReturnCode = mScanReturnEntries.keyAt(i);
   2244                 mWifiLogProto.scanReturnEntries[i].scanResultsCount = mScanReturnEntries.valueAt(i);
   2245             }
   2246 
   2247             // Convert the SparseIntArray of systemStateEntry into WifiSystemStateEntry proto list
   2248             // This one is slightly more complex, as the Sparse are indexed with:
   2249             //     key: wifiState * 2 + isScreenOn, value: wifiStateCount
   2250             mWifiLogProto.wifiSystemStateEntries =
   2251                     new WifiMetricsProto.WifiLog
   2252                     .WifiSystemStateEntry[mWifiSystemStateEntries.size()];
   2253             for (int i = 0; i < mWifiSystemStateEntries.size(); i++) {
   2254                 mWifiLogProto.wifiSystemStateEntries[i] =
   2255                         new WifiMetricsProto.WifiLog.WifiSystemStateEntry();
   2256                 mWifiLogProto.wifiSystemStateEntries[i].wifiState =
   2257                         mWifiSystemStateEntries.keyAt(i) / 2;
   2258                 mWifiLogProto.wifiSystemStateEntries[i].wifiStateCount =
   2259                         mWifiSystemStateEntries.valueAt(i);
   2260                 mWifiLogProto.wifiSystemStateEntries[i].isScreenOn =
   2261                         (mWifiSystemStateEntries.keyAt(i) % 2) > 0;
   2262             }
   2263             mWifiLogProto.recordDurationSec = (int) ((mClock.getElapsedSinceBootMillis() / 1000)
   2264                     - mRecordStartTimeSec);
   2265 
   2266             /**
   2267              * Convert the SparseIntArrays of RSSI poll rssi, counts, and frequency to the
   2268              * proto's repeated ntKeyVal array.
   2269              */
   2270             for (Map.Entry<Integer, SparseIntArray> entry : mRssiPollCountsMap.entrySet()) {
   2271                 int frequency = entry.getKey();
   2272                 SparseIntArray histogram = entry.getValue();
   2273                 for (int i = 0; i < histogram.size(); i++) {
   2274                     WifiMetricsProto.RssiPollCount keyVal = new WifiMetricsProto.RssiPollCount();
   2275                     keyVal.rssi = histogram.keyAt(i);
   2276                     keyVal.count = histogram.valueAt(i);
   2277                     keyVal.frequency = frequency;
   2278                     rssis.add(keyVal);
   2279                 }
   2280             }
   2281             mWifiLogProto.rssiPollRssiCount = rssis.toArray(mWifiLogProto.rssiPollRssiCount);
   2282 
   2283             /**
   2284              * Convert the SparseIntArray of RSSI delta rssi's and counts to the proto's repeated
   2285              * IntKeyVal array.
   2286              */
   2287             for (int i = 0; i < mRssiDeltaCounts.size(); i++) {
   2288                 WifiMetricsProto.RssiPollCount keyVal = new WifiMetricsProto.RssiPollCount();
   2289                 keyVal.rssi = mRssiDeltaCounts.keyAt(i);
   2290                 keyVal.count = mRssiDeltaCounts.valueAt(i);
   2291                 rssiDeltas.add(keyVal);
   2292             }
   2293             mWifiLogProto.rssiPollDeltaCount = rssiDeltas.toArray(mWifiLogProto.rssiPollDeltaCount);
   2294 
   2295 
   2296 
   2297             /**
   2298              * Convert the SparseIntArray of alert reasons and counts to the proto's repeated
   2299              * IntKeyVal array.
   2300              */
   2301             for (int i = 0; i < mWifiAlertReasonCounts.size(); i++) {
   2302                 WifiMetricsProto.AlertReasonCount keyVal = new WifiMetricsProto.AlertReasonCount();
   2303                 keyVal.reason = mWifiAlertReasonCounts.keyAt(i);
   2304                 keyVal.count = mWifiAlertReasonCounts.valueAt(i);
   2305                 alertReasons.add(keyVal);
   2306             }
   2307             mWifiLogProto.alertReasonCount = alertReasons.toArray(mWifiLogProto.alertReasonCount);
   2308 
   2309             /**
   2310             *  Convert the SparseIntArray of Wifi Score and counts to proto's repeated
   2311             * IntKeyVal array.
   2312             */
   2313             for (int score = 0; score < mWifiScoreCounts.size(); score++) {
   2314                 WifiMetricsProto.WifiScoreCount keyVal = new WifiMetricsProto.WifiScoreCount();
   2315                 keyVal.score = mWifiScoreCounts.keyAt(score);
   2316                 keyVal.count = mWifiScoreCounts.valueAt(score);
   2317                 scores.add(keyVal);
   2318             }
   2319             mWifiLogProto.wifiScoreCount = scores.toArray(mWifiLogProto.wifiScoreCount);
   2320 
   2321             /**
   2322              * Convert the SparseIntArray of SoftAp Return codes and counts to proto's repeated
   2323              * IntKeyVal array.
   2324              */
   2325             int codeCounts = mSoftApManagerReturnCodeCounts.size();
   2326             mWifiLogProto.softApReturnCode = new WifiMetricsProto.SoftApReturnCodeCount[codeCounts];
   2327             for (int sapCode = 0; sapCode < codeCounts; sapCode++) {
   2328                 mWifiLogProto.softApReturnCode[sapCode] =
   2329                         new WifiMetricsProto.SoftApReturnCodeCount();
   2330                 mWifiLogProto.softApReturnCode[sapCode].startResult =
   2331                         mSoftApManagerReturnCodeCounts.keyAt(sapCode);
   2332                 mWifiLogProto.softApReturnCode[sapCode].count =
   2333                         mSoftApManagerReturnCodeCounts.valueAt(sapCode);
   2334             }
   2335 
   2336             /**
   2337              * Convert StaEventList to array of StaEvents
   2338              */
   2339             mWifiLogProto.staEventList = new StaEvent[mStaEventList.size()];
   2340             for (int i = 0; i < mStaEventList.size(); i++) {
   2341                 mWifiLogProto.staEventList[i] = mStaEventList.get(i).staEvent;
   2342             }
   2343             mWifiLogProto.totalSsidsInScanHistogram =
   2344                     makeNumConnectableNetworksBucketArray(mTotalSsidsInScanHistogram);
   2345             mWifiLogProto.totalBssidsInScanHistogram =
   2346                     makeNumConnectableNetworksBucketArray(mTotalBssidsInScanHistogram);
   2347             mWifiLogProto.availableOpenSsidsInScanHistogram =
   2348                     makeNumConnectableNetworksBucketArray(mAvailableOpenSsidsInScanHistogram);
   2349             mWifiLogProto.availableOpenBssidsInScanHistogram =
   2350                     makeNumConnectableNetworksBucketArray(mAvailableOpenBssidsInScanHistogram);
   2351             mWifiLogProto.availableSavedSsidsInScanHistogram =
   2352                     makeNumConnectableNetworksBucketArray(mAvailableSavedSsidsInScanHistogram);
   2353             mWifiLogProto.availableSavedBssidsInScanHistogram =
   2354                     makeNumConnectableNetworksBucketArray(mAvailableSavedBssidsInScanHistogram);
   2355             mWifiLogProto.availableOpenOrSavedSsidsInScanHistogram =
   2356                     makeNumConnectableNetworksBucketArray(
   2357                     mAvailableOpenOrSavedSsidsInScanHistogram);
   2358             mWifiLogProto.availableOpenOrSavedBssidsInScanHistogram =
   2359                     makeNumConnectableNetworksBucketArray(
   2360                     mAvailableOpenOrSavedBssidsInScanHistogram);
   2361             mWifiLogProto.availableSavedPasspointProviderProfilesInScanHistogram =
   2362                     makeNumConnectableNetworksBucketArray(
   2363                     mAvailableSavedPasspointProviderProfilesInScanHistogram);
   2364             mWifiLogProto.availableSavedPasspointProviderBssidsInScanHistogram =
   2365                     makeNumConnectableNetworksBucketArray(
   2366                     mAvailableSavedPasspointProviderBssidsInScanHistogram);
   2367             mWifiLogProto.wifiAwareLog = mWifiAwareMetrics.consolidateProto();
   2368             mWifiLogProto.wifiRttLog = mRttMetrics.consolidateProto();
   2369 
   2370             mWifiLogProto.pnoScanMetrics = mPnoScanMetrics;
   2371 
   2372             /**
   2373              * Convert the SparseIntArray of "Connect to Network" notification types and counts to
   2374              * proto's repeated IntKeyVal array.
   2375              */
   2376             ConnectToNetworkNotificationAndActionCount[] notificationCountArray =
   2377                     new ConnectToNetworkNotificationAndActionCount[
   2378                             mConnectToNetworkNotificationCount.size()];
   2379             for (int i = 0; i < mConnectToNetworkNotificationCount.size(); i++) {
   2380                 ConnectToNetworkNotificationAndActionCount keyVal =
   2381                         new ConnectToNetworkNotificationAndActionCount();
   2382                 keyVal.notification = mConnectToNetworkNotificationCount.keyAt(i);
   2383                 keyVal.recommender =
   2384                         ConnectToNetworkNotificationAndActionCount.RECOMMENDER_OPEN;
   2385                 keyVal.count = mConnectToNetworkNotificationCount.valueAt(i);
   2386                 notificationCountArray[i] = keyVal;
   2387             }
   2388             mWifiLogProto.connectToNetworkNotificationCount = notificationCountArray;
   2389 
   2390             /**
   2391              * Convert the SparseIntArray of "Connect to Network" notification types and counts to
   2392              * proto's repeated IntKeyVal array.
   2393              */
   2394             ConnectToNetworkNotificationAndActionCount[] notificationActionCountArray =
   2395                     new ConnectToNetworkNotificationAndActionCount[
   2396                             mConnectToNetworkNotificationActionCount.size()];
   2397             for (int i = 0; i < mConnectToNetworkNotificationActionCount.size(); i++) {
   2398                 ConnectToNetworkNotificationAndActionCount keyVal =
   2399                         new ConnectToNetworkNotificationAndActionCount();
   2400                 int key = mConnectToNetworkNotificationActionCount.keyAt(i);
   2401                 keyVal.notification = key / CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER;
   2402                 keyVal.action = key % CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER;
   2403                 keyVal.recommender =
   2404                         ConnectToNetworkNotificationAndActionCount.RECOMMENDER_OPEN;
   2405                 keyVal.count = mConnectToNetworkNotificationActionCount.valueAt(i);
   2406                 notificationActionCountArray[i] = keyVal;
   2407             }
   2408             mWifiLogProto.connectToNetworkNotificationActionCount = notificationActionCountArray;
   2409 
   2410             mWifiLogProto.openNetworkRecommenderBlacklistSize =
   2411                     mOpenNetworkRecommenderBlacklistSize;
   2412             mWifiLogProto.isWifiNetworksAvailableNotificationOn =
   2413                     mIsWifiNetworksAvailableNotificationOn;
   2414             mWifiLogProto.numOpenNetworkRecommendationUpdates =
   2415                     mNumOpenNetworkRecommendationUpdates;
   2416             mWifiLogProto.numOpenNetworkConnectMessageFailedToSend =
   2417                     mNumOpenNetworkConnectMessageFailedToSend;
   2418 
   2419             mWifiLogProto.observedHotspotR1ApsInScanHistogram =
   2420                     makeNumConnectableNetworksBucketArray(mObservedHotspotR1ApInScanHistogram);
   2421             mWifiLogProto.observedHotspotR2ApsInScanHistogram =
   2422                     makeNumConnectableNetworksBucketArray(mObservedHotspotR2ApInScanHistogram);
   2423             mWifiLogProto.observedHotspotR1EssInScanHistogram =
   2424                     makeNumConnectableNetworksBucketArray(mObservedHotspotR1EssInScanHistogram);
   2425             mWifiLogProto.observedHotspotR2EssInScanHistogram =
   2426                     makeNumConnectableNetworksBucketArray(mObservedHotspotR2EssInScanHistogram);
   2427             mWifiLogProto.observedHotspotR1ApsPerEssInScanHistogram =
   2428                     makeNumConnectableNetworksBucketArray(
   2429                             mObservedHotspotR1ApsPerEssInScanHistogram);
   2430             mWifiLogProto.observedHotspotR2ApsPerEssInScanHistogram =
   2431                     makeNumConnectableNetworksBucketArray(
   2432                             mObservedHotspotR2ApsPerEssInScanHistogram);
   2433 
   2434             mWifiLogProto.observed80211McSupportingApsInScanHistogram =
   2435                     makeNumConnectableNetworksBucketArray(mObserved80211mcApInScanHistogram);
   2436 
   2437             if (mSoftApEventListTethered.size() > 0) {
   2438                 mWifiLogProto.softApConnectedClientsEventsTethered =
   2439                         mSoftApEventListTethered.toArray(
   2440                         mWifiLogProto.softApConnectedClientsEventsTethered);
   2441             }
   2442             if (mSoftApEventListLocalOnly.size() > 0) {
   2443                 mWifiLogProto.softApConnectedClientsEventsLocalOnly =
   2444                         mSoftApEventListLocalOnly.toArray(
   2445                         mWifiLogProto.softApConnectedClientsEventsLocalOnly);
   2446             }
   2447 
   2448             mWifiLogProto.wpsMetrics = mWpsMetrics;
   2449             mWifiLogProto.wifiPowerStats = mWifiPowerMetrics.buildProto();
   2450             mWifiLogProto.wifiWakeStats = mWifiWakeMetrics.buildProto();
   2451             mWifiLogProto.isMacRandomizationOn = mIsMacRandomizationOn;
   2452         }
   2453     }
   2454 
   2455     /** Sets the scoring experiment id to current value */
   2456     private void consolidateScoringParams() {
   2457         synchronized (mLock) {
   2458             if (mScoringParams != null) {
   2459                 int experimentIdentifier = mScoringParams.getExperimentIdentifier();
   2460                 if (experimentIdentifier == 0) {
   2461                     mWifiLogProto.scoreExperimentId = "";
   2462                 } else {
   2463                     mWifiLogProto.scoreExperimentId = "x" + experimentIdentifier;
   2464                 }
   2465             }
   2466         }
   2467     }
   2468 
   2469     private WifiMetricsProto.NumConnectableNetworksBucket[] makeNumConnectableNetworksBucketArray(
   2470             SparseIntArray sia) {
   2471         WifiMetricsProto.NumConnectableNetworksBucket[] array =
   2472                 new WifiMetricsProto.NumConnectableNetworksBucket[sia.size()];
   2473         for (int i = 0; i < sia.size(); i++) {
   2474             WifiMetricsProto.NumConnectableNetworksBucket keyVal =
   2475                     new WifiMetricsProto.NumConnectableNetworksBucket();
   2476             keyVal.numConnectableNetworks = sia.keyAt(i);
   2477             keyVal.count = sia.valueAt(i);
   2478             array[i] = keyVal;
   2479         }
   2480         return array;
   2481     }
   2482 
   2483     /**
   2484      * Clear all WifiMetrics, except for currentConnectionEvent and Open Network Notification
   2485      * feature enabled state, blacklist size.
   2486      */
   2487     private void clear() {
   2488         synchronized (mLock) {
   2489             mConnectionEventList.clear();
   2490             if (mCurrentConnectionEvent != null) {
   2491                 mConnectionEventList.add(mCurrentConnectionEvent);
   2492             }
   2493             mScanReturnEntries.clear();
   2494             mWifiSystemStateEntries.clear();
   2495             mRecordStartTimeSec = mClock.getElapsedSinceBootMillis() / 1000;
   2496             mRssiPollCountsMap.clear();
   2497             mRssiDeltaCounts.clear();
   2498             mWifiAlertReasonCounts.clear();
   2499             mWifiScoreCounts.clear();
   2500             mWifiLogProto.clear();
   2501             mScanResultRssiTimestampMillis = -1;
   2502             mSoftApManagerReturnCodeCounts.clear();
   2503             mStaEventList.clear();
   2504             mWifiAwareMetrics.clear();
   2505             mRttMetrics.clear();
   2506             mTotalSsidsInScanHistogram.clear();
   2507             mTotalBssidsInScanHistogram.clear();
   2508             mAvailableOpenSsidsInScanHistogram.clear();
   2509             mAvailableOpenBssidsInScanHistogram.clear();
   2510             mAvailableSavedSsidsInScanHistogram.clear();
   2511             mAvailableSavedBssidsInScanHistogram.clear();
   2512             mAvailableOpenOrSavedSsidsInScanHistogram.clear();
   2513             mAvailableOpenOrSavedBssidsInScanHistogram.clear();
   2514             mAvailableSavedPasspointProviderProfilesInScanHistogram.clear();
   2515             mAvailableSavedPasspointProviderBssidsInScanHistogram.clear();
   2516             mPnoScanMetrics.clear();
   2517             mConnectToNetworkNotificationCount.clear();
   2518             mConnectToNetworkNotificationActionCount.clear();
   2519             mNumOpenNetworkRecommendationUpdates = 0;
   2520             mNumOpenNetworkConnectMessageFailedToSend = 0;
   2521             mObservedHotspotR1ApInScanHistogram.clear();
   2522             mObservedHotspotR2ApInScanHistogram.clear();
   2523             mObservedHotspotR1EssInScanHistogram.clear();
   2524             mObservedHotspotR2EssInScanHistogram.clear();
   2525             mObservedHotspotR1ApsPerEssInScanHistogram.clear();
   2526             mObservedHotspotR2ApsPerEssInScanHistogram.clear();
   2527             mSoftApEventListTethered.clear();
   2528             mSoftApEventListLocalOnly.clear();
   2529             mWpsMetrics.clear();
   2530             mWifiWakeMetrics.clear();
   2531             mObserved80211mcApInScanHistogram.clear();
   2532         }
   2533     }
   2534 
   2535     /**
   2536      *  Set screen state (On/Off)
   2537      */
   2538     public void setScreenState(boolean screenOn) {
   2539         synchronized (mLock) {
   2540             mScreenOn = screenOn;
   2541         }
   2542     }
   2543 
   2544     /**
   2545      *  Set wifi state (WIFI_UNKNOWN, WIFI_DISABLED, WIFI_DISCONNECTED, WIFI_ASSOCIATED)
   2546      */
   2547     public void setWifiState(int wifiState) {
   2548         synchronized (mLock) {
   2549             mWifiState = wifiState;
   2550             mWifiWins = (wifiState == WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
   2551         }
   2552     }
   2553 
   2554     /**
   2555      * Message handler for interesting WifiMonitor messages. Generates StaEvents
   2556      */
   2557     private void processMessage(Message msg) {
   2558         StaEvent event = new StaEvent();
   2559         boolean logEvent = true;
   2560         switch (msg.what) {
   2561             case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
   2562                 event.type = StaEvent.TYPE_ASSOCIATION_REJECTION_EVENT;
   2563                 event.associationTimedOut = msg.arg1 > 0 ? true : false;
   2564                 event.status = msg.arg2;
   2565                 break;
   2566             case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
   2567                 event.type = StaEvent.TYPE_AUTHENTICATION_FAILURE_EVENT;
   2568                 switch (msg.arg1) {
   2569                     case WifiManager.ERROR_AUTH_FAILURE_NONE:
   2570                         event.authFailureReason = StaEvent.AUTH_FAILURE_NONE;
   2571                         break;
   2572                     case WifiManager.ERROR_AUTH_FAILURE_TIMEOUT:
   2573                         event.authFailureReason = StaEvent.AUTH_FAILURE_TIMEOUT;
   2574                         break;
   2575                     case WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD:
   2576                         event.authFailureReason = StaEvent.AUTH_FAILURE_WRONG_PSWD;
   2577                         break;
   2578                     case WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE:
   2579                         event.authFailureReason = StaEvent.AUTH_FAILURE_EAP_FAILURE;
   2580                         break;
   2581                     default:
   2582                         break;
   2583                 }
   2584                 break;
   2585             case WifiMonitor.NETWORK_CONNECTION_EVENT:
   2586                 event.type = StaEvent.TYPE_NETWORK_CONNECTION_EVENT;
   2587                 break;
   2588             case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
   2589                 event.type = StaEvent.TYPE_NETWORK_DISCONNECTION_EVENT;
   2590                 event.reason = msg.arg2;
   2591                 event.localGen = msg.arg1 == 0 ? false : true;
   2592                 break;
   2593             case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
   2594                 logEvent = false;
   2595                 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
   2596                 mSupplicantStateChangeBitmask |= supplicantStateToBit(stateChangeResult.state);
   2597                 break;
   2598             case WifiStateMachine.CMD_ASSOCIATED_BSSID:
   2599                 event.type = StaEvent.TYPE_CMD_ASSOCIATED_BSSID;
   2600                 break;
   2601             case WifiStateMachine.CMD_TARGET_BSSID:
   2602                 event.type = StaEvent.TYPE_CMD_TARGET_BSSID;
   2603                 break;
   2604             default:
   2605                 return;
   2606         }
   2607         if (logEvent) {
   2608             addStaEvent(event);
   2609         }
   2610     }
   2611     /**
   2612      * Log a StaEvent from WifiStateMachine. The StaEvent must not be one of the supplicant
   2613      * generated event types, which are logged through 'sendMessage'
   2614      * @param type StaEvent.EventType describing the event
   2615      */
   2616     public void logStaEvent(int type) {
   2617         logStaEvent(type, StaEvent.DISCONNECT_UNKNOWN, null);
   2618     }
   2619     /**
   2620      * Log a StaEvent from WifiStateMachine. The StaEvent must not be one of the supplicant
   2621      * generated event types, which are logged through 'sendMessage'
   2622      * @param type StaEvent.EventType describing the event
   2623      * @param config WifiConfiguration for a framework initiated connection attempt
   2624      */
   2625     public void logStaEvent(int type, WifiConfiguration config) {
   2626         logStaEvent(type, StaEvent.DISCONNECT_UNKNOWN, config);
   2627     }
   2628     /**
   2629      * Log a StaEvent from WifiStateMachine. The StaEvent must not be one of the supplicant
   2630      * generated event types, which are logged through 'sendMessage'
   2631      * @param type StaEvent.EventType describing the event
   2632      * @param frameworkDisconnectReason StaEvent.FrameworkDisconnectReason explaining why framework
   2633      *                                  initiated a FRAMEWORK_DISCONNECT
   2634      */
   2635     public void logStaEvent(int type, int frameworkDisconnectReason) {
   2636         logStaEvent(type, frameworkDisconnectReason, null);
   2637     }
   2638     /**
   2639      * Log a StaEvent from WifiStateMachine. The StaEvent must not be one of the supplicant
   2640      * generated event types, which are logged through 'sendMessage'
   2641      * @param type StaEvent.EventType describing the event
   2642      * @param frameworkDisconnectReason StaEvent.FrameworkDisconnectReason explaining why framework
   2643      *                                  initiated a FRAMEWORK_DISCONNECT
   2644      * @param config WifiConfiguration for a framework initiated connection attempt
   2645      */
   2646     public void logStaEvent(int type, int frameworkDisconnectReason, WifiConfiguration config) {
   2647         switch (type) {
   2648             case StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL:
   2649             case StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST:
   2650             case StaEvent.TYPE_CMD_IP_REACHABILITY_LOST:
   2651             case StaEvent.TYPE_CMD_START_CONNECT:
   2652             case StaEvent.TYPE_CMD_START_ROAM:
   2653             case StaEvent.TYPE_CONNECT_NETWORK:
   2654             case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK:
   2655             case StaEvent.TYPE_FRAMEWORK_DISCONNECT:
   2656             case StaEvent.TYPE_SCORE_BREACH:
   2657             case StaEvent.TYPE_MAC_CHANGE:
   2658                 break;
   2659             default:
   2660                 Log.e(TAG, "Unknown StaEvent:" + type);
   2661                 return;
   2662         }
   2663         StaEvent event = new StaEvent();
   2664         event.type = type;
   2665         if (frameworkDisconnectReason != StaEvent.DISCONNECT_UNKNOWN) {
   2666             event.frameworkDisconnectReason = frameworkDisconnectReason;
   2667         }
   2668         event.configInfo = createConfigInfo(config);
   2669         addStaEvent(event);
   2670     }
   2671 
   2672     private void addStaEvent(StaEvent staEvent) {
   2673         staEvent.startTimeMillis = mClock.getElapsedSinceBootMillis();
   2674         staEvent.lastRssi = mLastPollRssi;
   2675         staEvent.lastFreq = mLastPollFreq;
   2676         staEvent.lastLinkSpeed = mLastPollLinkSpeed;
   2677         staEvent.supplicantStateChangesBitmask = mSupplicantStateChangeBitmask;
   2678         staEvent.lastScore = mLastScore;
   2679         mSupplicantStateChangeBitmask = 0;
   2680         mLastPollRssi = -127;
   2681         mLastPollFreq = -1;
   2682         mLastPollLinkSpeed = -1;
   2683         mLastScore = -1;
   2684         mStaEventList.add(new StaEventWithTime(staEvent, mClock.getWallClockMillis()));
   2685         // Prune StaEventList if it gets too long
   2686         if (mStaEventList.size() > MAX_STA_EVENTS) mStaEventList.remove();
   2687     }
   2688 
   2689     private ConfigInfo createConfigInfo(WifiConfiguration config) {
   2690         if (config == null) return null;
   2691         ConfigInfo info = new ConfigInfo();
   2692         info.allowedKeyManagement = bitSetToInt(config.allowedKeyManagement);
   2693         info.allowedProtocols = bitSetToInt(config.allowedProtocols);
   2694         info.allowedAuthAlgorithms = bitSetToInt(config.allowedAuthAlgorithms);
   2695         info.allowedPairwiseCiphers = bitSetToInt(config.allowedPairwiseCiphers);
   2696         info.allowedGroupCiphers = bitSetToInt(config.allowedGroupCiphers);
   2697         info.hiddenSsid = config.hiddenSSID;
   2698         info.isPasspoint = config.isPasspoint();
   2699         info.isEphemeral = config.isEphemeral();
   2700         info.hasEverConnected = config.getNetworkSelectionStatus().getHasEverConnected();
   2701         ScanResult candidate = config.getNetworkSelectionStatus().getCandidate();
   2702         if (candidate != null) {
   2703             info.scanRssi = candidate.level;
   2704             info.scanFreq = candidate.frequency;
   2705         }
   2706         return info;
   2707     }
   2708 
   2709     public Handler getHandler() {
   2710         return mHandler;
   2711     }
   2712 
   2713     public WifiAwareMetrics getWifiAwareMetrics() {
   2714         return mWifiAwareMetrics;
   2715     }
   2716 
   2717     public WifiWakeMetrics getWakeupMetrics() {
   2718         return mWifiWakeMetrics;
   2719     }
   2720 
   2721     public RttMetrics getRttMetrics() {
   2722         return mRttMetrics;
   2723     }
   2724 
   2725     // Rather than generate a StaEvent for each SUPPLICANT_STATE_CHANGE, cache these in a bitmask
   2726     // and attach it to the next event which is generated.
   2727     private int mSupplicantStateChangeBitmask = 0;
   2728 
   2729     /**
   2730      * Converts a SupplicantState value to a single bit, with position defined by
   2731      * {@code StaEvent.SupplicantState}
   2732      */
   2733     public static int supplicantStateToBit(SupplicantState state) {
   2734         switch(state) {
   2735             case DISCONNECTED:
   2736                 return 1 << StaEvent.STATE_DISCONNECTED;
   2737             case INTERFACE_DISABLED:
   2738                 return 1 << StaEvent.STATE_INTERFACE_DISABLED;
   2739             case INACTIVE:
   2740                 return 1 << StaEvent.STATE_INACTIVE;
   2741             case SCANNING:
   2742                 return 1 << StaEvent.STATE_SCANNING;
   2743             case AUTHENTICATING:
   2744                 return 1 << StaEvent.STATE_AUTHENTICATING;
   2745             case ASSOCIATING:
   2746                 return 1 << StaEvent.STATE_ASSOCIATING;
   2747             case ASSOCIATED:
   2748                 return 1 << StaEvent.STATE_ASSOCIATED;
   2749             case FOUR_WAY_HANDSHAKE:
   2750                 return 1 << StaEvent.STATE_FOUR_WAY_HANDSHAKE;
   2751             case GROUP_HANDSHAKE:
   2752                 return 1 << StaEvent.STATE_GROUP_HANDSHAKE;
   2753             case COMPLETED:
   2754                 return 1 << StaEvent.STATE_COMPLETED;
   2755             case DORMANT:
   2756                 return 1 << StaEvent.STATE_DORMANT;
   2757             case UNINITIALIZED:
   2758                 return 1 << StaEvent.STATE_UNINITIALIZED;
   2759             case INVALID:
   2760                 return 1 << StaEvent.STATE_INVALID;
   2761             default:
   2762                 Log.wtf(TAG, "Got unknown supplicant state: " + state.ordinal());
   2763                 return 0;
   2764         }
   2765     }
   2766 
   2767     private static String supplicantStateChangesBitmaskToString(int mask) {
   2768         StringBuilder sb = new StringBuilder();
   2769         sb.append("supplicantStateChangeEvents: {");
   2770         if ((mask & (1 << StaEvent.STATE_DISCONNECTED)) > 0) sb.append(" DISCONNECTED");
   2771         if ((mask & (1 << StaEvent.STATE_INTERFACE_DISABLED)) > 0) sb.append(" INTERFACE_DISABLED");
   2772         if ((mask & (1 << StaEvent.STATE_INACTIVE)) > 0) sb.append(" INACTIVE");
   2773         if ((mask & (1 << StaEvent.STATE_SCANNING)) > 0) sb.append(" SCANNING");
   2774         if ((mask & (1 << StaEvent.STATE_AUTHENTICATING)) > 0) sb.append(" AUTHENTICATING");
   2775         if ((mask & (1 << StaEvent.STATE_ASSOCIATING)) > 0) sb.append(" ASSOCIATING");
   2776         if ((mask & (1 << StaEvent.STATE_ASSOCIATED)) > 0) sb.append(" ASSOCIATED");
   2777         if ((mask & (1 << StaEvent.STATE_FOUR_WAY_HANDSHAKE)) > 0) sb.append(" FOUR_WAY_HANDSHAKE");
   2778         if ((mask & (1 << StaEvent.STATE_GROUP_HANDSHAKE)) > 0) sb.append(" GROUP_HANDSHAKE");
   2779         if ((mask & (1 << StaEvent.STATE_COMPLETED)) > 0) sb.append(" COMPLETED");
   2780         if ((mask & (1 << StaEvent.STATE_DORMANT)) > 0) sb.append(" DORMANT");
   2781         if ((mask & (1 << StaEvent.STATE_UNINITIALIZED)) > 0) sb.append(" UNINITIALIZED");
   2782         if ((mask & (1 << StaEvent.STATE_INVALID)) > 0) sb.append(" INVALID");
   2783         sb.append("}");
   2784         return sb.toString();
   2785     }
   2786 
   2787     /**
   2788      * Returns a human readable string from a Sta Event. Only adds information relevant to the event
   2789      * type.
   2790      */
   2791     public static String staEventToString(StaEvent event) {
   2792         if (event == null) return "<NULL>";
   2793         StringBuilder sb = new StringBuilder();
   2794         switch (event.type) {
   2795             case StaEvent.TYPE_ASSOCIATION_REJECTION_EVENT:
   2796                 sb.append("ASSOCIATION_REJECTION_EVENT")
   2797                         .append(" timedOut=").append(event.associationTimedOut)
   2798                         .append(" status=").append(event.status).append(":")
   2799                         .append(ISupplicantStaIfaceCallback.StatusCode.toString(event.status));
   2800                 break;
   2801             case StaEvent.TYPE_AUTHENTICATION_FAILURE_EVENT:
   2802                 sb.append("AUTHENTICATION_FAILURE_EVENT reason=").append(event.authFailureReason)
   2803                         .append(":").append(authFailureReasonToString(event.authFailureReason));
   2804                 break;
   2805             case StaEvent.TYPE_NETWORK_CONNECTION_EVENT:
   2806                 sb.append("NETWORK_CONNECTION_EVENT");
   2807                 break;
   2808             case StaEvent.TYPE_NETWORK_DISCONNECTION_EVENT:
   2809                 sb.append("NETWORK_DISCONNECTION_EVENT")
   2810                         .append(" local_gen=").append(event.localGen)
   2811                         .append(" reason=").append(event.reason).append(":")
   2812                         .append(ISupplicantStaIfaceCallback.ReasonCode.toString(
   2813                                 (event.reason >= 0 ? event.reason : -1 * event.reason)));
   2814                 break;
   2815             case StaEvent.TYPE_CMD_ASSOCIATED_BSSID:
   2816                 sb.append("CMD_ASSOCIATED_BSSID");
   2817                 break;
   2818             case StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL:
   2819                 sb.append("CMD_IP_CONFIGURATION_SUCCESSFUL");
   2820                 break;
   2821             case StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST:
   2822                 sb.append("CMD_IP_CONFIGURATION_LOST");
   2823                 break;
   2824             case StaEvent.TYPE_CMD_IP_REACHABILITY_LOST:
   2825                 sb.append("CMD_IP_REACHABILITY_LOST");
   2826                 break;
   2827             case StaEvent.TYPE_CMD_TARGET_BSSID:
   2828                 sb.append("CMD_TARGET_BSSID");
   2829                 break;
   2830             case StaEvent.TYPE_CMD_START_CONNECT:
   2831                 sb.append("CMD_START_CONNECT");
   2832                 break;
   2833             case StaEvent.TYPE_CMD_START_ROAM:
   2834                 sb.append("CMD_START_ROAM");
   2835                 break;
   2836             case StaEvent.TYPE_CONNECT_NETWORK:
   2837                 sb.append("CONNECT_NETWORK");
   2838                 break;
   2839             case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK:
   2840                 sb.append("NETWORK_AGENT_VALID_NETWORK");
   2841                 break;
   2842             case StaEvent.TYPE_FRAMEWORK_DISCONNECT:
   2843                 sb.append("FRAMEWORK_DISCONNECT")
   2844                         .append(" reason=")
   2845                         .append(frameworkDisconnectReasonToString(event.frameworkDisconnectReason));
   2846                 break;
   2847             case StaEvent.TYPE_SCORE_BREACH:
   2848                 sb.append("SCORE_BREACH");
   2849                 break;
   2850             case StaEvent.TYPE_MAC_CHANGE:
   2851                 sb.append("MAC_CHANGE");
   2852                 break;
   2853             default:
   2854                 sb.append("UNKNOWN " + event.type + ":");
   2855                 break;
   2856         }
   2857         if (event.lastRssi != -127) sb.append(" lastRssi=").append(event.lastRssi);
   2858         if (event.lastFreq != -1) sb.append(" lastFreq=").append(event.lastFreq);
   2859         if (event.lastLinkSpeed != -1) sb.append(" lastLinkSpeed=").append(event.lastLinkSpeed);
   2860         if (event.lastScore != -1) sb.append(" lastScore=").append(event.lastScore);
   2861         if (event.supplicantStateChangesBitmask != 0) {
   2862             sb.append(", ").append(supplicantStateChangesBitmaskToString(
   2863                     event.supplicantStateChangesBitmask));
   2864         }
   2865         if (event.configInfo != null) {
   2866             sb.append(", ").append(configInfoToString(event.configInfo));
   2867         }
   2868 
   2869         return sb.toString();
   2870     }
   2871 
   2872     private static String authFailureReasonToString(int authFailureReason) {
   2873         switch (authFailureReason) {
   2874             case StaEvent.AUTH_FAILURE_NONE:
   2875                 return "ERROR_AUTH_FAILURE_NONE";
   2876             case StaEvent.AUTH_FAILURE_TIMEOUT:
   2877                 return "ERROR_AUTH_FAILURE_TIMEOUT";
   2878             case StaEvent.AUTH_FAILURE_WRONG_PSWD:
   2879                 return "ERROR_AUTH_FAILURE_WRONG_PSWD";
   2880             case StaEvent.AUTH_FAILURE_EAP_FAILURE:
   2881                 return "ERROR_AUTH_FAILURE_EAP_FAILURE";
   2882             default:
   2883                 return "";
   2884         }
   2885     }
   2886 
   2887     private static String frameworkDisconnectReasonToString(int frameworkDisconnectReason) {
   2888         switch (frameworkDisconnectReason) {
   2889             case StaEvent.DISCONNECT_API:
   2890                 return "DISCONNECT_API";
   2891             case StaEvent.DISCONNECT_GENERIC:
   2892                 return "DISCONNECT_GENERIC";
   2893             case StaEvent.DISCONNECT_UNWANTED:
   2894                 return "DISCONNECT_UNWANTED";
   2895             case StaEvent.DISCONNECT_ROAM_WATCHDOG_TIMER:
   2896                 return "DISCONNECT_ROAM_WATCHDOG_TIMER";
   2897             case StaEvent.DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST:
   2898                 return "DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST";
   2899             case StaEvent.DISCONNECT_RESET_SIM_NETWORKS:
   2900                 return "DISCONNECT_RESET_SIM_NETWORKS";
   2901             default:
   2902                 return "DISCONNECT_UNKNOWN=" + frameworkDisconnectReason;
   2903         }
   2904     }
   2905 
   2906     private static String configInfoToString(ConfigInfo info) {
   2907         StringBuilder sb = new StringBuilder();
   2908         sb.append("ConfigInfo:")
   2909                 .append(" allowed_key_management=").append(info.allowedKeyManagement)
   2910                 .append(" allowed_protocols=").append(info.allowedProtocols)
   2911                 .append(" allowed_auth_algorithms=").append(info.allowedAuthAlgorithms)
   2912                 .append(" allowed_pairwise_ciphers=").append(info.allowedPairwiseCiphers)
   2913                 .append(" allowed_group_ciphers=").append(info.allowedGroupCiphers)
   2914                 .append(" hidden_ssid=").append(info.hiddenSsid)
   2915                 .append(" is_passpoint=").append(info.isPasspoint)
   2916                 .append(" is_ephemeral=").append(info.isEphemeral)
   2917                 .append(" has_ever_connected=").append(info.hasEverConnected)
   2918                 .append(" scan_rssi=").append(info.scanRssi)
   2919                 .append(" scan_freq=").append(info.scanFreq);
   2920         return sb.toString();
   2921     }
   2922 
   2923     public static final int MAX_STA_EVENTS = 768;
   2924     private LinkedList<StaEventWithTime> mStaEventList = new LinkedList<StaEventWithTime>();
   2925     private int mLastPollRssi = -127;
   2926     private int mLastPollLinkSpeed = -1;
   2927     private int mLastPollFreq = -1;
   2928     private int mLastScore = -1;
   2929 
   2930     /**
   2931      * Converts the first 31 bits of a BitSet to a little endian int
   2932      */
   2933     private static int bitSetToInt(BitSet bits) {
   2934         int value = 0;
   2935         int nBits = bits.length() < 31 ? bits.length() : 31;
   2936         for (int i = 0; i < nBits; i++) {
   2937             value += bits.get(i) ? (1 << i) : 0;
   2938         }
   2939         return value;
   2940     }
   2941     private void incrementSsid(SparseIntArray sia, int element) {
   2942         increment(sia, Math.min(element, MAX_CONNECTABLE_SSID_NETWORK_BUCKET));
   2943     }
   2944     private void incrementBssid(SparseIntArray sia, int element) {
   2945         increment(sia, Math.min(element, MAX_CONNECTABLE_BSSID_NETWORK_BUCKET));
   2946     }
   2947     private void incrementTotalScanResults(SparseIntArray sia, int element) {
   2948         increment(sia, Math.min(element, MAX_TOTAL_SCAN_RESULTS_BUCKET));
   2949     }
   2950     private void incrementTotalScanSsids(SparseIntArray sia, int element) {
   2951         increment(sia, Math.min(element, MAX_TOTAL_SCAN_RESULT_SSIDS_BUCKET));
   2952     }
   2953     private void incrementTotalPasspointAps(SparseIntArray sia, int element) {
   2954         increment(sia, Math.min(element, MAX_TOTAL_PASSPOINT_APS_BUCKET));
   2955     }
   2956     private void incrementTotalUniquePasspointEss(SparseIntArray sia, int element) {
   2957         increment(sia, Math.min(element, MAX_TOTAL_PASSPOINT_UNIQUE_ESS_BUCKET));
   2958     }
   2959     private void incrementPasspointPerUniqueEss(SparseIntArray sia, int element) {
   2960         increment(sia, Math.min(element, MAX_PASSPOINT_APS_PER_UNIQUE_ESS_BUCKET));
   2961     }
   2962     private void increment80211mcAps(SparseIntArray sia, int element) {
   2963         increment(sia, Math.min(element, MAX_TOTAL_80211MC_APS_BUCKET));
   2964     }
   2965     private void increment(SparseIntArray sia, int element) {
   2966         int count = sia.get(element);
   2967         sia.put(element, count + 1);
   2968     }
   2969 
   2970     private static class StaEventWithTime {
   2971         public StaEvent staEvent;
   2972         public long wallClockMillis;
   2973 
   2974         StaEventWithTime(StaEvent event, long wallClockMillis) {
   2975             staEvent = event;
   2976             this.wallClockMillis = wallClockMillis;
   2977         }
   2978 
   2979         public String toString() {
   2980             StringBuilder sb = new StringBuilder();
   2981             Calendar c = Calendar.getInstance();
   2982             c.setTimeInMillis(wallClockMillis);
   2983             if (wallClockMillis != 0) {
   2984                 sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
   2985             } else {
   2986                 sb.append("                  ");
   2987             }
   2988             sb.append(" ").append(staEventToString(staEvent));
   2989             return sb.toString();
   2990         }
   2991     }
   2992 }
   2993