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