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