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.net.NetworkAgent;
     20 import android.net.wifi.ScanResult;
     21 import android.net.wifi.WifiConfiguration;
     22 import android.util.Base64;
     23 import android.util.Log;
     24 import android.util.SparseIntArray;
     25 
     26 import com.android.server.wifi.hotspot2.NetworkDetail;
     27 import com.android.server.wifi.util.InformationElementUtil;
     28 
     29 import java.io.FileDescriptor;
     30 import java.io.PrintWriter;
     31 import java.util.ArrayList;
     32 import java.util.Calendar;
     33 import java.util.List;
     34 
     35 /**
     36  * Provides storage for wireless connectivity metrics, as they are generated.
     37  * Metrics logged by this class include:
     38  *   Aggregated connection stats (num of connections, num of failures, ...)
     39  *   Discrete connection event stats (time, duration, failure codes, ...)
     40  *   Router details (technology type, authentication type, ...)
     41  *   Scan stats
     42  */
     43 public class WifiMetrics {
     44     private static final String TAG = "WifiMetrics";
     45     private static final boolean DBG = false;
     46     /**
     47      * Clamp the RSSI poll counts to values between [MIN,MAX]_RSSI_POLL
     48      */
     49     private static final int MAX_RSSI_POLL = 0;
     50     private static final int MIN_RSSI_POLL = -127;
     51     private static final int MIN_WIFI_SCORE = 0;
     52     private static final int MAX_WIFI_SCORE = NetworkAgent.WIFI_BASE_SCORE;
     53     private final Object mLock = new Object();
     54     private static final int MAX_CONNECTION_EVENTS = 256;
     55     private Clock mClock;
     56     private boolean mScreenOn;
     57     private int mWifiState;
     58     /**
     59      * Metrics are stored within an instance of the WifiLog proto during runtime,
     60      * The ConnectionEvent, SystemStateEntries & ScanReturnEntries metrics are stored during
     61      * runtime in member lists of this WifiMetrics class, with the final WifiLog proto being pieced
     62      * together at dump-time
     63      */
     64     private final WifiMetricsProto.WifiLog mWifiLogProto = new WifiMetricsProto.WifiLog();
     65     /**
     66      * Session information that gets logged for every Wifi connection attempt.
     67      */
     68     private final List<ConnectionEvent> mConnectionEventList = new ArrayList<>();
     69     /**
     70      * The latest started (but un-ended) connection attempt
     71      */
     72     private ConnectionEvent mCurrentConnectionEvent;
     73     /**
     74      * Count of number of times each scan return code, indexed by WifiLog.ScanReturnCode
     75      */
     76     private final SparseIntArray mScanReturnEntries = new SparseIntArray();
     77     /**
     78      * Mapping of system state to the counts of scans requested in that wifi state * screenOn
     79      * combination. Indexed by WifiLog.WifiState * (1 + screenOn)
     80      */
     81     private final SparseIntArray mWifiSystemStateEntries = new SparseIntArray();
     82     /** Mapping of RSSI values to counts. */
     83     private final SparseIntArray mRssiPollCounts = new SparseIntArray();
     84     /** Mapping of alert reason to the respective alert count. */
     85     private final SparseIntArray mWifiAlertReasonCounts = new SparseIntArray();
     86     /**
     87      * Records the elapsedRealtime (in seconds) that represents the beginning of data
     88      * capture for for this WifiMetricsProto
     89      */
     90     private long mRecordStartTimeSec;
     91     /** Mapping of Wifi Scores to counts */
     92     private final SparseIntArray mWifiScoreCounts = new SparseIntArray();
     93     class RouterFingerPrint {
     94         private WifiMetricsProto.RouterFingerPrint mRouterFingerPrintProto;
     95         RouterFingerPrint() {
     96             mRouterFingerPrintProto = new WifiMetricsProto.RouterFingerPrint();
     97         }
     98 
     99         public String toString() {
    100             StringBuilder sb = new StringBuilder();
    101             synchronized (mLock) {
    102                 sb.append("mConnectionEvent.roamType=" + mRouterFingerPrintProto.roamType);
    103                 sb.append(", mChannelInfo=" + mRouterFingerPrintProto.channelInfo);
    104                 sb.append(", mDtim=" + mRouterFingerPrintProto.dtim);
    105                 sb.append(", mAuthentication=" + mRouterFingerPrintProto.authentication);
    106                 sb.append(", mHidden=" + mRouterFingerPrintProto.hidden);
    107                 sb.append(", mRouterTechnology=" + mRouterFingerPrintProto.routerTechnology);
    108                 sb.append(", mSupportsIpv6=" + mRouterFingerPrintProto.supportsIpv6);
    109             }
    110             return sb.toString();
    111         }
    112         public void updateFromWifiConfiguration(WifiConfiguration config) {
    113             synchronized (mLock) {
    114                 if (config != null) {
    115                     // Is this a hidden network
    116                     mRouterFingerPrintProto.hidden = config.hiddenSSID;
    117                     // Config may not have a valid dtimInterval set yet, in which case dtim will be zero
    118                     // (These are only populated from beacon frame scan results, which are returned as
    119                     // scan results from the chip far less frequently than Probe-responses)
    120                     if (config.dtimInterval > 0) {
    121                         mRouterFingerPrintProto.dtim = config.dtimInterval;
    122                     }
    123                     mCurrentConnectionEvent.mConfigSsid = config.SSID;
    124                     // Get AuthType information from config (We do this again from ScanResult after
    125                     // associating with BSSID)
    126                     if (config.allowedKeyManagement != null
    127                             && config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) {
    128                         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
    129                                 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_OPEN;
    130                     } else if (config.isEnterprise()) {
    131                         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
    132                                 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE;
    133                     } else {
    134                         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
    135                                 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL;
    136                     }
    137                     mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
    138                             .passpoint = config.isPasspoint();
    139                     // If there's a ScanResult candidate associated with this config already, get it and
    140                     // log (more accurate) metrics from it
    141                     ScanResult candidate = config.getNetworkSelectionStatus().getCandidate();
    142                     if (candidate != null) {
    143                         updateMetricsFromScanResult(candidate);
    144                     }
    145                 }
    146             }
    147         }
    148     }
    149 
    150     /**
    151      * Log event, tracking the start time, end time and result of a wireless connection attempt.
    152      */
    153     class ConnectionEvent {
    154         WifiMetricsProto.ConnectionEvent mConnectionEvent;
    155         //<TODO> Move these constants into a wifi.proto Enum, and create a new Failure Type field
    156         //covering more than just l2 failures. see b/27652362
    157         /**
    158          * Failure codes, used for the 'level_2_failure_code' Connection event field (covers a lot
    159          * more failures than just l2 though, since the proto does not have a place to log
    160          * framework failures)
    161          */
    162         // Failure is unknown
    163         public static final int FAILURE_UNKNOWN = 0;
    164         // NONE
    165         public static final int FAILURE_NONE = 1;
    166         // ASSOCIATION_REJECTION_EVENT
    167         public static final int FAILURE_ASSOCIATION_REJECTION = 2;
    168         // AUTHENTICATION_FAILURE_EVENT
    169         public static final int FAILURE_AUTHENTICATION_FAILURE = 3;
    170         // SSID_TEMP_DISABLED (Also Auth failure)
    171         public static final int FAILURE_SSID_TEMP_DISABLED = 4;
    172         // reconnect() or reassociate() call to WifiNative failed
    173         public static final int FAILURE_CONNECT_NETWORK_FAILED = 5;
    174         // NETWORK_DISCONNECTION_EVENT
    175         public static final int FAILURE_NETWORK_DISCONNECTION = 6;
    176         // NEW_CONNECTION_ATTEMPT before previous finished
    177         public static final int FAILURE_NEW_CONNECTION_ATTEMPT = 7;
    178         // New connection attempt to the same network & bssid
    179         public static final int FAILURE_REDUNDANT_CONNECTION_ATTEMPT = 8;
    180         // Roam Watchdog timer triggered (Roaming timed out)
    181         public static final int FAILURE_ROAM_TIMEOUT = 9;
    182         // DHCP failure
    183         public static final int FAILURE_DHCP = 10;
    184 
    185         RouterFingerPrint mRouterFingerPrint;
    186         private long mRealStartTime;
    187         private long mRealEndTime;
    188         private String mConfigSsid;
    189         private String mConfigBssid;
    190         private int mWifiState;
    191         private boolean mScreenOn;
    192 
    193         private ConnectionEvent() {
    194             mConnectionEvent = new WifiMetricsProto.ConnectionEvent();
    195             mRealEndTime = 0;
    196             mRealStartTime = 0;
    197             mRouterFingerPrint = new RouterFingerPrint();
    198             mConnectionEvent.routerFingerprint = mRouterFingerPrint.mRouterFingerPrintProto;
    199             mConfigSsid = "<NULL>";
    200             mConfigBssid = "<NULL>";
    201             mWifiState = WifiMetricsProto.WifiLog.WIFI_UNKNOWN;
    202             mScreenOn = false;
    203         }
    204 
    205         public String toString() {
    206             StringBuilder sb = new StringBuilder();
    207             sb.append("startTime=");
    208             Calendar c = Calendar.getInstance();
    209             synchronized (mLock) {
    210                 c.setTimeInMillis(mConnectionEvent.startTimeMillis);
    211                 sb.append(mConnectionEvent.startTimeMillis == 0 ? "            <null>" :
    212                         String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
    213                 sb.append(", SSID=");
    214                 sb.append(mConfigSsid);
    215                 sb.append(", BSSID=");
    216                 sb.append(mConfigBssid);
    217                 sb.append(", durationMillis=");
    218                 sb.append(mConnectionEvent.durationTakenToConnectMillis);
    219                 sb.append(", roamType=");
    220                 switch(mConnectionEvent.roamType) {
    221                     case 1:
    222                         sb.append("ROAM_NONE");
    223                         break;
    224                     case 2:
    225                         sb.append("ROAM_DBDC");
    226                         break;
    227                     case 3:
    228                         sb.append("ROAM_ENTERPRISE");
    229                         break;
    230                     case 4:
    231                         sb.append("ROAM_USER_SELECTED");
    232                         break;
    233                     case 5:
    234                         sb.append("ROAM_UNRELATED");
    235                         break;
    236                     default:
    237                         sb.append("ROAM_UNKNOWN");
    238                 }
    239                 sb.append(", connectionResult=");
    240                 sb.append(mConnectionEvent.connectionResult);
    241                 sb.append(", level2FailureCode=");
    242                 switch(mConnectionEvent.level2FailureCode) {
    243                     case FAILURE_NONE:
    244                         sb.append("NONE");
    245                         break;
    246                     case FAILURE_ASSOCIATION_REJECTION:
    247                         sb.append("ASSOCIATION_REJECTION");
    248                         break;
    249                     case FAILURE_AUTHENTICATION_FAILURE:
    250                         sb.append("AUTHENTICATION_FAILURE");
    251                         break;
    252                     case FAILURE_SSID_TEMP_DISABLED:
    253                         sb.append("SSID_TEMP_DISABLED");
    254                         break;
    255                     case FAILURE_CONNECT_NETWORK_FAILED:
    256                         sb.append("CONNECT_NETWORK_FAILED");
    257                         break;
    258                     case FAILURE_NETWORK_DISCONNECTION:
    259                         sb.append("NETWORK_DISCONNECTION");
    260                         break;
    261                     case FAILURE_NEW_CONNECTION_ATTEMPT:
    262                         sb.append("NEW_CONNECTION_ATTEMPT");
    263                         break;
    264                     case FAILURE_REDUNDANT_CONNECTION_ATTEMPT:
    265                         sb.append("REDUNDANT_CONNECTION_ATTEMPT");
    266                         break;
    267                     case FAILURE_ROAM_TIMEOUT:
    268                         sb.append("ROAM_TIMEOUT");
    269                         break;
    270                     case FAILURE_DHCP:
    271                         sb.append("DHCP");
    272                     default:
    273                         sb.append("UNKNOWN");
    274                         break;
    275                 }
    276                 sb.append(", connectivityLevelFailureCode=");
    277                 switch(mConnectionEvent.connectivityLevelFailureCode) {
    278                     case WifiMetricsProto.ConnectionEvent.HLF_NONE:
    279                         sb.append("NONE");
    280                         break;
    281                     case WifiMetricsProto.ConnectionEvent.HLF_DHCP:
    282                         sb.append("DHCP");
    283                         break;
    284                     case WifiMetricsProto.ConnectionEvent.HLF_NO_INTERNET:
    285                         sb.append("NO_INTERNET");
    286                         break;
    287                     case WifiMetricsProto.ConnectionEvent.HLF_UNWANTED:
    288                         sb.append("UNWANTED");
    289                         break;
    290                     default:
    291                         sb.append("UNKNOWN");
    292                         break;
    293                 }
    294                 sb.append(", signalStrength=");
    295                 sb.append(mConnectionEvent.signalStrength);
    296                 sb.append(", wifiState=");
    297                 switch(mWifiState) {
    298                     case WifiMetricsProto.WifiLog.WIFI_DISABLED:
    299                         sb.append("WIFI_DISABLED");
    300                         break;
    301                     case WifiMetricsProto.WifiLog.WIFI_DISCONNECTED:
    302                         sb.append("WIFI_DISCONNECTED");
    303                         break;
    304                     case WifiMetricsProto.WifiLog.WIFI_ASSOCIATED:
    305                         sb.append("WIFI_ASSOCIATED");
    306                         break;
    307                     default:
    308                         sb.append("WIFI_UNKNOWN");
    309                         break;
    310                 }
    311                 sb.append(", screenOn=");
    312                 sb.append(mScreenOn);
    313                 sb.append(". mRouterFingerprint: ");
    314                 sb.append(mRouterFingerPrint.toString());
    315             }
    316             return sb.toString();
    317         }
    318     }
    319 
    320     public WifiMetrics(Clock clock) {
    321         mClock = clock;
    322         mCurrentConnectionEvent = null;
    323         mScreenOn = true;
    324         mWifiState = WifiMetricsProto.WifiLog.WIFI_DISABLED;
    325         mRecordStartTimeSec = mClock.elapsedRealtime() / 1000;
    326     }
    327 
    328     // Values used for indexing SystemStateEntries
    329     private static final int SCREEN_ON = 1;
    330     private static final int SCREEN_OFF = 0;
    331 
    332     /**
    333      * Create a new connection event. Call when wifi attempts to make a new network connection
    334      * If there is a current 'un-ended' connection event, it will be ended with UNKNOWN connectivity
    335      * failure code.
    336      * Gathers and sets the RouterFingerPrint data as well
    337      *
    338      * @param config WifiConfiguration of the config used for the current connection attempt
    339      * @param roamType Roam type that caused connection attempt, see WifiMetricsProto.WifiLog.ROAM_X
    340      */
    341     public void startConnectionEvent(WifiConfiguration config, String targetBSSID, int roamType) {
    342         synchronized (mLock) {
    343             // Check if this is overlapping another current connection event
    344             if (mCurrentConnectionEvent != null) {
    345                 //Is this new Connection Event the same as the current one
    346                 if (mCurrentConnectionEvent.mConfigSsid != null
    347                         && mCurrentConnectionEvent.mConfigBssid != null
    348                         && config != null
    349                         && mCurrentConnectionEvent.mConfigSsid.equals(config.SSID)
    350                         && (mCurrentConnectionEvent.mConfigBssid.equals("any")
    351                         || mCurrentConnectionEvent.mConfigBssid.equals(targetBSSID))) {
    352                     mCurrentConnectionEvent.mConfigBssid = targetBSSID;
    353                     // End Connection Event due to new connection attempt to the same network
    354                     endConnectionEvent(ConnectionEvent.FAILURE_REDUNDANT_CONNECTION_ATTEMPT,
    355                             WifiMetricsProto.ConnectionEvent.HLF_NONE);
    356                 } else {
    357                     // End Connection Event due to new connection attempt to different network
    358                     endConnectionEvent(ConnectionEvent.FAILURE_NEW_CONNECTION_ATTEMPT,
    359                             WifiMetricsProto.ConnectionEvent.HLF_NONE);
    360                 }
    361             }
    362             //If past maximum connection events, start removing the oldest
    363             while(mConnectionEventList.size() >= MAX_CONNECTION_EVENTS) {
    364                 mConnectionEventList.remove(0);
    365             }
    366             mCurrentConnectionEvent = new ConnectionEvent();
    367             mCurrentConnectionEvent.mConnectionEvent.startTimeMillis =
    368                     mClock.currentTimeMillis();
    369             mCurrentConnectionEvent.mConfigBssid = targetBSSID;
    370             mCurrentConnectionEvent.mConnectionEvent.roamType = roamType;
    371             mCurrentConnectionEvent.mRouterFingerPrint.updateFromWifiConfiguration(config);
    372             mCurrentConnectionEvent.mConfigBssid = "any";
    373             mCurrentConnectionEvent.mRealStartTime = mClock.elapsedRealtime();
    374             mCurrentConnectionEvent.mWifiState = mWifiState;
    375             mCurrentConnectionEvent.mScreenOn = mScreenOn;
    376             mConnectionEventList.add(mCurrentConnectionEvent);
    377         }
    378     }
    379 
    380     /**
    381      * set the RoamType of the current ConnectionEvent (if any)
    382      */
    383     public void setConnectionEventRoamType(int roamType) {
    384         synchronized (mLock) {
    385             if (mCurrentConnectionEvent != null) {
    386                 mCurrentConnectionEvent.mConnectionEvent.roamType = roamType;
    387             }
    388         }
    389     }
    390 
    391     /**
    392      * Set AP related metrics from ScanDetail
    393      */
    394     public void setConnectionScanDetail(ScanDetail scanDetail) {
    395         synchronized (mLock) {
    396             if (mCurrentConnectionEvent != null && scanDetail != null) {
    397                 NetworkDetail networkDetail = scanDetail.getNetworkDetail();
    398                 ScanResult scanResult = scanDetail.getScanResult();
    399                 //Ensure that we have a networkDetail, and that it corresponds to the currently
    400                 //tracked connection attempt
    401                 if (networkDetail != null && scanResult != null
    402                         && mCurrentConnectionEvent.mConfigSsid != null
    403                         && mCurrentConnectionEvent.mConfigSsid
    404                         .equals("\"" + networkDetail.getSSID() + "\"")) {
    405                     updateMetricsFromNetworkDetail(networkDetail);
    406                     updateMetricsFromScanResult(scanResult);
    407                 }
    408             }
    409         }
    410     }
    411 
    412     /**
    413      * End a Connection event record. Call when wifi connection attempt succeeds or fails.
    414      * If a Connection event has not been started and is active when .end is called, a new one is
    415      * created with zero duration.
    416      *
    417      * @param level2FailureCode Level 2 failure code returned by supplicant
    418      * @param connectivityFailureCode WifiMetricsProto.ConnectionEvent.HLF_X
    419      */
    420     public void endConnectionEvent(int level2FailureCode, int connectivityFailureCode) {
    421         synchronized (mLock) {
    422             if (mCurrentConnectionEvent != null) {
    423                 boolean result = (level2FailureCode == 1)
    424                         && (connectivityFailureCode == WifiMetricsProto.ConnectionEvent.HLF_NONE);
    425                 mCurrentConnectionEvent.mConnectionEvent.connectionResult = result ? 1 : 0;
    426                 mCurrentConnectionEvent.mRealEndTime = mClock.elapsedRealtime();
    427                 mCurrentConnectionEvent.mConnectionEvent.durationTakenToConnectMillis = (int)
    428                         (mCurrentConnectionEvent.mRealEndTime
    429                         - mCurrentConnectionEvent.mRealStartTime);
    430                 mCurrentConnectionEvent.mConnectionEvent.level2FailureCode = level2FailureCode;
    431                 mCurrentConnectionEvent.mConnectionEvent.connectivityLevelFailureCode =
    432                         connectivityFailureCode;
    433                 // ConnectionEvent already added to ConnectionEvents List. Safe to null current here
    434                 mCurrentConnectionEvent = null;
    435             }
    436         }
    437     }
    438 
    439     /**
    440      * Set ConnectionEvent DTIM Interval (if set), and 802.11 Connection mode, from NetworkDetail
    441      */
    442     private void updateMetricsFromNetworkDetail(NetworkDetail networkDetail) {
    443         int dtimInterval = networkDetail.getDtimInterval();
    444         if (dtimInterval > 0) {
    445             mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.dtim =
    446                     dtimInterval;
    447         }
    448         int connectionWifiMode;
    449         switch (networkDetail.getWifiMode()) {
    450             case InformationElementUtil.WifiMode.MODE_UNDEFINED:
    451                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_UNKNOWN;
    452                 break;
    453             case InformationElementUtil.WifiMode.MODE_11A:
    454                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_A;
    455                 break;
    456             case InformationElementUtil.WifiMode.MODE_11B:
    457                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_B;
    458                 break;
    459             case InformationElementUtil.WifiMode.MODE_11G:
    460                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_G;
    461                 break;
    462             case InformationElementUtil.WifiMode.MODE_11N:
    463                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_N;
    464                 break;
    465             case InformationElementUtil.WifiMode.MODE_11AC  :
    466                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_AC;
    467                 break;
    468             default:
    469                 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_OTHER;
    470                 break;
    471         }
    472         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto
    473                 .routerTechnology = connectionWifiMode;
    474     }
    475 
    476     /**
    477      * Set ConnectionEvent RSSI and authentication type from ScanResult
    478      */
    479     private void updateMetricsFromScanResult(ScanResult scanResult) {
    480         mCurrentConnectionEvent.mConnectionEvent.signalStrength = scanResult.level;
    481         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
    482                 WifiMetricsProto.RouterFingerPrint.AUTH_OPEN;
    483         mCurrentConnectionEvent.mConfigBssid = scanResult.BSSID;
    484         if (scanResult.capabilities != null) {
    485             if (scanResult.capabilities.contains("WEP")) {
    486                 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
    487                         WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL;
    488             } else if (scanResult.capabilities.contains("PSK")) {
    489                 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
    490                         WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL;
    491             } else if (scanResult.capabilities.contains("EAP")) {
    492                 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication =
    493                         WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE;
    494             }
    495         }
    496         mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.channelInfo =
    497                 scanResult.frequency;
    498     }
    499 
    500     void setNumSavedNetworks(int num) {
    501         synchronized (mLock) {
    502             mWifiLogProto.numSavedNetworks = num;
    503         }
    504     }
    505 
    506     void setNumOpenNetworks(int num) {
    507         synchronized (mLock) {
    508             mWifiLogProto.numOpenNetworks = num;
    509         }
    510     }
    511 
    512     void setNumPersonalNetworks(int num) {
    513         synchronized (mLock) {
    514             mWifiLogProto.numPersonalNetworks = num;
    515         }
    516     }
    517 
    518     void setNumEnterpriseNetworks(int num) {
    519         synchronized (mLock) {
    520             mWifiLogProto.numEnterpriseNetworks = num;
    521         }
    522     }
    523 
    524     void setNumHiddenNetworks(int num) {
    525         synchronized (mLock) {
    526             mWifiLogProto.numHiddenNetworks = num;
    527         }
    528     }
    529 
    530     void setNumPasspointNetworks(int num) {
    531         synchronized (mLock) {
    532             mWifiLogProto.numPasspointNetworks = num;
    533         }
    534     }
    535 
    536     void setNumNetworksAddedByUser(int num) {
    537         synchronized (mLock) {
    538             mWifiLogProto.numNetworksAddedByUser = num;
    539         }
    540     }
    541 
    542     void setNumNetworksAddedByApps(int num) {
    543         synchronized (mLock) {
    544             mWifiLogProto.numNetworksAddedByApps = num;
    545         }
    546     }
    547 
    548     void setIsLocationEnabled(boolean enabled) {
    549         synchronized (mLock) {
    550             mWifiLogProto.isLocationEnabled = enabled;
    551         }
    552     }
    553 
    554     void setIsScanningAlwaysEnabled(boolean enabled) {
    555         synchronized (mLock) {
    556             mWifiLogProto.isScanningAlwaysEnabled = enabled;
    557         }
    558     }
    559 
    560     /**
    561      * Increment Non Empty Scan Results count
    562      */
    563     public void incrementNonEmptyScanResultCount() {
    564         if (DBG) Log.v(TAG, "incrementNonEmptyScanResultCount");
    565         synchronized (mLock) {
    566             mWifiLogProto.numNonEmptyScanResults++;
    567         }
    568     }
    569 
    570     /**
    571      * Increment Empty Scan Results count
    572      */
    573     public void incrementEmptyScanResultCount() {
    574         if (DBG) Log.v(TAG, "incrementEmptyScanResultCount");
    575         synchronized (mLock) {
    576             mWifiLogProto.numEmptyScanResults++;
    577         }
    578     }
    579 
    580     /**
    581      * Increment background scan count
    582      */
    583     public void incrementBackgroundScanCount() {
    584         if (DBG) Log.v(TAG, "incrementBackgroundScanCount");
    585         synchronized (mLock) {
    586             mWifiLogProto.numBackgroundScans++;
    587         }
    588     }
    589 
    590    /**
    591      * Get Background scan count
    592      */
    593     public int getBackgroundScanCount() {
    594         synchronized (mLock) {
    595             return mWifiLogProto.numBackgroundScans;
    596         }
    597     }
    598 
    599     /**
    600      * Increment oneshot scan count, and the associated WifiSystemScanStateCount entry
    601      */
    602     public void incrementOneshotScanCount() {
    603         synchronized (mLock) {
    604             mWifiLogProto.numOneshotScans++;
    605         }
    606         incrementWifiSystemScanStateCount(mWifiState, mScreenOn);
    607     }
    608 
    609     /**
    610      * Get oneshot scan count
    611      */
    612     public int getOneshotScanCount() {
    613         synchronized (mLock) {
    614             return mWifiLogProto.numOneshotScans;
    615         }
    616     }
    617 
    618     private String returnCodeToString(int scanReturnCode) {
    619         switch(scanReturnCode){
    620             case WifiMetricsProto.WifiLog.SCAN_UNKNOWN:
    621                 return "SCAN_UNKNOWN";
    622             case WifiMetricsProto.WifiLog.SCAN_SUCCESS:
    623                 return "SCAN_SUCCESS";
    624             case WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED:
    625                 return "SCAN_FAILURE_INTERRUPTED";
    626             case WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION:
    627                 return "SCAN_FAILURE_INVALID_CONFIGURATION";
    628             case WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED:
    629                 return "FAILURE_WIFI_DISABLED";
    630             default:
    631                 return "<UNKNOWN>";
    632         }
    633     }
    634 
    635     /**
    636      * Increment count of scan return code occurrence
    637      *
    638      * @param scanReturnCode Return code from scan attempt WifiMetricsProto.WifiLog.SCAN_X
    639      */
    640     public void incrementScanReturnEntry(int scanReturnCode, int countToAdd) {
    641         synchronized (mLock) {
    642             if (DBG) Log.v(TAG, "incrementScanReturnEntry " + returnCodeToString(scanReturnCode));
    643             int entry = mScanReturnEntries.get(scanReturnCode);
    644             entry += countToAdd;
    645             mScanReturnEntries.put(scanReturnCode, entry);
    646         }
    647     }
    648     /**
    649      * Get the count of this scanReturnCode
    650      * @param scanReturnCode that we are getting the count for
    651      */
    652     public int getScanReturnEntry(int scanReturnCode) {
    653         synchronized (mLock) {
    654             return mScanReturnEntries.get(scanReturnCode);
    655         }
    656     }
    657 
    658     private String wifiSystemStateToString(int state) {
    659         switch(state){
    660             case WifiMetricsProto.WifiLog.WIFI_UNKNOWN:
    661                 return "WIFI_UNKNOWN";
    662             case WifiMetricsProto.WifiLog.WIFI_DISABLED:
    663                 return "WIFI_DISABLED";
    664             case WifiMetricsProto.WifiLog.WIFI_DISCONNECTED:
    665                 return "WIFI_DISCONNECTED";
    666             case WifiMetricsProto.WifiLog.WIFI_ASSOCIATED:
    667                 return "WIFI_ASSOCIATED";
    668             default:
    669                 return "default";
    670         }
    671     }
    672 
    673     /**
    674      * Increments the count of scans initiated by each wifi state, accounts for screenOn/Off
    675      *
    676      * @param state State of the system when scan was initiated, see WifiMetricsProto.WifiLog.WIFI_X
    677      * @param screenOn Is the screen on
    678      */
    679     public void incrementWifiSystemScanStateCount(int state, boolean screenOn) {
    680         synchronized (mLock) {
    681             if (DBG) {
    682                 Log.v(TAG, "incrementWifiSystemScanStateCount " + wifiSystemStateToString(state)
    683                         + " " + screenOn);
    684             }
    685             int index = (state * 2) + (screenOn ? SCREEN_ON : SCREEN_OFF);
    686             int entry = mWifiSystemStateEntries.get(index);
    687             entry++;
    688             mWifiSystemStateEntries.put(index, entry);
    689         }
    690     }
    691 
    692     /**
    693      * Get the count of this system State Entry
    694      */
    695     public int getSystemStateCount(int state, boolean screenOn) {
    696         synchronized (mLock) {
    697             int index = state * 2 + (screenOn ? SCREEN_ON : SCREEN_OFF);
    698             return mWifiSystemStateEntries.get(index);
    699         }
    700     }
    701 
    702     /**
    703      * Increment number of times the Watchdog of Last Resort triggered, resetting the wifi stack
    704      */
    705     public void incrementNumLastResortWatchdogTriggers() {
    706         synchronized (mLock) {
    707             mWifiLogProto.numLastResortWatchdogTriggers++;
    708         }
    709     }
    710     /**
    711      * @param count number of networks over bad association threshold when watchdog triggered
    712      */
    713     public void addCountToNumLastResortWatchdogBadAssociationNetworksTotal(int count) {
    714         synchronized (mLock) {
    715             mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal += count;
    716         }
    717     }
    718     /**
    719      * @param count number of networks over bad authentication threshold when watchdog triggered
    720      */
    721     public void addCountToNumLastResortWatchdogBadAuthenticationNetworksTotal(int count) {
    722         synchronized (mLock) {
    723             mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal += count;
    724         }
    725     }
    726     /**
    727      * @param count number of networks over bad dhcp threshold when watchdog triggered
    728      */
    729     public void addCountToNumLastResortWatchdogBadDhcpNetworksTotal(int count) {
    730         synchronized (mLock) {
    731             mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal += count;
    732         }
    733     }
    734     /**
    735      * @param count number of networks over bad other threshold when watchdog triggered
    736      */
    737     public void addCountToNumLastResortWatchdogBadOtherNetworksTotal(int count) {
    738         synchronized (mLock) {
    739             mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal += count;
    740         }
    741     }
    742     /**
    743      * @param count number of networks seen when watchdog triggered
    744      */
    745     public void addCountToNumLastResortWatchdogAvailableNetworksTotal(int count) {
    746         synchronized (mLock) {
    747             mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal += count;
    748         }
    749     }
    750     /**
    751      * Increment count of triggers with atleast one bad association network
    752      */
    753     public void incrementNumLastResortWatchdogTriggersWithBadAssociation() {
    754         synchronized (mLock) {
    755             mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation++;
    756         }
    757     }
    758     /**
    759      * Increment count of triggers with atleast one bad authentication network
    760      */
    761     public void incrementNumLastResortWatchdogTriggersWithBadAuthentication() {
    762         synchronized (mLock) {
    763             mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication++;
    764         }
    765     }
    766     /**
    767      * Increment count of triggers with atleast one bad dhcp network
    768      */
    769     public void incrementNumLastResortWatchdogTriggersWithBadDhcp() {
    770         synchronized (mLock) {
    771             mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp++;
    772         }
    773     }
    774     /**
    775      * Increment count of triggers with atleast one bad other network
    776      */
    777     public void incrementNumLastResortWatchdogTriggersWithBadOther() {
    778         synchronized (mLock) {
    779             mWifiLogProto.numLastResortWatchdogTriggersWithBadOther++;
    780         }
    781     }
    782 
    783     /**
    784      * Increment number of times connectivity watchdog confirmed pno is working
    785      */
    786     public void incrementNumConnectivityWatchdogPnoGood() {
    787         synchronized (mLock) {
    788             mWifiLogProto.numConnectivityWatchdogPnoGood++;
    789         }
    790     }
    791     /**
    792      * Increment number of times connectivity watchdog found pno not working
    793      */
    794     public void incrementNumConnectivityWatchdogPnoBad() {
    795         synchronized (mLock) {
    796             mWifiLogProto.numConnectivityWatchdogPnoBad++;
    797         }
    798     }
    799     /**
    800      * Increment number of times connectivity watchdog confirmed background scan is working
    801      */
    802     public void incrementNumConnectivityWatchdogBackgroundGood() {
    803         synchronized (mLock) {
    804             mWifiLogProto.numConnectivityWatchdogBackgroundGood++;
    805         }
    806     }
    807     /**
    808      * Increment number of times connectivity watchdog found background scan not working
    809      */
    810     public void incrementNumConnectivityWatchdogBackgroundBad() {
    811         synchronized (mLock) {
    812             mWifiLogProto.numConnectivityWatchdogBackgroundBad++;
    813         }
    814     }
    815 
    816     /**
    817      * Increment occurence count of RSSI level from RSSI poll.
    818      * Ignores rssi values outside the bounds of [MIN_RSSI_POLL, MAX_RSSI_POLL]
    819      */
    820     public void incrementRssiPollRssiCount(int rssi) {
    821         if (!(rssi >= MIN_RSSI_POLL && rssi <= MAX_RSSI_POLL)) {
    822             return;
    823         }
    824         synchronized (mLock) {
    825             int count = mRssiPollCounts.get(rssi);
    826             mRssiPollCounts.put(rssi, count + 1);
    827         }
    828     }
    829 
    830     /**
    831      * Increment count of Watchdog successes.
    832      */
    833     public void incrementNumLastResortWatchdogSuccesses() {
    834         synchronized (mLock) {
    835             mWifiLogProto.numLastResortWatchdogSuccesses++;
    836         }
    837     }
    838 
    839     /**
    840      * Increments the count of alerts by alert reason.
    841      *
    842      * @param reason The cause of the alert. The reason values are driver-specific.
    843      */
    844     public void incrementAlertReasonCount(int reason) {
    845         if (reason > WifiLoggerHal.WIFI_ALERT_REASON_MAX
    846                 || reason < WifiLoggerHal.WIFI_ALERT_REASON_MIN) {
    847             reason = WifiLoggerHal.WIFI_ALERT_REASON_RESERVED;
    848         }
    849         synchronized (mLock) {
    850             int alertCount = mWifiAlertReasonCounts.get(reason);
    851             mWifiAlertReasonCounts.put(reason, alertCount + 1);
    852         }
    853     }
    854 
    855     /**
    856      * Counts all the different types of networks seen in a set of scan results
    857      */
    858     public void countScanResults(List<ScanDetail> scanDetails) {
    859         if (scanDetails == null) {
    860             return;
    861         }
    862         int totalResults = 0;
    863         int openNetworks = 0;
    864         int personalNetworks = 0;
    865         int enterpriseNetworks = 0;
    866         int hiddenNetworks = 0;
    867         int hotspot2r1Networks = 0;
    868         int hotspot2r2Networks = 0;
    869         for (ScanDetail scanDetail : scanDetails) {
    870             NetworkDetail networkDetail = scanDetail.getNetworkDetail();
    871             ScanResult scanResult = scanDetail.getScanResult();
    872             totalResults++;
    873             if (networkDetail != null) {
    874                 if (networkDetail.isHiddenBeaconFrame()) {
    875                     hiddenNetworks++;
    876                 }
    877                 if (networkDetail.getHSRelease() != null) {
    878                     if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) {
    879                         hotspot2r1Networks++;
    880                     } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) {
    881                         hotspot2r2Networks++;
    882                     }
    883                 }
    884             }
    885             if (scanResult != null && scanResult.capabilities != null) {
    886                 if (scanResult.capabilities.contains("EAP")) {
    887                     enterpriseNetworks++;
    888                 } else if (scanResult.capabilities.contains("PSK")
    889                         || scanResult.capabilities.contains("WEP")) {
    890                     personalNetworks++;
    891                 } else {
    892                     openNetworks++;
    893                 }
    894             }
    895         }
    896         synchronized (mLock) {
    897             mWifiLogProto.numTotalScanResults += totalResults;
    898             mWifiLogProto.numOpenNetworkScanResults += openNetworks;
    899             mWifiLogProto.numPersonalNetworkScanResults += personalNetworks;
    900             mWifiLogProto.numEnterpriseNetworkScanResults += enterpriseNetworks;
    901             mWifiLogProto.numHiddenNetworkScanResults += hiddenNetworks;
    902             mWifiLogProto.numHotspot2R1NetworkScanResults += hotspot2r1Networks;
    903             mWifiLogProto.numHotspot2R2NetworkScanResults += hotspot2r2Networks;
    904             mWifiLogProto.numScans++;
    905         }
    906     }
    907 
    908     /**
    909      * Increments occurence of a particular wifi score calculated
    910      * in WifiScoreReport by current connected network. Scores are bounded
    911      * within  [MIN_WIFI_SCORE, MAX_WIFI_SCORE] to limit size of SparseArray
    912      */
    913     public void incrementWifiScoreCount(int score) {
    914         if (score < MIN_WIFI_SCORE || score > MAX_WIFI_SCORE) {
    915             return;
    916         }
    917         synchronized (mLock) {
    918             int count = mWifiScoreCounts.get(score);
    919             mWifiScoreCounts.put(score, count + 1);
    920         }
    921     }
    922 
    923     public static final String PROTO_DUMP_ARG = "wifiMetricsProto";
    924     public static final String CLEAN_DUMP_ARG = "clean";
    925 
    926     /**
    927      * Dump all WifiMetrics. Collects some metrics from ConfigStore, Settings and WifiManager
    928      * at this time.
    929      *
    930      * @param fd unused
    931      * @param pw PrintWriter for writing dump to
    932      * @param args unused
    933      */
    934     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    935         synchronized (mLock) {
    936             if (args.length > 0 && PROTO_DUMP_ARG.equals(args[0])) {
    937                 // Dump serialized WifiLog proto
    938                 consolidateProto(true);
    939                 for (ConnectionEvent event : mConnectionEventList) {
    940                     if (mCurrentConnectionEvent != event) {
    941                         //indicate that automatic bug report has been taken for all valid
    942                         //connection events
    943                         event.mConnectionEvent.automaticBugReportTaken = true;
    944                     }
    945                 }
    946                 byte[] wifiMetricsProto = WifiMetricsProto.WifiLog.toByteArray(mWifiLogProto);
    947                 String metricsProtoDump = Base64.encodeToString(wifiMetricsProto, Base64.DEFAULT);
    948                 if (args.length > 1 && CLEAN_DUMP_ARG.equals(args[1])) {
    949                     // Output metrics proto bytes (base64) and nothing else
    950                     pw.print(metricsProtoDump);
    951                 } else {
    952                     // Tag the start and end of the metrics proto bytes
    953                     pw.println("WifiMetrics:");
    954                     pw.println(metricsProtoDump);
    955                     pw.println("EndWifiMetrics");
    956                 }
    957                 clear();
    958             } else {
    959                 pw.println("WifiMetrics:");
    960                 pw.println("mConnectionEvents:");
    961                 for (ConnectionEvent event : mConnectionEventList) {
    962                     String eventLine = event.toString();
    963                     if (event == mCurrentConnectionEvent) {
    964                         eventLine += "CURRENTLY OPEN EVENT";
    965                     }
    966                     pw.println(eventLine);
    967                 }
    968                 pw.println("mWifiLogProto.numSavedNetworks=" + mWifiLogProto.numSavedNetworks);
    969                 pw.println("mWifiLogProto.numOpenNetworks=" + mWifiLogProto.numOpenNetworks);
    970                 pw.println("mWifiLogProto.numPersonalNetworks="
    971                         + mWifiLogProto.numPersonalNetworks);
    972                 pw.println("mWifiLogProto.numEnterpriseNetworks="
    973                         + mWifiLogProto.numEnterpriseNetworks);
    974                 pw.println("mWifiLogProto.numHiddenNetworks=" + mWifiLogProto.numHiddenNetworks);
    975                 pw.println("mWifiLogProto.numPasspointNetworks="
    976                         + mWifiLogProto.numPasspointNetworks);
    977                 pw.println("mWifiLogProto.isLocationEnabled=" + mWifiLogProto.isLocationEnabled);
    978                 pw.println("mWifiLogProto.isScanningAlwaysEnabled="
    979                         + mWifiLogProto.isScanningAlwaysEnabled);
    980                 pw.println("mWifiLogProto.numNetworksAddedByUser="
    981                         + mWifiLogProto.numNetworksAddedByUser);
    982                 pw.println("mWifiLogProto.numNetworksAddedByApps="
    983                         + mWifiLogProto.numNetworksAddedByApps);
    984                 pw.println("mWifiLogProto.numNonEmptyScanResults="
    985                         + mWifiLogProto.numNonEmptyScanResults);
    986                 pw.println("mWifiLogProto.numEmptyScanResults="
    987                         + mWifiLogProto.numEmptyScanResults);
    988                 pw.println("mWifiLogProto.numOneshotScans="
    989                         + mWifiLogProto.numOneshotScans);
    990                 pw.println("mWifiLogProto.numBackgroundScans="
    991                         + mWifiLogProto.numBackgroundScans);
    992 
    993                 pw.println("mScanReturnEntries:");
    994                 pw.println("  SCAN_UNKNOWN: " + getScanReturnEntry(
    995                         WifiMetricsProto.WifiLog.SCAN_UNKNOWN));
    996                 pw.println("  SCAN_SUCCESS: " + getScanReturnEntry(
    997                         WifiMetricsProto.WifiLog.SCAN_SUCCESS));
    998                 pw.println("  SCAN_FAILURE_INTERRUPTED: " + getScanReturnEntry(
    999                         WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED));
   1000                 pw.println("  SCAN_FAILURE_INVALID_CONFIGURATION: " + getScanReturnEntry(
   1001                         WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION));
   1002                 pw.println("  FAILURE_WIFI_DISABLED: " + getScanReturnEntry(
   1003                         WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED));
   1004 
   1005                 pw.println("mSystemStateEntries: <state><screenOn> : <scansInitiated>");
   1006                 pw.println("  WIFI_UNKNOWN       ON: "
   1007                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, true));
   1008                 pw.println("  WIFI_DISABLED      ON: "
   1009                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, true));
   1010                 pw.println("  WIFI_DISCONNECTED  ON: "
   1011                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, true));
   1012                 pw.println("  WIFI_ASSOCIATED    ON: "
   1013                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, true));
   1014                 pw.println("  WIFI_UNKNOWN      OFF: "
   1015                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, false));
   1016                 pw.println("  WIFI_DISABLED     OFF: "
   1017                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, false));
   1018                 pw.println("  WIFI_DISCONNECTED OFF: "
   1019                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, false));
   1020                 pw.println("  WIFI_ASSOCIATED   OFF: "
   1021                         + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, false));
   1022                 pw.println("mWifiLogProto.numConnectivityWatchdogPnoGood="
   1023                         + mWifiLogProto.numConnectivityWatchdogPnoGood);
   1024                 pw.println("mWifiLogProto.numConnectivityWatchdogPnoBad="
   1025                         + mWifiLogProto.numConnectivityWatchdogPnoBad);
   1026                 pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundGood="
   1027                         + mWifiLogProto.numConnectivityWatchdogBackgroundGood);
   1028                 pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundBad="
   1029                         + mWifiLogProto.numConnectivityWatchdogBackgroundBad);
   1030                 pw.println("mWifiLogProto.numLastResortWatchdogTriggers="
   1031                         + mWifiLogProto.numLastResortWatchdogTriggers);
   1032                 pw.println("mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal="
   1033                         + mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal);
   1034                 pw.println("mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal="
   1035                         + mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal);
   1036                 pw.println("mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal="
   1037                         + mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal);
   1038                 pw.println("mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal="
   1039                         + mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal);
   1040                 pw.println("mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal="
   1041                         + mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal);
   1042                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation="
   1043                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation);
   1044                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication="
   1045                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication);
   1046                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp="
   1047                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp);
   1048                 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadOther="
   1049                         + mWifiLogProto.numLastResortWatchdogTriggersWithBadOther);
   1050                 pw.println("mWifiLogProto.numLastResortWatchdogSuccesses="
   1051                         + mWifiLogProto.numLastResortWatchdogSuccesses);
   1052                 pw.println("mWifiLogProto.recordDurationSec="
   1053                         + ((mClock.elapsedRealtime() / 1000) - mRecordStartTimeSec));
   1054                 pw.println("mWifiLogProto.rssiPollRssiCount: Printing counts for [" + MIN_RSSI_POLL
   1055                         + ", " + MAX_RSSI_POLL + "]");
   1056                 StringBuilder sb = new StringBuilder();
   1057                 for (int i = MIN_RSSI_POLL; i <= MAX_RSSI_POLL; i++) {
   1058                     sb.append(mRssiPollCounts.get(i) + " ");
   1059                 }
   1060                 pw.println("  " + sb.toString());
   1061                 pw.print("mWifiLogProto.alertReasonCounts=");
   1062                 sb.setLength(0);
   1063                 for (int i = WifiLoggerHal.WIFI_ALERT_REASON_MIN;
   1064                         i <= WifiLoggerHal.WIFI_ALERT_REASON_MAX; i++) {
   1065                     int count = mWifiAlertReasonCounts.get(i);
   1066                     if (count > 0) {
   1067                         sb.append("(" + i + "," + count + "),");
   1068                     }
   1069                 }
   1070                 if (sb.length() > 1) {
   1071                     sb.setLength(sb.length() - 1);  // strip trailing comma
   1072                     pw.println(sb.toString());
   1073                 } else {
   1074                     pw.println("()");
   1075                 }
   1076                 pw.println("mWifiLogProto.numTotalScanResults="
   1077                         + mWifiLogProto.numTotalScanResults);
   1078                 pw.println("mWifiLogProto.numOpenNetworkScanResults="
   1079                         + mWifiLogProto.numOpenNetworkScanResults);
   1080                 pw.println("mWifiLogProto.numPersonalNetworkScanResults="
   1081                         + mWifiLogProto.numPersonalNetworkScanResults);
   1082                 pw.println("mWifiLogProto.numEnterpriseNetworkScanResults="
   1083                         + mWifiLogProto.numEnterpriseNetworkScanResults);
   1084                 pw.println("mWifiLogProto.numHiddenNetworkScanResults="
   1085                         + mWifiLogProto.numHiddenNetworkScanResults);
   1086                 pw.println("mWifiLogProto.numHotspot2R1NetworkScanResults="
   1087                         + mWifiLogProto.numHotspot2R1NetworkScanResults);
   1088                 pw.println("mWifiLogProto.numHotspot2R2NetworkScanResults="
   1089                         + mWifiLogProto.numHotspot2R2NetworkScanResults);
   1090                 pw.println("mWifiLogProto.numScans=" + mWifiLogProto.numScans);
   1091                 pw.println("mWifiLogProto.WifiScoreCount: [" + MIN_WIFI_SCORE + ", "
   1092                         + MAX_WIFI_SCORE + "]");
   1093                 for (int i = 0; i <= MAX_WIFI_SCORE; i++) {
   1094                     pw.print(mWifiScoreCounts.get(i) + " ");
   1095                 }
   1096                 pw.print("\n");
   1097             }
   1098         }
   1099     }
   1100 
   1101     /**
   1102      * append the separate ConnectionEvent, SystemStateEntry and ScanReturnCode collections to their
   1103      * respective lists within mWifiLogProto
   1104      *
   1105      * @param incremental Only include ConnectionEvents created since last automatic bug report
   1106      */
   1107     private void consolidateProto(boolean incremental) {
   1108         List<WifiMetricsProto.ConnectionEvent> events = new ArrayList<>();
   1109         List<WifiMetricsProto.RssiPollCount> rssis = new ArrayList<>();
   1110         List<WifiMetricsProto.AlertReasonCount> alertReasons = new ArrayList<>();
   1111         List<WifiMetricsProto.WifiScoreCount> scores = new ArrayList<>();
   1112         synchronized (mLock) {
   1113             for (ConnectionEvent event : mConnectionEventList) {
   1114                 // If this is not incremental, dump full ConnectionEvent list
   1115                 // Else Dump all un-dumped events except for the current one
   1116                 if (!incremental || ((mCurrentConnectionEvent != event)
   1117                         && !event.mConnectionEvent.automaticBugReportTaken)) {
   1118                     //Get all ConnectionEvents that haven not been dumped as a proto, also exclude
   1119                     //the current active un-ended connection event
   1120                     events.add(event.mConnectionEvent);
   1121                     if (incremental) {
   1122                         event.mConnectionEvent.automaticBugReportTaken = true;
   1123                     }
   1124                 }
   1125             }
   1126             if (events.size() > 0) {
   1127                 mWifiLogProto.connectionEvent = events.toArray(mWifiLogProto.connectionEvent);
   1128             }
   1129 
   1130             //Convert the SparseIntArray of scanReturnEntry integers into ScanReturnEntry proto list
   1131             mWifiLogProto.scanReturnEntries =
   1132                     new WifiMetricsProto.WifiLog.ScanReturnEntry[mScanReturnEntries.size()];
   1133             for (int i = 0; i < mScanReturnEntries.size(); i++) {
   1134                 mWifiLogProto.scanReturnEntries[i] = new WifiMetricsProto.WifiLog.ScanReturnEntry();
   1135                 mWifiLogProto.scanReturnEntries[i].scanReturnCode = mScanReturnEntries.keyAt(i);
   1136                 mWifiLogProto.scanReturnEntries[i].scanResultsCount = mScanReturnEntries.valueAt(i);
   1137             }
   1138 
   1139             // Convert the SparseIntArray of systemStateEntry into WifiSystemStateEntry proto list
   1140             // This one is slightly more complex, as the Sparse are indexed with:
   1141             //     key: wifiState * 2 + isScreenOn, value: wifiStateCount
   1142             mWifiLogProto.wifiSystemStateEntries =
   1143                     new WifiMetricsProto.WifiLog
   1144                     .WifiSystemStateEntry[mWifiSystemStateEntries.size()];
   1145             for (int i = 0; i < mWifiSystemStateEntries.size(); i++) {
   1146                 mWifiLogProto.wifiSystemStateEntries[i] =
   1147                         new WifiMetricsProto.WifiLog.WifiSystemStateEntry();
   1148                 mWifiLogProto.wifiSystemStateEntries[i].wifiState =
   1149                         mWifiSystemStateEntries.keyAt(i) / 2;
   1150                 mWifiLogProto.wifiSystemStateEntries[i].wifiStateCount =
   1151                         mWifiSystemStateEntries.valueAt(i);
   1152                 mWifiLogProto.wifiSystemStateEntries[i].isScreenOn =
   1153                         (mWifiSystemStateEntries.keyAt(i) % 2) > 0;
   1154             }
   1155             mWifiLogProto.recordDurationSec = (int) ((mClock.elapsedRealtime() / 1000)
   1156                     - mRecordStartTimeSec);
   1157 
   1158             /**
   1159              * Convert the SparseIntArray of RSSI poll rssi's and counts to the proto's repeated
   1160              * IntKeyVal array.
   1161              */
   1162             for (int i = 0; i < mRssiPollCounts.size(); i++) {
   1163                 WifiMetricsProto.RssiPollCount keyVal = new WifiMetricsProto.RssiPollCount();
   1164                 keyVal.rssi = mRssiPollCounts.keyAt(i);
   1165                 keyVal.count = mRssiPollCounts.valueAt(i);
   1166                 rssis.add(keyVal);
   1167             }
   1168             mWifiLogProto.rssiPollRssiCount = rssis.toArray(mWifiLogProto.rssiPollRssiCount);
   1169 
   1170             /**
   1171              * Convert the SparseIntArray of alert reasons and counts to the proto's repeated
   1172              * IntKeyVal array.
   1173              */
   1174             for (int i = 0; i < mWifiAlertReasonCounts.size(); i++) {
   1175                 WifiMetricsProto.AlertReasonCount keyVal = new WifiMetricsProto.AlertReasonCount();
   1176                 keyVal.reason = mWifiAlertReasonCounts.keyAt(i);
   1177                 keyVal.count = mWifiAlertReasonCounts.valueAt(i);
   1178                 alertReasons.add(keyVal);
   1179             }
   1180             mWifiLogProto.alertReasonCount = alertReasons.toArray(mWifiLogProto.alertReasonCount);
   1181             /**
   1182             *  Convert the SparseIntArray of Wifi Score and counts to proto's repeated
   1183             * IntKeyVal array.
   1184             */
   1185             for (int score = 0; score < mWifiScoreCounts.size(); score++) {
   1186                 WifiMetricsProto.WifiScoreCount keyVal = new WifiMetricsProto.WifiScoreCount();
   1187                 keyVal.score = mWifiScoreCounts.keyAt(score);
   1188                 keyVal.count = mWifiScoreCounts.valueAt(score);
   1189                 scores.add(keyVal);
   1190             }
   1191             mWifiLogProto.wifiScoreCount = scores.toArray(mWifiLogProto.wifiScoreCount);
   1192         }
   1193     }
   1194 
   1195     /**
   1196      * Clear all WifiMetrics, except for currentConnectionEvent.
   1197      */
   1198     private void clear() {
   1199         synchronized (mLock) {
   1200             mConnectionEventList.clear();
   1201             if (mCurrentConnectionEvent != null) {
   1202                 mConnectionEventList.add(mCurrentConnectionEvent);
   1203             }
   1204             mScanReturnEntries.clear();
   1205             mWifiSystemStateEntries.clear();
   1206             mRecordStartTimeSec = mClock.elapsedRealtime() / 1000;
   1207             mRssiPollCounts.clear();
   1208             mWifiAlertReasonCounts.clear();
   1209             mWifiScoreCounts.clear();
   1210             mWifiLogProto.clear();
   1211         }
   1212     }
   1213 
   1214     /**
   1215      *  Set screen state (On/Off)
   1216      */
   1217     public void setScreenState(boolean screenOn) {
   1218         synchronized (mLock) {
   1219             mScreenOn = screenOn;
   1220         }
   1221     }
   1222 
   1223     /**
   1224      *  Set wifi state (WIFI_UNKNOWN, WIFI_DISABLED, WIFI_DISCONNECTED, WIFI_ASSOCIATED)
   1225      */
   1226     public void setWifiState(int wifiState) {
   1227         synchronized (mLock) {
   1228             mWifiState = wifiState;
   1229         }
   1230     }
   1231 }
   1232