WifiConfigurationUtil.java revision 0d14dbc1da819e72054b9f168c8e3db767dd34bf
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 17package com.android.server.wifi; 18 19import android.content.pm.UserInfo; 20import android.net.IpConfiguration; 21import android.net.wifi.WifiConfiguration; 22import android.net.wifi.WifiEnterpriseConfig; 23import android.net.wifi.WifiScanner; 24import android.os.UserHandle; 25 26import com.android.internal.annotations.VisibleForTesting; 27 28import java.security.cert.X509Certificate; 29import java.util.Arrays; 30import java.util.Comparator; 31import java.util.List; 32import java.util.Objects; 33 34/** 35 * WifiConfiguration utility for any {@link android.net.wifi.WifiConfiguration} related operations. 36 * Currently contains: 37 * > Helper method to check if the WifiConfiguration object is visible to the provided users. 38 * > Helper methods to identify the encryption of a WifiConfiguration object. 39 */ 40public class WifiConfigurationUtil { 41 /** 42 * Check whether a network configuration is visible to a user or any of its managed profiles. 43 * 44 * @param config the network configuration whose visibility should be checked 45 * @param profiles the user IDs of the user itself and all its managed profiles (can be obtained 46 * via {@link android.os.UserManager#getProfiles}) 47 * @return whether the network configuration is visible to the user or any of its managed 48 * profiles 49 */ 50 public static boolean isVisibleToAnyProfile(WifiConfiguration config, List<UserInfo> profiles) { 51 return (config.shared || doesUidBelongToAnyProfile(config.creatorUid, profiles)); 52 } 53 54 /** 55 * Check whether a uid belong to a user or any of its managed profiles. 56 * 57 * @param uid uid of the app. 58 * @param profiles the user IDs of the user itself and all its managed profiles (can be obtained 59 * via {@link android.os.UserManager#getProfiles}) 60 * @return whether the uid belongs to the user or any of its managed profiles. 61 */ 62 public static boolean doesUidBelongToAnyProfile(int uid, List<UserInfo> profiles) { 63 final int userId = UserHandle.getUserId(uid); 64 for (UserInfo profile : profiles) { 65 if (profile.id == userId) { 66 return true; 67 } 68 } 69 return false; 70 } 71 72 /** 73 * Checks if the provided |wepKeys| array contains any non-null value; 74 */ 75 public static boolean hasAnyValidWepKey(String[] wepKeys) { 76 for (int i = 0; i < wepKeys.length; i++) { 77 if (wepKeys[i] != null) { 78 return true; 79 } 80 } 81 return false; 82 } 83 84 /** 85 * Helper method to check if the provided |config| corresponds to a PSK network or not. 86 */ 87 public static boolean isConfigForPskNetwork(WifiConfiguration config) { 88 return config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK); 89 } 90 91 /** 92 * Helper method to check if the provided |config| corresponds to a EAP network or not. 93 */ 94 public static boolean isConfigForEapNetwork(WifiConfiguration config) { 95 return (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP) 96 || config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X)); 97 } 98 99 /** 100 * Helper method to check if the provided |config| corresponds to a WEP network or not. 101 */ 102 public static boolean isConfigForWepNetwork(WifiConfiguration config) { 103 return (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE) 104 && hasAnyValidWepKey(config.wepKeys)); 105 } 106 107 /** 108 * Helper method to check if the provided |config| corresponds to an open network or not. 109 */ 110 public static boolean isConfigForOpenNetwork(WifiConfiguration config) { 111 return !(isConfigForWepNetwork(config) || isConfigForPskNetwork(config) 112 || isConfigForEapNetwork(config)); 113 } 114 115 /** 116 * Compare existing and new WifiConfiguration objects after a network update and return if 117 * IP parameters have changed or not. 118 * 119 * @param existingConfig Existing WifiConfiguration object corresponding to the network. 120 * @param newConfig New WifiConfiguration object corresponding to the network. 121 * @return true if IP parameters have changed, false otherwise. 122 */ 123 public static boolean hasIpChanged(WifiConfiguration existingConfig, 124 WifiConfiguration newConfig) { 125 if (existingConfig.getIpAssignment() != newConfig.getIpAssignment()) { 126 return true; 127 } 128 if (newConfig.getIpAssignment() == IpConfiguration.IpAssignment.STATIC) { 129 return !Objects.equals(existingConfig.getStaticIpConfiguration(), 130 newConfig.getStaticIpConfiguration()); 131 } 132 return false; 133 } 134 135 /** 136 * Compare existing and new WifiConfiguration objects after a network update and return if 137 * proxy parameters have changed or not. 138 * 139 * @param existingConfig Existing WifiConfiguration object corresponding to the network. 140 * @param newConfig New WifiConfiguration object corresponding to the network. 141 * @return true if proxy parameters have changed, false if no existing config and proxy settings 142 * are NONE, false otherwise. 143 */ 144 public static boolean hasProxyChanged(WifiConfiguration existingConfig, 145 WifiConfiguration newConfig) { 146 if (existingConfig == null) { 147 return newConfig.getProxySettings() != IpConfiguration.ProxySettings.NONE; 148 } 149 if (newConfig.getProxySettings() != existingConfig.getProxySettings()) { 150 return true; 151 } 152 return !Objects.equals(existingConfig.getHttpProxy(), newConfig.getHttpProxy()); 153 } 154 155 /** 156 * Compare existing and new WifiEnterpriseConfig objects after a network update and return if 157 * credential parameters have changed or not. 158 * 159 * @param existingEnterpriseConfig Existing WifiConfiguration object corresponding to the 160 * network. 161 * @param newEnterpriseConfig New WifiConfiguration object corresponding to the network. 162 * @return true if credentials have changed, false otherwise. 163 */ 164 @VisibleForTesting 165 public static boolean hasEnterpriseConfigChanged(WifiEnterpriseConfig existingEnterpriseConfig, 166 WifiEnterpriseConfig newEnterpriseConfig) { 167 if (existingEnterpriseConfig != null && newEnterpriseConfig != null) { 168 if (existingEnterpriseConfig.getEapMethod() != newEnterpriseConfig.getEapMethod()) { 169 return true; 170 } 171 if (existingEnterpriseConfig.getPhase2Method() 172 != newEnterpriseConfig.getPhase2Method()) { 173 return true; 174 } 175 X509Certificate[] existingCaCerts = existingEnterpriseConfig.getCaCertificates(); 176 X509Certificate[] newCaCerts = newEnterpriseConfig.getCaCertificates(); 177 if (!Arrays.equals(existingCaCerts, newCaCerts)) { 178 return true; 179 } 180 } else { 181 // One of the configs may have an enterpriseConfig 182 if (existingEnterpriseConfig != null || newEnterpriseConfig != null) { 183 return true; 184 } 185 } 186 return false; 187 } 188 189 /** 190 * Compare existing and new WifiConfiguration objects after a network update and return if 191 * credential parameters have changed or not. 192 * 193 * @param existingConfig Existing WifiConfiguration object corresponding to the network. 194 * @param newConfig New WifiConfiguration object corresponding to the network. 195 * @return true if credentials have changed, false otherwise. 196 */ 197 public static boolean hasCredentialChanged(WifiConfiguration existingConfig, 198 WifiConfiguration newConfig) { 199 if (!Objects.equals(existingConfig.allowedKeyManagement, 200 newConfig.allowedKeyManagement)) { 201 return true; 202 } 203 if (!Objects.equals(existingConfig.allowedProtocols, newConfig.allowedProtocols)) { 204 return true; 205 } 206 if (!Objects.equals(existingConfig.allowedAuthAlgorithms, 207 newConfig.allowedAuthAlgorithms)) { 208 return true; 209 } 210 if (!Objects.equals(existingConfig.allowedPairwiseCiphers, 211 newConfig.allowedPairwiseCiphers)) { 212 return true; 213 } 214 if (!Objects.equals(existingConfig.allowedGroupCiphers, 215 newConfig.allowedGroupCiphers)) { 216 return true; 217 } 218 if (!Objects.equals(existingConfig.preSharedKey, newConfig.preSharedKey)) { 219 return true; 220 } 221 if (!Arrays.equals(existingConfig.wepKeys, newConfig.wepKeys)) { 222 return true; 223 } 224 if (existingConfig.wepTxKeyIndex != newConfig.wepTxKeyIndex) { 225 return true; 226 } 227 if (existingConfig.hiddenSSID != newConfig.hiddenSSID) { 228 return true; 229 } 230 if (hasEnterpriseConfigChanged(existingConfig.enterpriseConfig, 231 newConfig.enterpriseConfig)) { 232 return true; 233 } 234 return false; 235 } 236 237 /** 238 * Create a PnoNetwork object from the provided WifiConfiguration. 239 * 240 * @param config Configuration corresponding to the network. 241 * @param newPriority New priority to be assigned to the network. 242 * @return PnoNetwork object corresponding to the network. 243 */ 244 public static WifiScanner.PnoSettings.PnoNetwork createPnoNetwork( 245 WifiConfiguration config, int newPriority) { 246 WifiScanner.PnoSettings.PnoNetwork pnoNetwork = 247 new WifiScanner.PnoSettings.PnoNetwork(config.SSID); 248 if (config.hiddenSSID) { 249 pnoNetwork.flags |= WifiScanner.PnoSettings.PnoNetwork.FLAG_DIRECTED_SCAN; 250 } 251 pnoNetwork.flags |= WifiScanner.PnoSettings.PnoNetwork.FLAG_A_BAND; 252 pnoNetwork.flags |= WifiScanner.PnoSettings.PnoNetwork.FLAG_G_BAND; 253 if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) { 254 pnoNetwork.authBitField |= WifiScanner.PnoSettings.PnoNetwork.AUTH_CODE_PSK; 255 } else if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP) 256 || config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X)) { 257 pnoNetwork.authBitField |= WifiScanner.PnoSettings.PnoNetwork.AUTH_CODE_EAPOL; 258 } else { 259 pnoNetwork.authBitField |= WifiScanner.PnoSettings.PnoNetwork.AUTH_CODE_OPEN; 260 } 261 return pnoNetwork; 262 } 263 264 /** 265 * General WifiConfiguration list sorting algorithm: 266 * 1, Place the fully enabled networks first. 267 * 2. Next place all the temporarily disabled networks. 268 * 3. Place the permanently disabled networks last (Permanently disabled networks are removed 269 * before WifiConfigManager uses this comparator today!). 270 * 271 * Among the networks with the same status, sort them in the order determined by the return of 272 * {@link #compareNetworksWithSameStatus(WifiConfiguration, WifiConfiguration)} method 273 * implementation. 274 */ 275 public abstract static class WifiConfigurationComparator implements 276 Comparator<WifiConfiguration> { 277 private static final int ENABLED_NETWORK_SCORE = 3; 278 private static final int TEMPORARY_DISABLED_NETWORK_SCORE = 2; 279 private static final int PERMANENTLY_DISABLED_NETWORK_SCORE = 1; 280 281 @Override 282 public int compare(WifiConfiguration a, WifiConfiguration b) { 283 int configAScore = getNetworkStatusScore(a); 284 int configBScore = getNetworkStatusScore(b); 285 if (configAScore == configBScore) { 286 return compareNetworksWithSameStatus(a, b); 287 } else { 288 return Integer.compare(configBScore, configAScore); 289 } 290 } 291 292 // This needs to be implemented by the connected/disconnected PNO list comparator. 293 abstract int compareNetworksWithSameStatus(WifiConfiguration a, WifiConfiguration b); 294 295 /** 296 * Returns an integer representing a score for each configuration. The scores are assigned 297 * based on the status of the configuration. The scores are assigned according to the order: 298 * Fully enabled network > Temporarily disabled network > Permanently disabled network. 299 */ 300 private int getNetworkStatusScore(WifiConfiguration config) { 301 if (config.getNetworkSelectionStatus().isNetworkEnabled()) { 302 return ENABLED_NETWORK_SCORE; 303 } else if (config.getNetworkSelectionStatus().isNetworkTemporaryDisabled()) { 304 return TEMPORARY_DISABLED_NETWORK_SCORE; 305 } else { 306 return PERMANENTLY_DISABLED_NETWORK_SCORE; 307 } 308 } 309 } 310} 311