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