1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi; 18 19 import android.content.Context; 20 21 import android.net.wifi.ScanResult; 22 23 import android.net.wifi.WifiConfiguration; 24 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; 25 import android.net.wifi.WifiSsid; 26 import android.os.Environment; 27 import android.os.Process; 28 import android.text.TextUtils; 29 30 import android.util.LocalLog; 31 import android.util.Log; 32 33 import com.android.server.net.DelayedDiskWrite; 34 35 import java.io.BufferedInputStream; 36 import java.io.DataInputStream; 37 import java.io.DataOutputStream; 38 import java.io.EOFException; 39 import java.io.FileInputStream; 40 import java.io.FileNotFoundException; 41 import java.io.IOException; 42 import java.text.DateFormat; 43 import java.util.BitSet; 44 import java.util.HashMap; 45 import java.util.HashSet; 46 import java.util.List; 47 import java.util.Map; 48 import java.util.Set; 49 import java.util.concurrent.ConcurrentHashMap; 50 51 /** 52 * Provides an API to read and write the network history from WifiConfigurations to file 53 * This is largely separate and extra to the supplicant config file. 54 */ 55 public class WifiNetworkHistory { 56 public static final String TAG = "WifiNetworkHistory"; 57 private static final boolean DBG = true; 58 private static final boolean VDBG = true; 59 static final String NETWORK_HISTORY_CONFIG_FILE = Environment.getDataDirectory() 60 + "/misc/wifi/networkHistory.txt"; 61 /* Network History Keys */ 62 private static final String SSID_KEY = "SSID"; 63 static final String CONFIG_KEY = "CONFIG"; 64 private static final String CONFIG_BSSID_KEY = "CONFIG_BSSID"; 65 private static final String CHOICE_KEY = "CHOICE"; 66 private static final String CHOICE_TIME_KEY = "CHOICE_TIME"; 67 private static final String LINK_KEY = "LINK"; 68 private static final String BSSID_KEY = "BSSID"; 69 private static final String BSSID_KEY_END = "/BSSID"; 70 private static final String RSSI_KEY = "RSSI"; 71 private static final String FREQ_KEY = "FREQ"; 72 private static final String DATE_KEY = "DATE"; 73 private static final String MILLI_KEY = "MILLI"; 74 private static final String NETWORK_ID_KEY = "ID"; 75 private static final String PRIORITY_KEY = "PRIORITY"; 76 private static final String DEFAULT_GW_KEY = "DEFAULT_GW"; 77 private static final String AUTH_KEY = "AUTH"; 78 private static final String BSSID_STATUS_KEY = "BSSID_STATUS"; 79 private static final String SELF_ADDED_KEY = "SELF_ADDED"; 80 private static final String FAILURE_KEY = "FAILURE"; 81 private static final String DID_SELF_ADD_KEY = "DID_SELF_ADD"; 82 private static final String PEER_CONFIGURATION_KEY = "PEER_CONFIGURATION"; 83 static final String CREATOR_UID_KEY = "CREATOR_UID_KEY"; 84 private static final String CONNECT_UID_KEY = "CONNECT_UID_KEY"; 85 private static final String UPDATE_UID_KEY = "UPDATE_UID"; 86 private static final String FQDN_KEY = "FQDN"; 87 private static final String SCORER_OVERRIDE_KEY = "SCORER_OVERRIDE"; 88 private static final String SCORER_OVERRIDE_AND_SWITCH_KEY = "SCORER_OVERRIDE_AND_SWITCH"; 89 private static final String VALIDATED_INTERNET_ACCESS_KEY = "VALIDATED_INTERNET_ACCESS"; 90 private static final String NO_INTERNET_ACCESS_REPORTS_KEY = "NO_INTERNET_ACCESS_REPORTS"; 91 private static final String NO_INTERNET_ACCESS_EXPECTED_KEY = "NO_INTERNET_ACCESS_EXPECTED"; 92 private static final String EPHEMERAL_KEY = "EPHEMERAL"; 93 private static final String USE_EXTERNAL_SCORES_KEY = "USE_EXTERNAL_SCORES"; 94 private static final String METERED_HINT_KEY = "METERED_HINT"; 95 private static final String NUM_ASSOCIATION_KEY = "NUM_ASSOCIATION"; 96 private static final String DELETED_EPHEMERAL_KEY = "DELETED_EPHEMERAL"; 97 private static final String CREATOR_NAME_KEY = "CREATOR_NAME"; 98 private static final String UPDATE_NAME_KEY = "UPDATE_NAME"; 99 private static final String USER_APPROVED_KEY = "USER_APPROVED"; 100 private static final String CREATION_TIME_KEY = "CREATION_TIME"; 101 private static final String UPDATE_TIME_KEY = "UPDATE_TIME"; 102 static final String SHARED_KEY = "SHARED"; 103 private static final String NETWORK_SELECTION_STATUS_KEY = "NETWORK_SELECTION_STATUS"; 104 private static final String NETWORK_SELECTION_DISABLE_REASON_KEY = 105 "NETWORK_SELECTION_DISABLE_REASON"; 106 private static final String HAS_EVER_CONNECTED_KEY = "HAS_EVER_CONNECTED"; 107 108 private static final String SEPARATOR = ": "; 109 private static final String NL = "\n"; 110 111 protected final DelayedDiskWrite mWriter; 112 Context mContext; 113 private final LocalLog mLocalLog; 114 /* 115 * Lost config list, whenever we read a config from networkHistory.txt that was not in 116 * wpa_supplicant.conf 117 */ 118 HashSet<String> mLostConfigsDbg = new HashSet<String>(); 119 120 public WifiNetworkHistory(Context c, LocalLog localLog, DelayedDiskWrite writer) { 121 mContext = c; 122 mWriter = writer; 123 mLocalLog = localLog; 124 } 125 126 /** 127 * Write network history to file, for configured networks 128 * 129 * @param networks List of ConfiguredNetworks to write to NetworkHistory 130 */ 131 public void writeKnownNetworkHistory(final List<WifiConfiguration> networks, 132 final ConcurrentHashMap<Integer, ScanDetailCache> scanDetailCaches, 133 final Set<String> deletedEphemeralSSIDs) { 134 135 /* Make a copy */ 136 //final List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 137 138 //for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) { 139 // networks.add(new WifiConfiguration(config)); 140 //} 141 142 mWriter.write(NETWORK_HISTORY_CONFIG_FILE, new DelayedDiskWrite.Writer() { 143 public void onWriteCalled(DataOutputStream out) throws IOException { 144 for (WifiConfiguration config : networks) { 145 //loge("onWriteCalled write SSID: " + config.SSID); 146 /* if (config.getLinkProperties() != null) 147 loge(" lp " + config.getLinkProperties().toString()); 148 else 149 loge("attempt config w/o lp"); 150 */ 151 NetworkSelectionStatus status = config.getNetworkSelectionStatus(); 152 if (VDBG) { 153 int numlink = 0; 154 if (config.linkedConfigurations != null) { 155 numlink = config.linkedConfigurations.size(); 156 } 157 String disableTime; 158 if (config.getNetworkSelectionStatus().isNetworkEnabled()) { 159 disableTime = ""; 160 } else { 161 disableTime = "Disable time: " + DateFormat.getInstance().format( 162 config.getNetworkSelectionStatus().getDisableTime()); 163 } 164 logd("saving network history: " + config.configKey() + " gw: " 165 + config.defaultGwMacAddress + " Network Selection-status: " 166 + status.getNetworkStatusString() 167 + disableTime + " ephemeral=" + config.ephemeral 168 + " choice:" + status.getConnectChoice() 169 + " link:" + numlink 170 + " status:" + config.status 171 + " nid:" + config.networkId 172 + " hasEverConnected: " + status.getHasEverConnected()); 173 } 174 175 if (!isValid(config)) { 176 continue; 177 } 178 179 if (config.SSID == null) { 180 if (VDBG) { 181 logv("writeKnownNetworkHistory trying to write config with null SSID"); 182 } 183 continue; 184 } 185 if (VDBG) { 186 logv("writeKnownNetworkHistory write config " + config.configKey()); 187 } 188 out.writeUTF(CONFIG_KEY + SEPARATOR + config.configKey() + NL); 189 190 if (config.SSID != null) { 191 out.writeUTF(SSID_KEY + SEPARATOR + config.SSID + NL); 192 } 193 if (config.BSSID != null) { 194 out.writeUTF(CONFIG_BSSID_KEY + SEPARATOR + config.BSSID + NL); 195 } else { 196 out.writeUTF(CONFIG_BSSID_KEY + SEPARATOR + "null" + NL); 197 } 198 if (config.FQDN != null) { 199 out.writeUTF(FQDN_KEY + SEPARATOR + config.FQDN + NL); 200 } 201 202 out.writeUTF(PRIORITY_KEY + SEPARATOR + Integer.toString(config.priority) + NL); 203 out.writeUTF(NETWORK_ID_KEY + SEPARATOR 204 + Integer.toString(config.networkId) + NL); 205 out.writeUTF(SELF_ADDED_KEY + SEPARATOR 206 + Boolean.toString(config.selfAdded) + NL); 207 out.writeUTF(DID_SELF_ADD_KEY + SEPARATOR 208 + Boolean.toString(config.didSelfAdd) + NL); 209 out.writeUTF(NO_INTERNET_ACCESS_REPORTS_KEY + SEPARATOR 210 + Integer.toString(config.numNoInternetAccessReports) + NL); 211 out.writeUTF(VALIDATED_INTERNET_ACCESS_KEY + SEPARATOR 212 + Boolean.toString(config.validatedInternetAccess) + NL); 213 out.writeUTF(NO_INTERNET_ACCESS_EXPECTED_KEY + SEPARATOR + 214 Boolean.toString(config.noInternetAccessExpected) + NL); 215 out.writeUTF(EPHEMERAL_KEY + SEPARATOR 216 + Boolean.toString(config.ephemeral) + NL); 217 out.writeUTF(METERED_HINT_KEY + SEPARATOR 218 + Boolean.toString(config.meteredHint) + NL); 219 out.writeUTF(USE_EXTERNAL_SCORES_KEY + SEPARATOR 220 + Boolean.toString(config.useExternalScores) + NL); 221 if (config.creationTime != null) { 222 out.writeUTF(CREATION_TIME_KEY + SEPARATOR + config.creationTime + NL); 223 } 224 if (config.updateTime != null) { 225 out.writeUTF(UPDATE_TIME_KEY + SEPARATOR + config.updateTime + NL); 226 } 227 if (config.peerWifiConfiguration != null) { 228 out.writeUTF(PEER_CONFIGURATION_KEY + SEPARATOR 229 + config.peerWifiConfiguration + NL); 230 } 231 out.writeUTF(SCORER_OVERRIDE_KEY + SEPARATOR 232 + Integer.toString(config.numScorerOverride) + NL); 233 out.writeUTF(SCORER_OVERRIDE_AND_SWITCH_KEY + SEPARATOR 234 + Integer.toString(config.numScorerOverrideAndSwitchedNetwork) + NL); 235 out.writeUTF(NUM_ASSOCIATION_KEY + SEPARATOR 236 + Integer.toString(config.numAssociation) + NL); 237 out.writeUTF(CREATOR_UID_KEY + SEPARATOR 238 + Integer.toString(config.creatorUid) + NL); 239 out.writeUTF(CONNECT_UID_KEY + SEPARATOR 240 + Integer.toString(config.lastConnectUid) + NL); 241 out.writeUTF(UPDATE_UID_KEY + SEPARATOR 242 + Integer.toString(config.lastUpdateUid) + NL); 243 out.writeUTF(CREATOR_NAME_KEY + SEPARATOR 244 + config.creatorName + NL); 245 out.writeUTF(UPDATE_NAME_KEY + SEPARATOR 246 + config.lastUpdateName + NL); 247 out.writeUTF(USER_APPROVED_KEY + SEPARATOR 248 + Integer.toString(config.userApproved) + NL); 249 out.writeUTF(SHARED_KEY + SEPARATOR + Boolean.toString(config.shared) + NL); 250 String allowedKeyManagementString = 251 makeString(config.allowedKeyManagement, 252 WifiConfiguration.KeyMgmt.strings); 253 out.writeUTF(AUTH_KEY + SEPARATOR 254 + allowedKeyManagementString + NL); 255 out.writeUTF(NETWORK_SELECTION_STATUS_KEY + SEPARATOR 256 + status.getNetworkSelectionStatus() + NL); 257 out.writeUTF(NETWORK_SELECTION_DISABLE_REASON_KEY + SEPARATOR 258 + status.getNetworkSelectionDisableReason() + NL); 259 260 if (status.getConnectChoice() != null) { 261 out.writeUTF(CHOICE_KEY + SEPARATOR + status.getConnectChoice() + NL); 262 out.writeUTF(CHOICE_TIME_KEY + SEPARATOR 263 + status.getConnectChoiceTimestamp() + NL); 264 } 265 266 if (config.linkedConfigurations != null) { 267 log("writeKnownNetworkHistory write linked " 268 + config.linkedConfigurations.size()); 269 270 for (String key : config.linkedConfigurations.keySet()) { 271 out.writeUTF(LINK_KEY + SEPARATOR + key + NL); 272 } 273 } 274 275 String macAddress = config.defaultGwMacAddress; 276 if (macAddress != null) { 277 out.writeUTF(DEFAULT_GW_KEY + SEPARATOR + macAddress + NL); 278 } 279 280 if (getScanDetailCache(config, scanDetailCaches) != null) { 281 for (ScanDetail scanDetail : getScanDetailCache(config, 282 scanDetailCaches).values()) { 283 ScanResult result = scanDetail.getScanResult(); 284 out.writeUTF(BSSID_KEY + SEPARATOR 285 + result.BSSID + NL); 286 out.writeUTF(FREQ_KEY + SEPARATOR 287 + Integer.toString(result.frequency) + NL); 288 289 out.writeUTF(RSSI_KEY + SEPARATOR 290 + Integer.toString(result.level) + NL); 291 292 out.writeUTF(BSSID_KEY_END + NL); 293 } 294 } 295 if (config.lastFailure != null) { 296 out.writeUTF(FAILURE_KEY + SEPARATOR + config.lastFailure + NL); 297 } 298 out.writeUTF(HAS_EVER_CONNECTED_KEY + SEPARATOR 299 + Boolean.toString(status.getHasEverConnected()) + NL); 300 out.writeUTF(NL); 301 // Add extra blank lines for clarity 302 out.writeUTF(NL); 303 out.writeUTF(NL); 304 } 305 if (deletedEphemeralSSIDs != null && deletedEphemeralSSIDs.size() > 0) { 306 for (String ssid : deletedEphemeralSSIDs) { 307 out.writeUTF(DELETED_EPHEMERAL_KEY); 308 out.writeUTF(ssid); 309 out.writeUTF(NL); 310 } 311 } 312 } 313 }); 314 } 315 316 /** 317 * Adds information stored in networkHistory.txt to the given configs. The configs are provided 318 * as a mapping from configKey to WifiConfiguration, because the WifiConfigurations themselves 319 * do not contain sufficient information to compute their configKeys until after the information 320 * that is stored in networkHistory.txt has been added to them. 321 * 322 * @param configs mapping from configKey to a WifiConfiguration that contains the information 323 * information read from wpa_supplicant.conf 324 */ 325 public void readNetworkHistory(Map<String, WifiConfiguration> configs, 326 ConcurrentHashMap<Integer, ScanDetailCache> scanDetailCaches, 327 Set<String> deletedEphemeralSSIDs) { 328 localLog("readNetworkHistory() path:" + NETWORK_HISTORY_CONFIG_FILE); 329 330 try (DataInputStream in = 331 new DataInputStream(new BufferedInputStream( 332 new FileInputStream(NETWORK_HISTORY_CONFIG_FILE)))) { 333 334 String bssid = null; 335 String ssid = null; 336 337 int freq = 0; 338 int status = 0; 339 long seen = 0; 340 int rssi = WifiConfiguration.INVALID_RSSI; 341 String caps = null; 342 343 WifiConfiguration config = null; 344 while (true) { 345 String line = in.readUTF(); 346 if (line == null) { 347 break; 348 } 349 int colon = line.indexOf(':'); 350 if (colon < 0) { 351 continue; 352 } 353 354 String key = line.substring(0, colon).trim(); 355 String value = line.substring(colon + 1).trim(); 356 357 if (key.equals(CONFIG_KEY)) { 358 config = configs.get(value); 359 360 // skip reading that configuration data 361 // since we don't have a corresponding network ID 362 if (config == null) { 363 localLog("readNetworkHistory didnt find netid for hash=" 364 + Integer.toString(value.hashCode()) 365 + " key: " + value); 366 mLostConfigsDbg.add(value); 367 continue; 368 } else { 369 // After an upgrade count old connections as owned by system 370 if (config.creatorName == null || config.lastUpdateName == null) { 371 config.creatorName = 372 mContext.getPackageManager().getNameForUid(Process.SYSTEM_UID); 373 config.lastUpdateName = config.creatorName; 374 375 if (DBG) { 376 Log.w(TAG, "Upgrading network " + config.networkId 377 + " to " + config.creatorName); 378 } 379 } 380 } 381 } else if (config != null) { 382 NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); 383 switch (key) { 384 case SSID_KEY: 385 if (config.isPasspoint()) { 386 break; 387 } 388 ssid = value; 389 if (config.SSID != null && !config.SSID.equals(ssid)) { 390 loge("Error parsing network history file, mismatched SSIDs"); 391 config = null; //error 392 ssid = null; 393 } else { 394 config.SSID = ssid; 395 } 396 break; 397 case CONFIG_BSSID_KEY: 398 config.BSSID = value.equals("null") ? null : value; 399 break; 400 case FQDN_KEY: 401 // Check for literal 'null' to be backwards compatible. 402 config.FQDN = value.equals("null") ? null : value; 403 break; 404 case DEFAULT_GW_KEY: 405 config.defaultGwMacAddress = value; 406 break; 407 case SELF_ADDED_KEY: 408 config.selfAdded = Boolean.parseBoolean(value); 409 break; 410 case DID_SELF_ADD_KEY: 411 config.didSelfAdd = Boolean.parseBoolean(value); 412 break; 413 case NO_INTERNET_ACCESS_REPORTS_KEY: 414 config.numNoInternetAccessReports = Integer.parseInt(value); 415 break; 416 case VALIDATED_INTERNET_ACCESS_KEY: 417 config.validatedInternetAccess = Boolean.parseBoolean(value); 418 break; 419 case NO_INTERNET_ACCESS_EXPECTED_KEY: 420 config.noInternetAccessExpected = Boolean.parseBoolean(value); 421 break; 422 case CREATION_TIME_KEY: 423 config.creationTime = value; 424 break; 425 case UPDATE_TIME_KEY: 426 config.updateTime = value; 427 break; 428 case EPHEMERAL_KEY: 429 config.ephemeral = Boolean.parseBoolean(value); 430 break; 431 case METERED_HINT_KEY: 432 config.meteredHint = Boolean.parseBoolean(value); 433 break; 434 case USE_EXTERNAL_SCORES_KEY: 435 config.useExternalScores = Boolean.parseBoolean(value); 436 break; 437 case CREATOR_UID_KEY: 438 config.creatorUid = Integer.parseInt(value); 439 break; 440 case SCORER_OVERRIDE_KEY: 441 config.numScorerOverride = Integer.parseInt(value); 442 break; 443 case SCORER_OVERRIDE_AND_SWITCH_KEY: 444 config.numScorerOverrideAndSwitchedNetwork = Integer.parseInt(value); 445 break; 446 case NUM_ASSOCIATION_KEY: 447 config.numAssociation = Integer.parseInt(value); 448 break; 449 case CONNECT_UID_KEY: 450 config.lastConnectUid = Integer.parseInt(value); 451 break; 452 case UPDATE_UID_KEY: 453 config.lastUpdateUid = Integer.parseInt(value); 454 break; 455 case FAILURE_KEY: 456 config.lastFailure = value; 457 break; 458 case PEER_CONFIGURATION_KEY: 459 config.peerWifiConfiguration = value; 460 break; 461 case NETWORK_SELECTION_STATUS_KEY: 462 int networkStatusValue = Integer.parseInt(value); 463 // Reset temporarily disabled network status 464 if (networkStatusValue == 465 NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED) { 466 networkStatusValue = 467 NetworkSelectionStatus.NETWORK_SELECTION_ENABLED; 468 } 469 networkStatus.setNetworkSelectionStatus(networkStatusValue); 470 break; 471 case NETWORK_SELECTION_DISABLE_REASON_KEY: 472 networkStatus.setNetworkSelectionDisableReason(Integer.parseInt(value)); 473 break; 474 case CHOICE_KEY: 475 networkStatus.setConnectChoice(value); 476 break; 477 case CHOICE_TIME_KEY: 478 networkStatus.setConnectChoiceTimestamp(Long.parseLong(value)); 479 break; 480 case LINK_KEY: 481 if (config.linkedConfigurations == null) { 482 config.linkedConfigurations = new HashMap<>(); 483 } else { 484 config.linkedConfigurations.put(value, -1); 485 } 486 break; 487 case BSSID_KEY: 488 status = 0; 489 ssid = null; 490 bssid = null; 491 freq = 0; 492 seen = 0; 493 rssi = WifiConfiguration.INVALID_RSSI; 494 caps = ""; 495 break; 496 case RSSI_KEY: 497 rssi = Integer.parseInt(value); 498 break; 499 case FREQ_KEY: 500 freq = Integer.parseInt(value); 501 break; 502 case DATE_KEY: 503 /* 504 * when reading the configuration from file we don't update the date 505 * so as to avoid reading back stale or non-sensical data that would 506 * depend on network time. 507 * The date of a WifiConfiguration should only come from actual scan 508 * result. 509 * 510 String s = key.replace(FREQ_KEY, ""); 511 seen = Integer.getInteger(s); 512 */ 513 break; 514 case BSSID_KEY_END: 515 if ((bssid != null) && (ssid != null)) { 516 if (getScanDetailCache(config, scanDetailCaches) != null) { 517 WifiSsid wssid = WifiSsid.createFromAsciiEncoded(ssid); 518 ScanDetail scanDetail = new ScanDetail(wssid, bssid, 519 caps, rssi, freq, (long) 0, seen); 520 getScanDetailCache(config, scanDetailCaches).put(scanDetail); 521 } 522 } 523 break; 524 case DELETED_EPHEMERAL_KEY: 525 if (!TextUtils.isEmpty(value)) { 526 deletedEphemeralSSIDs.add(value); 527 } 528 break; 529 case CREATOR_NAME_KEY: 530 config.creatorName = value; 531 break; 532 case UPDATE_NAME_KEY: 533 config.lastUpdateName = value; 534 break; 535 case USER_APPROVED_KEY: 536 config.userApproved = Integer.parseInt(value); 537 break; 538 case SHARED_KEY: 539 config.shared = Boolean.parseBoolean(value); 540 break; 541 case HAS_EVER_CONNECTED_KEY: 542 networkStatus.setHasEverConnected(Boolean.parseBoolean(value)); 543 break; 544 } 545 } 546 } 547 } catch (EOFException e) { 548 // do nothing 549 } catch (FileNotFoundException e) { 550 Log.i(TAG, "readNetworkHistory: no config file, " + e); 551 } catch (NumberFormatException e) { 552 Log.e(TAG, "readNetworkHistory: failed to parse, " + e, e); 553 } catch (IOException e) { 554 Log.e(TAG, "readNetworkHistory: failed to read, " + e, e); 555 } 556 } 557 558 /** 559 * Ported this out of WifiServiceImpl, I have no idea what it's doing 560 * <TODO> figure out what/why this is doing 561 * <TODO> Port it into WifiConfiguration, then remove all the silly business from ServiceImpl 562 */ 563 public boolean isValid(WifiConfiguration config) { 564 if (config.allowedKeyManagement == null) { 565 return false; 566 } 567 if (config.allowedKeyManagement.cardinality() > 1) { 568 if (config.allowedKeyManagement.cardinality() != 2) { 569 return false; 570 } 571 if (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP)) { 572 return false; 573 } 574 if ((!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X)) 575 && (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK))) { 576 return false; 577 } 578 } 579 return true; 580 } 581 582 private static String makeString(BitSet set, String[] strings) { 583 StringBuffer buf = new StringBuffer(); 584 int nextSetBit = -1; 585 586 /* Make sure all set bits are in [0, strings.length) to avoid 587 * going out of bounds on strings. (Shouldn't happen, but...) */ 588 set = set.get(0, strings.length); 589 590 while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { 591 buf.append(strings[nextSetBit].replace('_', '-')).append(' '); 592 } 593 594 // remove trailing space 595 if (set.cardinality() > 0) { 596 buf.setLength(buf.length() - 1); 597 } 598 599 return buf.toString(); 600 } 601 602 protected void logv(String s) { 603 Log.v(TAG, s); 604 } 605 protected void logd(String s) { 606 Log.d(TAG, s); 607 } 608 protected void log(String s) { 609 Log.d(TAG, s); 610 } 611 protected void loge(String s) { 612 loge(s, false); 613 } 614 protected void loge(String s, boolean stack) { 615 if (stack) { 616 Log.e(TAG, s + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 617 + " - " + Thread.currentThread().getStackTrace()[3].getMethodName() 618 + " - " + Thread.currentThread().getStackTrace()[4].getMethodName() 619 + " - " + Thread.currentThread().getStackTrace()[5].getMethodName()); 620 } else { 621 Log.e(TAG, s); 622 } 623 } 624 625 private void localLog(String s) { 626 if (mLocalLog != null) { 627 mLocalLog.log(s); 628 } 629 } 630 631 private ScanDetailCache getScanDetailCache(WifiConfiguration config, 632 ConcurrentHashMap<Integer, ScanDetailCache> scanDetailCaches) { 633 if (config == null || scanDetailCaches == null) return null; 634 ScanDetailCache cache = scanDetailCaches.get(config.networkId); 635 if (cache == null && config.networkId != WifiConfiguration.INVALID_NETWORK_ID) { 636 cache = new ScanDetailCache(config); 637 scanDetailCaches.put(config.networkId, cache); 638 } 639 return cache; 640 } 641 } 642