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