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