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