Home | History | Annotate | Download | only in wifi
      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