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.annotation.NonNull; 20 import android.net.wifi.ScanResult; 21 import android.net.wifi.WifiConfiguration; 22 import android.telephony.TelephonyManager; 23 import android.util.LocalLog; 24 import android.util.Pair; 25 26 import com.android.server.wifi.hotspot2.PasspointNetworkNominateHelper; 27 import com.android.server.wifi.util.WifiPermissionsUtil; 28 29 import java.util.List; 30 31 /** 32 * This class is the WifiNetworkSelector.NetworkNominator implementation for 33 * saved networks. 34 */ 35 public class SavedNetworkNominator implements WifiNetworkSelector.NetworkNominator { 36 private static final String NAME = "SavedNetworkNominator"; 37 private final WifiConfigManager mWifiConfigManager; 38 private final LocalLog mLocalLog; 39 private final WifiCarrierInfoManager mWifiCarrierInfoManager; 40 private final PasspointNetworkNominateHelper mPasspointNetworkNominateHelper; 41 private final WifiPermissionsUtil mWifiPermissionsUtil; 42 private final WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager; 43 SavedNetworkNominator(WifiConfigManager configManager, PasspointNetworkNominateHelper nominateHelper, LocalLog localLog, WifiCarrierInfoManager wifiCarrierInfoManager, WifiPermissionsUtil wifiPermissionsUtil, WifiNetworkSuggestionsManager wifiNetworkSuggestionsManager)44 SavedNetworkNominator(WifiConfigManager configManager, 45 PasspointNetworkNominateHelper nominateHelper, LocalLog localLog, 46 WifiCarrierInfoManager wifiCarrierInfoManager, 47 WifiPermissionsUtil wifiPermissionsUtil, 48 WifiNetworkSuggestionsManager wifiNetworkSuggestionsManager) { 49 mWifiConfigManager = configManager; 50 mPasspointNetworkNominateHelper = nominateHelper; 51 mLocalLog = localLog; 52 mWifiCarrierInfoManager = wifiCarrierInfoManager; 53 mWifiPermissionsUtil = wifiPermissionsUtil; 54 mWifiNetworkSuggestionsManager = wifiNetworkSuggestionsManager; 55 } 56 localLog(String log)57 private void localLog(String log) { 58 mLocalLog.log(log); 59 } 60 61 /** 62 * Get the Nominator type. 63 */ 64 @Override getId()65 public @NominatorId int getId() { 66 return NOMINATOR_ID_SAVED; 67 } 68 69 /** 70 * Get the Nominator name. 71 */ 72 @Override getName()73 public String getName() { 74 return NAME; 75 } 76 77 /** 78 * Update the Nominator. 79 */ 80 @Override update(List<ScanDetail> scanDetails)81 public void update(List<ScanDetail> scanDetails) { 82 // Update the matching profiles into WifiConfigManager, help displaying Passpoint networks 83 // in Wifi Picker 84 mPasspointNetworkNominateHelper.getPasspointNetworkCandidates(scanDetails, false); 85 } 86 87 /** 88 * Run through all scanDetails and nominate all connectable network as candidates. 89 * 90 */ 91 @Override nominateNetworks(List<ScanDetail> scanDetails, boolean untrustedNetworkAllowed , boolean oemPaidNetworkAllowed , boolean oemPrivateNetworkAllowed , @NonNull OnConnectableListener onConnectableListener)92 public void nominateNetworks(List<ScanDetail> scanDetails, 93 boolean untrustedNetworkAllowed /* unused */, 94 boolean oemPaidNetworkAllowed /* unused */, 95 boolean oemPrivateNetworkAllowed /* unused */, 96 @NonNull OnConnectableListener onConnectableListener) { 97 findMatchedSavedNetworks(scanDetails, onConnectableListener); 98 findMatchedPasspointNetworks(scanDetails, onConnectableListener); 99 } 100 findMatchedSavedNetworks(List<ScanDetail> scanDetails, OnConnectableListener onConnectableListener)101 private void findMatchedSavedNetworks(List<ScanDetail> scanDetails, 102 OnConnectableListener onConnectableListener) { 103 for (ScanDetail scanDetail : scanDetails) { 104 ScanResult scanResult = scanDetail.getScanResult(); 105 106 // One ScanResult can be associated with more than one network, hence we calculate all 107 // the scores and use the highest one as the ScanResult's score. 108 WifiConfiguration network = 109 mWifiConfigManager.getSavedNetworkForScanDetailAndCache(scanDetail); 110 111 if (network == null) { 112 continue; 113 } 114 115 /** 116 * Ignore Passpoint and Ephemeral networks. They are configured networks, 117 * but without being persisted to the storage. They are nominated by 118 * {@link PasspointNetworkNominator} and {@link ScoredNetworkNominator} 119 * respectively. 120 */ 121 if (network.isPasspoint() || network.isEphemeral()) { 122 continue; 123 } 124 125 // Ignore networks that the user has disallowed auto-join for. 126 if (!network.allowAutojoin) { 127 localLog("Ignoring auto join disabled SSID: " + network.SSID); 128 continue; 129 } 130 131 WifiConfiguration.NetworkSelectionStatus status = 132 network.getNetworkSelectionStatus(); 133 status.setSeenInLastQualifiedNetworkSelection(true); 134 135 if (mWifiConfigManager.isNonCarrierMergedNetworkTemporarilyDisabled(network)) { 136 localLog("Ignoring non-carrier-merged SSID: " + network.SSID); 137 continue; 138 } 139 if (mWifiConfigManager.isNetworkTemporarilyDisabledByUser(network.SSID)) { 140 localLog("Ignoring user disabled SSID: " + network.SSID); 141 continue; 142 } 143 144 if (!status.isNetworkEnabled()) { 145 localLog("Ignoring network selection disabled SSID: " + network.SSID); 146 continue; 147 } 148 if (network.BSSID != null && !network.BSSID.equals("any") 149 && !network.BSSID.equals(scanResult.BSSID)) { 150 // App has specified the only BSSID to connect for this 151 // configuration. So only the matching ScanResult can be a candidate. 152 localLog("Network " + WifiNetworkSelector.toNetworkString(network) 153 + " has specified BSSID " + network.BSSID + ". Skip " 154 + scanResult.BSSID); 155 continue; 156 } 157 if (isNetworkSimBasedCredential(network) && !isSimBasedNetworkAbleToAutoJoin(network)) { 158 localLog("Ignoring SIM auto join disabled SSID: " + network.SSID); 159 continue; 160 } 161 162 // If the network is marked to use external scores, or is an open network with 163 // curate saved open networks enabled, do not consider it for network selection. 164 if (network.useExternalScores) { 165 localLog("Network " + WifiNetworkSelector.toNetworkString(network) 166 + " has external score."); 167 continue; 168 } 169 170 if (mWifiNetworkSuggestionsManager 171 .shouldBeIgnoredBySecureSuggestionFromSameCarrier(network, 172 scanDetails)) { 173 localLog("Open Network " + WifiNetworkSelector.toNetworkString(network) 174 + " has a secure network suggestion from same carrier."); 175 continue; 176 } 177 178 onConnectableListener.onConnectable(scanDetail, 179 mWifiConfigManager.getConfiguredNetwork(network.networkId)); 180 } 181 } 182 findMatchedPasspointNetworks(List<ScanDetail> scanDetails, OnConnectableListener onConnectableListener)183 private void findMatchedPasspointNetworks(List<ScanDetail> scanDetails, 184 OnConnectableListener onConnectableListener) { 185 List<Pair<ScanDetail, WifiConfiguration>> candidates = 186 mPasspointNetworkNominateHelper.getPasspointNetworkCandidates(scanDetails, false); 187 for (Pair<ScanDetail, WifiConfiguration> candidate : candidates) { 188 WifiConfiguration config = candidate.second; 189 if (!config.allowAutojoin) { 190 continue; 191 } 192 if (isNetworkSimBasedCredential(config) && !isSimBasedNetworkAbleToAutoJoin(config)) { 193 continue; 194 } 195 onConnectableListener.onConnectable(candidate.first, config); 196 } 197 } 198 isSimBasedNetworkAbleToAutoJoin(WifiConfiguration network)199 private boolean isSimBasedNetworkAbleToAutoJoin(WifiConfiguration network) { 200 int carrierId = network.carrierId == TelephonyManager.UNKNOWN_CARRIER_ID 201 ? mWifiCarrierInfoManager.getDefaultDataSimCarrierId() : network.carrierId; 202 int subId = mWifiCarrierInfoManager.getMatchingSubId(carrierId); 203 // Ignore security type is EAP SIM/AKA/AKA' when SIM is not present. 204 if (!mWifiCarrierInfoManager.isSimReady(subId)) { 205 localLog("No SIM card is good for Network " 206 + WifiNetworkSelector.toNetworkString(network)); 207 return false; 208 } 209 // Ignore IMSI info not available or protection exemption pending network. 210 if (mWifiCarrierInfoManager.requiresImsiEncryption(subId)) { 211 if (!mWifiCarrierInfoManager.isImsiEncryptionInfoAvailable(subId)) { 212 localLog("Imsi protection required but not available for Network " 213 + WifiNetworkSelector.toNetworkString(network)); 214 return false; 215 } 216 } else if (isImsiProtectionApprovalNeeded(network.creatorUid, carrierId)) { 217 localLog("Imsi protection exemption needed for Network " 218 + WifiNetworkSelector.toNetworkString(network)); 219 return false; 220 } 221 // Ignore metered network with non-data Sim. 222 if (WifiConfiguration.isMetered(network, null) 223 && mWifiCarrierInfoManager.isCarrierNetworkFromNonDefaultDataSim(network)) { 224 localLog("No default SIM is used for metered Network: " 225 + WifiNetworkSelector.toNetworkString(network)); 226 return false; 227 } 228 return true; 229 } 230 isNetworkSimBasedCredential(WifiConfiguration network)231 private boolean isNetworkSimBasedCredential(WifiConfiguration network) { 232 return network != null && network.enterpriseConfig != null 233 && network.enterpriseConfig.isAuthenticationSimBased(); 234 } 235 isImsiProtectionApprovalNeeded(int creatorUid, int carrierId)236 private boolean isImsiProtectionApprovalNeeded(int creatorUid, int carrierId) { 237 // User saved network got exemption. 238 if (mWifiPermissionsUtil.checkNetworkSettingsPermission(creatorUid) 239 || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(creatorUid)) { 240 return false; 241 } 242 if (mWifiCarrierInfoManager.hasUserApprovedImsiPrivacyExemptionForCarrier(carrierId)) { 243 return false; 244 } 245 mWifiCarrierInfoManager.sendImsiProtectionExemptionNotificationIfRequired(carrierId); 246 return true; 247 } 248 } 249