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