WifiMetrics.java revision a284841edf33e4070748816a034c47f996bfeb81
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     * Increments the count of alerts by alert reason.
814     *
815     * @param reason The cause of the alert. The reason values are driver-specific.
816     */
817    public void incrementAlertReasonCount(int reason) {
818        if (reason > WifiLoggerHal.WIFI_ALERT_REASON_MAX
819                || reason < WifiLoggerHal.WIFI_ALERT_REASON_MIN) {
820            reason = WifiLoggerHal.WIFI_ALERT_REASON_RESERVED;
821        }
822        synchronized (mLock) {
823            int alertCount = mWifiAlertReasonCounts.get(reason);
824            mWifiAlertReasonCounts.put(reason, alertCount + 1);
825        }
826    }
827
828    public static final String PROTO_DUMP_ARG = "wifiMetricsProto";
829    /**
830     * Dump all WifiMetrics. Collects some metrics from ConfigStore, Settings and WifiManager
831     * at this time
832     *
833     * @param fd unused
834     * @param pw PrintWriter for writing dump to
835     * @param args unused
836     */
837    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
838        synchronized (mLock) {
839            pw.println("WifiMetrics:");
840            if (args.length > 0 && PROTO_DUMP_ARG.equals(args[0])) {
841                //Dump serialized WifiLog proto
842                consolidateProto(true);
843                for (ConnectionEvent event : mConnectionEventList) {
844                    if (mCurrentConnectionEvent != event) {
845                        //indicate that automatic bug report has been taken for all valid
846                        //connection events
847                        event.mConnectionEvent.automaticBugReportTaken = true;
848                    }
849                }
850                byte[] wifiMetricsProto = WifiMetricsProto.WifiLog.toByteArray(mWifiLogProto);
851                String metricsProtoDump = Base64.encodeToString(wifiMetricsProto, Base64.DEFAULT);
852                pw.println(metricsProtoDump);
853                pw.println("EndWifiMetrics");
854                clear();
855            } else {
856                pw.println("mConnectionEvents:");
857                for (ConnectionEvent event : mConnectionEventList) {
858                    String eventLine = event.toString();
859                    if (event == mCurrentConnectionEvent) {
860                        eventLine += "CURRENTLY OPEN EVENT";
861                    }
862                    pw.println(eventLine);
863                }
864                pw.println("mWifiLogProto.numSavedNetworks=" + mWifiLogProto.numSavedNetworks);
865                pw.println("mWifiLogProto.numOpenNetworks=" + mWifiLogProto.numOpenNetworks);
866                pw.println("mWifiLogProto.numPersonalNetworks="
867                        + mWifiLogProto.numPersonalNetworks);
868                pw.println("mWifiLogProto.numEnterpriseNetworks="
869                        + mWifiLogProto.numEnterpriseNetworks);
870                pw.println("mWifiLogProto.isLocationEnabled=" + mWifiLogProto.isLocationEnabled);
871                pw.println("mWifiLogProto.isScanningAlwaysEnabled="
872                        + mWifiLogProto.isScanningAlwaysEnabled);
873                pw.println("mWifiLogProto.numNetworksAddedByUser="
874                        + mWifiLogProto.numNetworksAddedByUser);
875                pw.println("mWifiLogProto.numNetworksAddedByApps="
876                        + mWifiLogProto.numNetworksAddedByApps);
877                pw.println("mWifiLogProto.numNonEmptyScanResults="
878                        + mWifiLogProto.numNonEmptyScanResults);
879                pw.println("mWifiLogProto.numEmptyScanResults="
880                        + mWifiLogProto.numEmptyScanResults);
881                pw.println("mWifiLogProto.numOneshotScans="
882                        + mWifiLogProto.numOneshotScans);
883                pw.println("mWifiLogProto.numBackgroundScans="
884                        + mWifiLogProto.numBackgroundScans);
885
886                pw.println("mScanReturnEntries:");
887                pw.println("  SCAN_UNKNOWN: " + getScanReturnEntry(
888                        WifiMetricsProto.WifiLog.SCAN_UNKNOWN));
889                pw.println("  SCAN_SUCCESS: " + getScanReturnEntry(
890                        WifiMetricsProto.WifiLog.SCAN_SUCCESS));
891                pw.println("  SCAN_FAILURE_INTERRUPTED: " + getScanReturnEntry(
892                        WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED));
893                pw.println("  SCAN_FAILURE_INVALID_CONFIGURATION: " + getScanReturnEntry(
894                        WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION));
895                pw.println("  FAILURE_WIFI_DISABLED: " + getScanReturnEntry(
896                        WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED));
897
898                pw.println("mSystemStateEntries: <state><screenOn> : <scansInitiated>");
899                pw.println("  WIFI_UNKNOWN       ON: "
900                        + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, true));
901                pw.println("  WIFI_DISABLED      ON: "
902                        + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, true));
903                pw.println("  WIFI_DISCONNECTED  ON: "
904                        + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, true));
905                pw.println("  WIFI_ASSOCIATED    ON: "
906                        + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, true));
907                pw.println("  WIFI_UNKNOWN      OFF: "
908                        + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, false));
909                pw.println("  WIFI_DISABLED     OFF: "
910                        + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, false));
911                pw.println("  WIFI_DISCONNECTED OFF: "
912                        + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, false));
913                pw.println("  WIFI_ASSOCIATED   OFF: "
914                        + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, false));
915                pw.println("mWifiLogProto.numConnectivityWatchdogPnoGood="
916                        + mWifiLogProto.numConnectivityWatchdogPnoGood);
917                pw.println("mWifiLogProto.numConnectivityWatchdogPnoBad="
918                        + mWifiLogProto.numConnectivityWatchdogPnoBad);
919                pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundGood="
920                        + mWifiLogProto.numConnectivityWatchdogBackgroundGood);
921                pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundBad="
922                        + mWifiLogProto.numConnectivityWatchdogBackgroundBad);
923                pw.println("mWifiLogProto.numLastResortWatchdogTriggers="
924                        + mWifiLogProto.numLastResortWatchdogTriggers);
925                pw.println("mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal="
926                        + mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal);
927                pw.println("mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal="
928                        + mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal);
929                pw.println("mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal="
930                        + mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal);
931                pw.println("mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal="
932                        + mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal);
933                pw.println("mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal="
934                        + mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal);
935                pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation="
936                        + mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation);
937                pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication="
938                        + mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication);
939                pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp="
940                        + mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp);
941                pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadOther="
942                        + mWifiLogProto.numLastResortWatchdogTriggersWithBadOther);
943                pw.println("mWifiLogProto.recordDurationSec="
944                        + ((mClock.elapsedRealtime() / 1000) - mRecordStartTimeSec));
945                pw.println("mWifiLogProto.rssiPollRssiCount: Printing counts for [" + MIN_RSSI_POLL
946                        + ", " + MAX_RSSI_POLL + "]");
947                StringBuilder sb = new StringBuilder();
948                for (int i = MIN_RSSI_POLL; i <= MAX_RSSI_POLL; i++) {
949                    sb.append(mRssiPollCounts.get(i) + " ");
950                }
951                pw.println("  " + sb.toString());
952                pw.print("mWifiLogProto.alertReasonCounts=");
953                sb.setLength(0);
954                for (int i = WifiLoggerHal.WIFI_ALERT_REASON_MIN;
955                        i <= WifiLoggerHal.WIFI_ALERT_REASON_MAX; i++) {
956                    int count = mWifiAlertReasonCounts.get(i);
957                    if (count > 0) {
958                        sb.append("(" + i + "," + count + "),");
959                    }
960                }
961                if (sb.length() > 1) {
962                    sb.setLength(sb.length() - 1);  // strip trailing comma
963                    pw.println(sb.toString());
964                } else {
965                    pw.println("()");
966                }
967            }
968        }
969    }
970
971    /**
972     * append the separate ConnectionEvent, SystemStateEntry and ScanReturnCode collections to their
973     * respective lists within mWifiLogProto
974     *
975     * @param incremental Only include ConnectionEvents created since last automatic bug report
976     */
977    private void consolidateProto(boolean incremental) {
978        List<WifiMetricsProto.ConnectionEvent> events = new ArrayList<>();
979        List<WifiMetricsProto.RssiPollCount> rssis = new ArrayList<>();
980        List<WifiMetricsProto.AlertReasonCount> alertReasons = new ArrayList<>();
981        synchronized (mLock) {
982            for (ConnectionEvent event : mConnectionEventList) {
983                // If this is not incremental, dump full ConnectionEvent list
984                // Else Dump all un-dumped events except for the current one
985                if (!incremental || ((mCurrentConnectionEvent != event)
986                        && !event.mConnectionEvent.automaticBugReportTaken)) {
987                    //Get all ConnectionEvents that haven not been dumped as a proto, also exclude
988                    //the current active un-ended connection event
989                    events.add(event.mConnectionEvent);
990                    if (incremental) {
991                        event.mConnectionEvent.automaticBugReportTaken = true;
992                    }
993                }
994            }
995            if (events.size() > 0) {
996                mWifiLogProto.connectionEvent = events.toArray(mWifiLogProto.connectionEvent);
997            }
998
999            //Convert the SparseIntArray of scanReturnEntry integers into ScanReturnEntry proto list
1000            mWifiLogProto.scanReturnEntries =
1001                    new WifiMetricsProto.WifiLog.ScanReturnEntry[mScanReturnEntries.size()];
1002            for (int i = 0; i < mScanReturnEntries.size(); i++) {
1003                mWifiLogProto.scanReturnEntries[i] = new WifiMetricsProto.WifiLog.ScanReturnEntry();
1004                mWifiLogProto.scanReturnEntries[i].scanReturnCode = mScanReturnEntries.keyAt(i);
1005                mWifiLogProto.scanReturnEntries[i].scanResultsCount = mScanReturnEntries.valueAt(i);
1006            }
1007
1008            // Convert the SparseIntArray of systemStateEntry into WifiSystemStateEntry proto list
1009            // This one is slightly more complex, as the Sparse are indexed with:
1010            //     key: wifiState * 2 + isScreenOn, value: wifiStateCount
1011            mWifiLogProto.wifiSystemStateEntries =
1012                    new WifiMetricsProto.WifiLog
1013                    .WifiSystemStateEntry[mWifiSystemStateEntries.size()];
1014            for (int i = 0; i < mWifiSystemStateEntries.size(); i++) {
1015                mWifiLogProto.wifiSystemStateEntries[i] =
1016                        new WifiMetricsProto.WifiLog.WifiSystemStateEntry();
1017                mWifiLogProto.wifiSystemStateEntries[i].wifiState =
1018                        mWifiSystemStateEntries.keyAt(i) / 2;
1019                mWifiLogProto.wifiSystemStateEntries[i].wifiStateCount =
1020                        mWifiSystemStateEntries.valueAt(i);
1021                mWifiLogProto.wifiSystemStateEntries[i].isScreenOn =
1022                        (mWifiSystemStateEntries.keyAt(i) % 2) > 0;
1023            }
1024            mWifiLogProto.recordDurationSec = (int) ((mClock.elapsedRealtime() / 1000)
1025                    - mRecordStartTimeSec);
1026
1027            /**
1028             * Convert the SparseIntArray of RSSI poll rssi's and counts to the proto's repeated
1029             * IntKeyVal array.
1030             */
1031            for (int i = 0; i < mRssiPollCounts.size(); i++) {
1032                WifiMetricsProto.RssiPollCount keyVal = new WifiMetricsProto.RssiPollCount();
1033                keyVal.rssi = mRssiPollCounts.keyAt(i);
1034                keyVal.count = mRssiPollCounts.valueAt(i);
1035                rssis.add(keyVal);
1036            }
1037            mWifiLogProto.rssiPollRssiCount = rssis.toArray(mWifiLogProto.rssiPollRssiCount);
1038
1039            /**
1040             * Convert the SparseIntArray of alert reasons and counts to the proto's repeated
1041             * IntKeyVal array.
1042             */
1043            for (int i = 0; i < mWifiAlertReasonCounts.size(); i++) {
1044                WifiMetricsProto.AlertReasonCount keyVal = new WifiMetricsProto.AlertReasonCount();
1045                keyVal.reason = mWifiAlertReasonCounts.keyAt(i);
1046                keyVal.count = mWifiAlertReasonCounts.valueAt(i);
1047                alertReasons.add(keyVal);
1048            }
1049            mWifiLogProto.alertReasonCount = alertReasons.toArray(mWifiLogProto.alertReasonCount);
1050        }
1051    }
1052
1053    /**
1054     * Clear all WifiMetrics, except for currentConnectionEvent.
1055     */
1056    private void clear() {
1057        synchronized (mLock) {
1058            mConnectionEventList.clear();
1059            if (mCurrentConnectionEvent != null) {
1060                mConnectionEventList.add(mCurrentConnectionEvent);
1061            }
1062            mScanReturnEntries.clear();
1063            mWifiSystemStateEntries.clear();
1064            mRecordStartTimeSec = mClock.elapsedRealtime() / 1000;
1065            mRssiPollCounts.clear();
1066            mWifiAlertReasonCounts.clear();
1067            mWifiLogProto.clear();
1068        }
1069    }
1070
1071    /**
1072     *  Set screen state (On/Off)
1073     */
1074    public void setScreenState(boolean screenOn) {
1075        synchronized (mLock) {
1076            mScreenOn = screenOn;
1077        }
1078    }
1079
1080    /**
1081     *  Set wifi state (WIFI_UNKNOWN, WIFI_DISABLED, WIFI_DISCONNECTED, WIFI_ASSOCIATED)
1082     */
1083    public void setWifiState(int wifiState) {
1084        synchronized (mLock) {
1085            mWifiState = wifiState;
1086        }
1087    }
1088}
1089