PasspointNetworkEvaluator.java revision 17c2a7b30e5680b11fc0073ce322ee7bc14ef2c5
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.hotspot2; 18 19import android.net.wifi.WifiConfiguration; 20import android.os.Process; 21import android.text.TextUtils; 22import android.util.LocalLog; 23import android.util.Pair; 24 25import com.android.server.wifi.NetworkUpdateResult; 26import com.android.server.wifi.ScanDetail; 27import com.android.server.wifi.WifiConfigManager; 28import com.android.server.wifi.WifiNetworkSelector; 29import com.android.server.wifi.util.ScanResultUtil; 30 31import java.util.ArrayList; 32import java.util.List; 33 34/** 35 * This class is the WifiNetworkSelector.NetworkEvaluator implementation for 36 * Passpoint networks. 37 */ 38public class PasspointNetworkEvaluator implements WifiNetworkSelector.NetworkEvaluator { 39 private static final String NAME = "PasspointNetworkEvaluator"; 40 41 private final PasspointManager mPasspointManager; 42 private final WifiConfigManager mWifiConfigManager; 43 private final LocalLog mLocalLog; 44 45 public PasspointNetworkEvaluator(PasspointManager passpointManager, 46 WifiConfigManager wifiConfigManager, LocalLog localLog) { 47 mPasspointManager = passpointManager; 48 mWifiConfigManager = wifiConfigManager; 49 mLocalLog = localLog; 50 } 51 52 @Override 53 public String getName() { 54 return NAME; 55 } 56 57 @Override 58 public void update(List<ScanDetail> scanDetails) {} 59 60 @Override 61 public WifiConfiguration evaluateNetworks(List<ScanDetail> scanDetails, 62 WifiConfiguration currentNetwork, String currentBssid, 63 boolean connected, boolean untrustedNetworkAllowed, 64 List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks) { 65 // Sweep the ANQP cache to remove any expired ANQP entries. 66 mPasspointManager.sweepCache(); 67 68 // Go through each ScanDetail and find the best provider for each ScanDetail. 69 List<Pair<ScanDetail, Pair<PasspointProvider, PasspointMatch>>> providerList = 70 new ArrayList<>(); 71 for (ScanDetail scanDetail : scanDetails) { 72 // Skip non-Passpoint APs. 73 if (!scanDetail.getNetworkDetail().isInterworking()) { 74 continue; 75 } 76 77 // Find the best provider for this ScanDetail. 78 Pair<PasspointProvider, PasspointMatch> bestProvider = 79 mPasspointManager.matchProvider(scanDetail.getScanResult()); 80 if (bestProvider != null) { 81 providerList.add(Pair.create(scanDetail, bestProvider)); 82 } 83 } 84 85 // Done if no matching provider is found. 86 if (providerList.isEmpty()) { 87 localLog("No suitable Passpoint network found"); 88 return null; 89 } 90 91 // Find the best Passpoint network among all matches. 92 Pair<PasspointProvider, ScanDetail> bestNetwork = findBestNetwork(providerList, 93 currentNetwork == null ? null : currentNetwork.SSID); 94 95 // Return the configuration for the current connected network if it is the best network. 96 if (currentNetwork != null && TextUtils.equals(currentNetwork.SSID, 97 ScanResultUtil.createQuotedSSID(bestNetwork.second.getSSID()))) { 98 localLog("Staying with current Passpoint network " + currentNetwork.SSID); 99 connectableNetworks.add(Pair.create(bestNetwork.second, currentNetwork)); 100 return currentNetwork; 101 } 102 103 WifiConfiguration config = 104 createWifiConfigForProvider(bestNetwork.first, bestNetwork.second); 105 connectableNetworks.add(Pair.create(bestNetwork.second, config)); 106 localLog("Passpoint network to connect to: " + config.SSID); 107 return config; 108 } 109 110 /** 111 * Create and return a WifiConfiguration for the given ScanDetail and PasspointProvider. 112 * The newly created WifiConfiguration will also be added to WifiConfigManager. 113 * 114 * @param provider The provider to create WifiConfiguration from 115 * @param scanDetail The ScanDetail to create WifiConfiguration from 116 * @return {@link WifiConfiguration} 117 */ 118 private WifiConfiguration createWifiConfigForProvider(PasspointProvider provider, 119 ScanDetail scanDetail) { 120 WifiConfiguration config = provider.getWifiConfig(); 121 config.SSID = ScanResultUtil.createQuotedSSID(scanDetail.getSSID()); 122 123 // Add the newly created WifiConfiguration to WifiConfigManager. 124 NetworkUpdateResult result = 125 mWifiConfigManager.addOrUpdateNetwork(config, Process.WIFI_UID); 126 if (!result.isSuccess()) { 127 localLog("Failed to add passpoint network"); 128 return null; 129 } 130 mWifiConfigManager.enableNetwork(result.getNetworkId(), false, Process.WIFI_UID); 131 mWifiConfigManager.setNetworkCandidateScanResult(result.getNetworkId(), 132 scanDetail.getScanResult(), 0); 133 mWifiConfigManager.updateScanDetailForNetwork(result.getNetworkId(), scanDetail); 134 return mWifiConfigManager.getConfiguredNetwork(result.getNetworkId()); 135 } 136 137 /** 138 * Given a list of Passpoint networks (with both provider and scan info), find and return 139 * the one with highest score. The score is calculated using 140 * {@link PasspointNetworkScore#calculateScore}. 141 * 142 * @param networkList List of Passpoint networks 143 * @param currentNetworkSsid The SSID of the currently connected network, null if not connected 144 * @return {@link PasspointProvider} and {@link ScanDetail} associated with the network 145 */ 146 private Pair<PasspointProvider, ScanDetail> findBestNetwork( 147 List<Pair<ScanDetail, Pair<PasspointProvider, PasspointMatch>>> networkList, 148 String currentNetworkSsid) { 149 ScanDetail bestScanDetail = null; 150 PasspointProvider bestProvider = null; 151 int bestScore = Integer.MIN_VALUE; 152 for (Pair<ScanDetail, Pair<PasspointProvider, PasspointMatch>> candidate : networkList) { 153 ScanDetail scanDetail = candidate.first; 154 PasspointProvider provider = candidate.second.first; 155 PasspointMatch match = candidate.second.second; 156 157 boolean isActiveNetwork = TextUtils.equals(currentNetworkSsid, 158 ScanResultUtil.createQuotedSSID(scanDetail.getSSID())); 159 int score = PasspointNetworkScore.calculateScore(match == PasspointMatch.HomeProvider, 160 scanDetail, mPasspointManager.getANQPElements(scanDetail.getScanResult()), 161 isActiveNetwork); 162 163 if (score > bestScore) { 164 bestScanDetail = scanDetail; 165 bestProvider = provider; 166 bestScore = score; 167 } 168 } 169 localLog("Best Passpoint network " + bestScanDetail.getSSID() + " provided by " 170 + bestProvider.getConfig().getHomeSp().getFqdn()); 171 return Pair.create(bestProvider, bestScanDetail); 172 } 173 174 private void localLog(String log) { 175 mLocalLog.log(log); 176 } 177} 178