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