ScanDetailCache.java revision 4d381bc39f5263effdae73ec99065eb299b806ca
1
2package com.android.server.wifi;
3
4import android.net.wifi.ScanResult;
5import android.net.wifi.WifiConfiguration;
6
7import com.android.server.wifi.ScanDetail;
8import com.android.server.wifi.hotspot2.PasspointMatch;
9import com.android.server.wifi.hotspot2.PasspointMatchInfo;
10import com.android.server.wifi.hotspot2.pps.HomeSP;
11
12import java.util.ArrayList;
13import java.util.Collection;
14import java.util.Collections;
15import java.util.Comparator;
16import java.util.HashMap;
17import java.util.Iterator;
18import java.util.List;
19
20class ScanDetailCache {
21    private WifiConfiguration mConfig;
22    private HashMap<String, ScanDetail> mMap;
23    private HashMap<String, PasspointMatchInfo> mPasspointMatches;
24
25    ScanDetailCache(WifiConfiguration config) {
26        mConfig = config;
27        mMap = new HashMap();
28        mPasspointMatches = new HashMap();
29    }
30
31    void put(ScanDetail scanDetail) {
32        put(scanDetail, null, null);
33    }
34
35    void put(ScanDetail scanDetail, PasspointMatch match, HomeSP homeSp) {
36        mMap.put(scanDetail.getBSSIDString(), scanDetail);
37        mPasspointMatches.put(scanDetail.getBSSIDString(),
38                new PasspointMatchInfo(match, scanDetail, homeSp));
39    }
40
41    ScanResult get(String bssid) {
42        ScanDetail scanDetail = getScanDetail(bssid);
43        return scanDetail == null ? null : scanDetail.getScanResult();
44    }
45
46    ScanDetail getScanDetail(String bssid) {
47        return mMap.get(bssid);
48    }
49
50    void remove(String bssid) {
51        mMap.remove(bssid);
52    }
53
54    int size() {
55        return mMap.size();
56    }
57
58    boolean isEmpty() {
59        return size() == 0;
60    }
61
62    ScanDetail getFirst() {
63        Iterator<ScanDetail> it = mMap.values().iterator();
64        return it.hasNext() ? it.next() : null;
65    }
66
67    Collection<String> keySet() {
68        return mMap.keySet();
69    }
70
71    Collection<ScanDetail> values() {
72        return mMap.values();
73    }
74
75    public void trim(int num) {
76        int currentSize = mMap.size();
77        if (currentSize <= num) {
78            return; // Nothing to trim
79        }
80        ArrayList<ScanDetail> list = new ArrayList<ScanDetail>(mMap.values());
81        if (list.size() != 0) {
82            // Sort by descending timestamp
83            Collections.sort(list, new Comparator() {
84                public int compare(Object o1, Object o2) {
85                    ScanDetail a = (ScanDetail) o1;
86                    ScanDetail b = (ScanDetail) o2;
87                    if (a.getSeen() > b.getSeen()) {
88                        return 1;
89                    }
90                    if (a.getSeen() < b.getSeen()) {
91                        return -1;
92                    }
93                    return a.getBSSIDString().compareTo(b.getBSSIDString());
94                }
95            });
96        }
97        for (int i = 0; i < currentSize - num ; i++) {
98            // Remove oldest results from scan cache
99            ScanDetail result = list.get(i);
100            mMap.remove(result.getBSSIDString());
101            mPasspointMatches.remove(result.getBSSIDString());
102        }
103    }
104
105    /* @hide */
106    private ArrayList<ScanDetail> sort() {
107        ArrayList<ScanDetail> list = new ArrayList<ScanDetail>(mMap.values());
108        if (list.size() != 0) {
109            Collections.sort(list, new Comparator() {
110                public int compare(Object o1, Object o2) {
111                    ScanResult a = ((ScanDetail)o1).getScanResult();
112                    ScanResult b = ((ScanDetail)o2).getScanResult();
113                    if (a.numIpConfigFailures > b.numIpConfigFailures) {
114                        return 1;
115                    }
116                    if (a.numIpConfigFailures < b.numIpConfigFailures) {
117                        return -1;
118                    }
119                    if (a.seen > b.seen) {
120                        return -1;
121                    }
122                    if (a.seen < b.seen) {
123                        return 1;
124                    }
125                    if (a.level > b.level) {
126                        return -1;
127                    }
128                    if (a.level < b.level) {
129                        return 1;
130                    }
131                    return a.BSSID.compareTo(b.BSSID);
132                }
133            });
134        }
135        return list;
136    }
137
138    public WifiConfiguration.Visibility getVisibilityByRssi(long age) {
139        WifiConfiguration.Visibility status = new WifiConfiguration.Visibility();
140
141        long now_ms = System.currentTimeMillis();
142        for(ScanDetail scanDetail : values()) {
143            ScanResult result = scanDetail.getScanResult();
144            if (scanDetail.getSeen() == 0)
145                continue;
146
147            if (result.is5GHz()) {
148                //strictly speaking: [4915, 5825]
149                //number of known BSSID on 5GHz band
150                status.num5 = status.num5 + 1;
151            } else if (result.is24GHz()) {
152                //strictly speaking: [2412, 2482]
153                //number of known BSSID on 2.4Ghz band
154                status.num24 = status.num24 + 1;
155            }
156
157            if ((now_ms - result.seen) > age) continue;
158
159            if (result.is5GHz()) {
160                if (result.level > status.rssi5) {
161                    status.rssi5 = result.level;
162                    status.age5 = result.seen;
163                    status.BSSID5 = result.BSSID;
164                }
165            } else if (result.is24GHz()) {
166                if (result.level > status.rssi24) {
167                    status.rssi24 = result.level;
168                    status.age24 = result.seen;
169                    status.BSSID24 = result.BSSID;
170                }
171            }
172        }
173
174        return status;
175    }
176
177    public WifiConfiguration.Visibility getVisibilityByPasspointMatch(long age) {
178        WifiConfiguration.Visibility status = new WifiConfiguration.Visibility();
179
180        long now_ms = System.currentTimeMillis();
181        for(ScanDetail scanDetail : values()) {
182            ScanResult result = scanDetail.getScanResult();
183            if (scanDetail.getSeen() == 0)
184                continue;
185
186            if (result.is5GHz()) {
187                //strictly speaking: [4915, 5825]
188                //number of known BSSID on 5GHz band
189                status.num5 = status.num5 + 1;
190            } else if (result.is24GHz()) {
191                //strictly speaking: [2412, 2482]
192                //number of known BSSID on 2.4Ghz band
193                status.num24 = status.num24 + 1;
194            }
195
196            if ((now_ms - result.seen) > age) continue;
197
198            if (result.is5GHz()) {
199                if (result.level > status.rssi5) {
200                    status.rssi5 = result.level;
201                    status.age5 = result.seen;
202                    status.BSSID5 = result.BSSID;
203                }
204            } else if (result.is24GHz()) {
205                if (result.level > status.rssi24) {
206                    status.rssi24 = result.level;
207                    status.age24 = result.seen;
208                    status.BSSID24 = result.BSSID;
209                }
210            }
211        }
212
213        return status;
214    }
215
216    public WifiConfiguration.Visibility getVisibility(long age) {
217        if (mConfig.isPasspoint()) {
218            return getVisibilityByPasspointMatch(age);
219        } else {
220            return getVisibilityByRssi(age);
221        }
222    }
223
224
225
226    @Override
227    public String toString() {
228        StringBuilder sbuf = new StringBuilder();
229        sbuf.append("Scan Cache:  ").append('\n');
230
231        ArrayList<ScanDetail> list = sort();
232        long now_ms = System.currentTimeMillis();
233        if (list.size() > 0) {
234            for (ScanDetail scanDetail : list) {
235                ScanResult result = scanDetail.getScanResult();
236                long milli = now_ms - scanDetail.getSeen();
237                long ageSec = 0;
238                long ageMin = 0;
239                long ageHour = 0;
240                long ageMilli = 0;
241                long ageDay = 0;
242                if (now_ms > scanDetail.getSeen() && scanDetail.getSeen() > 0) {
243                    ageMilli = milli % 1000;
244                    ageSec   = (milli / 1000) % 60;
245                    ageMin   = (milli / (60*1000)) % 60;
246                    ageHour  = (milli / (60*60*1000)) % 24;
247                    ageDay   = (milli / (24*60*60*1000));
248                }
249                sbuf.append("{").append(result.BSSID).append(",").append(result.frequency);
250                sbuf.append(",").append(String.format("%3d", result.level));
251                if (result.autoJoinStatus > 0) {
252                    sbuf.append(",st=").append(result.autoJoinStatus);
253                }
254                if (ageSec > 0 || ageMilli > 0) {
255                    sbuf.append(String.format(",%4d.%02d.%02d.%02d.%03dms", ageDay,
256                            ageHour, ageMin, ageSec, ageMilli));
257                }
258                if (result.numIpConfigFailures > 0) {
259                    sbuf.append(",ipfail=");
260                    sbuf.append(result.numIpConfigFailures);
261                }
262                sbuf.append("} ");
263            }
264            sbuf.append('\n');
265        }
266
267        return sbuf.toString();
268    }
269
270}
271