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