Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 2017 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 import android.net.IpConfiguration;
     21 import android.net.wifi.WifiConfiguration;
     22 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
     23 import android.net.wifi.WifiEnterpriseConfig;
     24 import android.os.Process;
     25 import android.util.Log;
     26 import android.util.Pair;
     27 
     28 import com.android.server.wifi.util.XmlUtil;
     29 import com.android.server.wifi.util.XmlUtil.IpConfigurationXmlUtil;
     30 import com.android.server.wifi.util.XmlUtil.NetworkSelectionStatusXmlUtil;
     31 import com.android.server.wifi.util.XmlUtil.WifiConfigurationXmlUtil;
     32 import com.android.server.wifi.util.XmlUtil.WifiEnterpriseConfigXmlUtil;
     33 
     34 import org.xmlpull.v1.XmlPullParser;
     35 import org.xmlpull.v1.XmlPullParserException;
     36 import org.xmlpull.v1.XmlSerializer;
     37 
     38 import java.io.IOException;
     39 import java.util.ArrayList;
     40 import java.util.List;
     41 
     42 /**
     43  * This class performs serialization and parsing of XML data block that contain the list of WiFi
     44  * network configurations (XML block data inside <NetworkList> tag).
     45  */
     46 public class NetworkListStoreData implements WifiConfigStore.StoreData {
     47     private static final String TAG = "NetworkListStoreData";
     48 
     49     private static final String XML_TAG_SECTION_HEADER_NETWORK_LIST = "NetworkList";
     50     private static final String XML_TAG_SECTION_HEADER_NETWORK = "Network";
     51     private static final String XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION = "WifiConfiguration";
     52     private static final String XML_TAG_SECTION_HEADER_NETWORK_STATUS = "NetworkStatus";
     53     private static final String XML_TAG_SECTION_HEADER_IP_CONFIGURATION = "IpConfiguration";
     54     private static final String XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION =
     55             "WifiEnterpriseConfiguration";
     56 
     57     private final Context mContext;
     58 
     59     /**
     60      * List of saved shared networks visible to all the users to be stored in the shared store file.
     61      */
     62     private List<WifiConfiguration> mSharedConfigurations;
     63     /**
     64      * List of saved private networks only visible to the current user to be stored in the user
     65      * specific store file.
     66      */
     67     private List<WifiConfiguration> mUserConfigurations;
     68 
     69     NetworkListStoreData(Context context) {
     70         mContext = context;
     71     }
     72 
     73     @Override
     74     public void serializeData(XmlSerializer out, boolean shared)
     75             throws XmlPullParserException, IOException {
     76         if (shared) {
     77             serializeNetworkList(out, mSharedConfigurations);
     78         } else {
     79             serializeNetworkList(out, mUserConfigurations);
     80         }
     81     }
     82 
     83     @Override
     84     public void deserializeData(XmlPullParser in, int outerTagDepth, boolean shared)
     85             throws XmlPullParserException, IOException {
     86         // Ignore empty reads.
     87         if (in == null) {
     88             return;
     89         }
     90         if (shared) {
     91             mSharedConfigurations = parseNetworkList(in, outerTagDepth);
     92         } else {
     93             mUserConfigurations = parseNetworkList(in, outerTagDepth);
     94         }
     95     }
     96 
     97     @Override
     98     public void resetData(boolean shared) {
     99         if (shared) {
    100             mSharedConfigurations = null;
    101         } else {
    102             mUserConfigurations = null;
    103         }
    104     }
    105 
    106     @Override
    107     public String getName() {
    108         return XML_TAG_SECTION_HEADER_NETWORK_LIST;
    109     }
    110 
    111     @Override
    112     public boolean supportShareData() {
    113         return true;
    114     }
    115 
    116     public void setSharedConfigurations(List<WifiConfiguration> configs) {
    117         mSharedConfigurations = configs;
    118     }
    119 
    120     /**
    121      * An empty list will be returned if no shared configurations.
    122      *
    123      * @return List of {@link WifiConfiguration}
    124      */
    125     public List<WifiConfiguration> getSharedConfigurations() {
    126         if (mSharedConfigurations == null) {
    127             return new ArrayList<WifiConfiguration>();
    128         }
    129         return mSharedConfigurations;
    130     }
    131 
    132     public void setUserConfigurations(List<WifiConfiguration> configs) {
    133         mUserConfigurations = configs;
    134     }
    135 
    136     /**
    137      * An empty list will be returned if no user configurations.
    138      *
    139      * @return List of {@link WifiConfiguration}
    140      */
    141     public List<WifiConfiguration> getUserConfigurations() {
    142         if (mUserConfigurations == null) {
    143             return new ArrayList<WifiConfiguration>();
    144         }
    145         return mUserConfigurations;
    146     }
    147 
    148     /**
    149      * Serialize the list of {@link WifiConfiguration} to an output stream in XML format.
    150      *
    151      * @param out The output stream to serialize the data to
    152      * @param networkList The network list to serialize
    153      * @throws XmlPullParserException
    154      * @throws IOException
    155      */
    156     private void serializeNetworkList(XmlSerializer out, List<WifiConfiguration> networkList)
    157             throws XmlPullParserException, IOException {
    158         if (networkList == null) {
    159             return;
    160         }
    161         for (WifiConfiguration network : networkList) {
    162             serializeNetwork(out, network);
    163         }
    164     }
    165 
    166     /**
    167      * Serialize a {@link WifiConfiguration} to an output stream in XML format.
    168      * @param out
    169      * @param config
    170      * @throws XmlPullParserException
    171      * @throws IOException
    172      */
    173     private void serializeNetwork(XmlSerializer out, WifiConfiguration config)
    174             throws XmlPullParserException, IOException {
    175         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK);
    176 
    177         // Serialize WifiConfiguration.
    178         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION);
    179         WifiConfigurationXmlUtil.writeToXmlForConfigStore(out, config);
    180         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION);
    181 
    182         // Serialize network selection status.
    183         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK_STATUS);
    184         NetworkSelectionStatusXmlUtil.writeToXml(out, config.getNetworkSelectionStatus());
    185         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_NETWORK_STATUS);
    186 
    187         // Serialize IP configuration.
    188         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_IP_CONFIGURATION);
    189         IpConfigurationXmlUtil.writeToXml(out, config.getIpConfiguration());
    190         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_IP_CONFIGURATION);
    191 
    192         // Serialize enterprise configuration for enterprise networks.
    193         if (config.enterpriseConfig != null
    194                 && config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE) {
    195             XmlUtil.writeNextSectionStart(
    196                     out, XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION);
    197             WifiEnterpriseConfigXmlUtil.writeToXml(out, config.enterpriseConfig);
    198             XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION);
    199         }
    200 
    201         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_NETWORK);
    202     }
    203 
    204     /**
    205      * Parse a list of {@link WifiConfiguration} from an input stream in XML format.
    206      *
    207      * @param in The input stream to read from
    208      * @param outerTagDepth The XML tag depth of the outer XML block
    209      * @return List of {@link WifiConfiguration}
    210      * @throws XmlPullParserException
    211      * @throws IOException
    212      */
    213     private List<WifiConfiguration> parseNetworkList(XmlPullParser in, int outerTagDepth)
    214             throws XmlPullParserException, IOException {
    215         List<WifiConfiguration> networkList = new ArrayList<>();
    216         while (XmlUtil.gotoNextSectionWithNameOrEnd(in, XML_TAG_SECTION_HEADER_NETWORK,
    217                 outerTagDepth)) {
    218             // Try/catch only runtime exceptions (like illegal args), any XML/IO exceptions are
    219             // fatal and should abort the entire loading process.
    220             try {
    221                 WifiConfiguration config = parseNetwork(in, outerTagDepth + 1);
    222                 networkList.add(config);
    223             } catch (RuntimeException e) {
    224                 // Failed to parse this network, skip it.
    225                 Log.e(TAG, "Failed to parse network config. Skipping...", e);
    226             }
    227         }
    228         return networkList;
    229     }
    230 
    231     /**
    232      * Parse a {@link WifiConfiguration} from an input stream in XML format.
    233      *
    234      * @param in The input stream to read from
    235      * @param outerTagDepth The XML tag depth of the outer XML block
    236      * @return {@link WifiConfiguration}
    237      * @throws XmlPullParserException
    238      * @throws IOException
    239      */
    240     private WifiConfiguration parseNetwork(XmlPullParser in, int outerTagDepth)
    241             throws XmlPullParserException, IOException {
    242         Pair<String, WifiConfiguration> parsedConfig = null;
    243         NetworkSelectionStatus status = null;
    244         IpConfiguration ipConfiguration = null;
    245         WifiEnterpriseConfig enterpriseConfig = null;
    246 
    247         String[] headerName = new String[1];
    248         while (XmlUtil.gotoNextSectionOrEnd(in, headerName, outerTagDepth)) {
    249             switch (headerName[0]) {
    250                 case XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION:
    251                     if (parsedConfig != null) {
    252                         throw new XmlPullParserException("Detected duplicate tag for: "
    253                                 + XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION);
    254                     }
    255                     parsedConfig = WifiConfigurationXmlUtil.parseFromXml(in, outerTagDepth + 1);
    256                     break;
    257                 case XML_TAG_SECTION_HEADER_NETWORK_STATUS:
    258                     if (status != null) {
    259                         throw new XmlPullParserException("Detected duplicate tag for: "
    260                                 + XML_TAG_SECTION_HEADER_NETWORK_STATUS);
    261                     }
    262                     status = NetworkSelectionStatusXmlUtil.parseFromXml(in, outerTagDepth + 1);
    263                     break;
    264                 case XML_TAG_SECTION_HEADER_IP_CONFIGURATION:
    265                     if (ipConfiguration != null) {
    266                         throw new XmlPullParserException("Detected duplicate tag for: "
    267                                 + XML_TAG_SECTION_HEADER_IP_CONFIGURATION);
    268                     }
    269                     ipConfiguration = IpConfigurationXmlUtil.parseFromXml(in, outerTagDepth + 1);
    270                     break;
    271                 case XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION:
    272                     if (enterpriseConfig != null) {
    273                         throw new XmlPullParserException("Detected duplicate tag for: "
    274                                 + XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION);
    275                     }
    276                     enterpriseConfig =
    277                             WifiEnterpriseConfigXmlUtil.parseFromXml(in, outerTagDepth + 1);
    278                     break;
    279                 default:
    280                     throw new XmlPullParserException("Unknown tag under "
    281                             + XML_TAG_SECTION_HEADER_NETWORK + ": " + headerName[0]);
    282             }
    283         }
    284         if (parsedConfig == null || parsedConfig.first == null || parsedConfig.second == null) {
    285             throw new XmlPullParserException("XML parsing of wifi configuration failed");
    286         }
    287         String configKeyParsed = parsedConfig.first;
    288         WifiConfiguration configuration = parsedConfig.second;
    289         String configKeyCalculated = configuration.configKey();
    290         if (!configKeyParsed.equals(configKeyCalculated)) {
    291             throw new XmlPullParserException(
    292                     "Configuration key does not match. Retrieved: " + configKeyParsed
    293                             + ", Calculated: " + configKeyCalculated);
    294         }
    295         // Set creatorUid/creatorName for networks which don't have it set to valid value.
    296         String creatorName = mContext.getPackageManager().getNameForUid(configuration.creatorUid);
    297         if (creatorName == null) {
    298             Log.e(TAG, "Invalid creatorUid for saved network " + configuration.configKey()
    299                     + ", creatorUid=" + configuration.creatorUid);
    300             configuration.creatorUid = Process.SYSTEM_UID;
    301             configuration.creatorName =
    302                     mContext.getPackageManager().getNameForUid(Process.SYSTEM_UID);
    303         } else if (!creatorName.equals(configuration.creatorName)) {
    304             Log.w(TAG, "Invalid creatorName for saved network " + configuration.configKey()
    305                     + ", creatorUid=" + configuration.creatorUid
    306                     + ", creatorName=" + configuration.creatorName);
    307             configuration.creatorName = creatorName;
    308         }
    309 
    310         configuration.setNetworkSelectionStatus(status);
    311         configuration.setIpConfiguration(ipConfiguration);
    312         if (enterpriseConfig != null) {
    313             configuration.enterpriseConfig = enterpriseConfig;
    314         }
    315         return configuration;
    316     }
    317 }
    318 
    319