WifiLastResortWatchdog.java revision 09abbe29be6e552a2531b0367bd6d29647d33767
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.Log;
22import android.util.Pair;
23
24import java.util.HashMap;
25import java.util.Iterator;
26import java.util.List;
27import java.util.Map;
28
29/**
30 * <TBD> Intended Purpose/Behavior of the class upon completion:
31 * Essentially this class automates a user toggling 'Airplane Mode' when WiFi "won't work".
32 * IF each available saved network has failed connecting more times than the FAILURE_THRESHOLD
33 * THEN Watchdog will restart Supplicant, wifi driver and return WifiStateMachine to InitialState.
34 * </TBD>
35 */
36public class WifiLastResortWatchdog {
37    private static final String TAG = "WifiLastResortWatchdog";
38    private static final boolean VDBG = false;
39    /**
40     * Cached WifiConfigurations of available networks seen within MAX_BSSID_AGE scan results
41     * Key:BSSID, Value:Counters of failure types
42     */
43    private Map<String, AvailableNetworkFailureCount> mRecentAvailableNetworks = new HashMap<>();
44
45    // Maximum number of scan results received since we last saw a BSSID.
46    // If it is not seen before this limit is reached, the network is culled
47    public static final int MAX_BSSID_AGE = 10;
48
49    /**
50     * Refreshes recentAvailableNetworks with the latest available networks
51     * Adds new networks, removes old ones that have timed out. Should be called after Wifi
52     * framework decides what networks it is potentially connecting to.
53     * @param availableNetworkFailureCounts ScanDetail & Config list of potential connection
54     * candidates
55     */
56    public void updateAvailableNetworks(
57            List<Pair<ScanDetail, WifiConfiguration>> availableNetworkFailureCounts) {
58        // Add new networks to mRecentAvailableNetworks
59        if (availableNetworkFailureCounts != null) {
60            for (Pair<ScanDetail, WifiConfiguration> pair : availableNetworkFailureCounts) {
61                ScanResult scanResult = pair.first.getScanResult();
62                if (scanResult == null) continue;
63                String key = scanResult.BSSID;
64
65                // Cache the scanResult & WifiConfig
66                AvailableNetworkFailureCount availableNetworkFailureCount =
67                        mRecentAvailableNetworks.get(key);
68                if (availableNetworkFailureCount != null) {
69                    // We've already cached this, refresh timeout count & config
70                    availableNetworkFailureCount.config = pair.second;
71                } else {
72                    // New network is available
73                    availableNetworkFailureCount = new AvailableNetworkFailureCount(pair.second);
74                    availableNetworkFailureCount.Ssid = pair.first.getSSID();
75                }
76                // If we saw a network, set its Age to -1 here, next incrementation will set it to 0
77                availableNetworkFailureCount.age = -1;
78                mRecentAvailableNetworks.put(key, availableNetworkFailureCount);
79            }
80        }
81
82        // Iterate through available networks updating timeout counts & removing networks.
83        Iterator<Map.Entry<String, AvailableNetworkFailureCount>> it =
84                mRecentAvailableNetworks.entrySet().iterator();
85        while (it.hasNext()) {
86            Map.Entry<String, AvailableNetworkFailureCount> entry = it.next();
87            if (entry.getValue().age < MAX_BSSID_AGE - 1) {
88                entry.getValue().age++;
89            } else {
90                it.remove();
91            }
92        }
93        if (VDBG) Log.v(TAG, toString());
94    }
95
96    /**
97     * Gets the buffer of recently available networks
98     */
99    Map<String, AvailableNetworkFailureCount> getRecentAvailableNetworks() {
100        return mRecentAvailableNetworks;
101    }
102
103    /**
104     * Prints all networks & counts within mRecentAvailableNetworks to string
105     */
106    public String toString() {
107        StringBuilder sb = new StringBuilder();
108        sb.append("WifiLastResortWatchdog: " + mRecentAvailableNetworks.size() + " networks...");
109        for (Map.Entry<String, AvailableNetworkFailureCount> entry
110                : mRecentAvailableNetworks.entrySet()) {
111            sb.append("\n " + entry.getKey() + ": " + entry.getValue());
112        }
113        return sb.toString();
114    }
115
116    static class AvailableNetworkFailureCount {
117        /**
118         * WifiConfiguration associated with this network. Can be null for Ephemeral networks
119         */
120        public WifiConfiguration config;
121        /**
122        * SSID of the network (from ScanDetail)
123        */
124        public String Ssid = "";
125        /**
126         * Number of times network has failed for this reason
127         */
128        public int associationRejection = 0;
129        /**
130         * Number of times network has failed for this reason
131         */
132        public int authenticationRejection = 0;
133        /**
134         * Number of times network has failed for this reason
135         */
136        public int dhcpFailure = 0;
137        /**
138         * Number of scanResults since this network was last seen
139         */
140        public int age = 0;
141
142        AvailableNetworkFailureCount(WifiConfiguration config) {
143            config = config;
144        }
145
146        void resetCounts() {
147            associationRejection = 0;
148            authenticationRejection = 0;
149            dhcpFailure = 0;
150        }
151
152        public String toString() {
153            return  Ssid + ", HasEverConnected: " + ((config != null)
154                    ? config.getNetworkSelectionStatus().getHasEverConnected() : false)
155                    + ", Failures: {"
156                    + "Assoc: " + associationRejection
157                    + ", Auth: " + authenticationRejection
158                    + ", Dhcp: " + dhcpFailure
159                    + "}"
160                    + ", Age: " + age;
161        }
162    }
163}
164