PasspointNetworkEvaluator.java revision b54f07e01c9daef8883c85e09f61436f2c06cc72
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 return null; 88 } 89 90 // Find the best Passpoint network among all matches. 91 Pair<PasspointProvider, ScanDetail> bestNetwork = findBestNetwork(providerList, 92 currentNetwork == null ? null : currentNetwork.SSID); 93 94 // Return the configuration for the current connected network if it is the best network. 95 if (currentNetwork != null && TextUtils.equals(currentNetwork.SSID, 96 ScanResultUtil.createQuotedSSID(bestNetwork.second.getSSID()))) { 97 connectableNetworks.add(Pair.create(bestNetwork.second, currentNetwork)); 98 return currentNetwork; 99 } 100 101 WifiConfiguration config = 102 createWifiConfigForProvider(bestNetwork.first, bestNetwork.second); 103 connectableNetworks.add(Pair.create(bestNetwork.second, config)); 104 return config; 105 } 106 107 /** 108 * Create and return a WifiConfiguration for the given ScanDetail and PasspointProvider. 109 * The newly created WifiConfiguration will also be added to WifiConfigManager. 110 * 111 * @param provider The provider to create WifiConfiguration from 112 * @param scanDetail The ScanDetail to create WifiConfiguration from 113 * @return {@link WifiConfiguration} 114 */ 115 private WifiConfiguration createWifiConfigForProvider(PasspointProvider provider, 116 ScanDetail scanDetail) { 117 WifiConfiguration config = provider.getWifiConfig(); 118 config.SSID = ScanResultUtil.createQuotedSSID(scanDetail.getSSID()); 119 120 // Add the newly created WifiConfiguration to WifiConfigManager. 121 NetworkUpdateResult result = 122 mWifiConfigManager.addOrUpdateNetwork(config, Process.WIFI_UID); 123 if (!result.isSuccess()) { 124 localLog("Failed to add passpoint network"); 125 return null; 126 } 127 mWifiConfigManager.enableNetwork(result.getNetworkId(), false, Process.WIFI_UID); 128 mWifiConfigManager.setNetworkCandidateScanResult(result.getNetworkId(), 129 scanDetail.getScanResult(), 0); 130 mWifiConfigManager.updateScanDetailForNetwork(result.getNetworkId(), scanDetail); 131 return mWifiConfigManager.getConfiguredNetwork(result.getNetworkId()); 132 } 133 134 /** 135 * Given a list of Passpoint networks (with both provider and scan info), find and return 136 * the one with highest score. The score is calculated using 137 * {@link PasspointNetworkScore#calculateScore}. 138 * 139 * @param networkList List of Passpoint networks 140 * @param currentNetworkSsid The SSID of the currently connected network, null if not connected 141 * @return {@link PasspointProvider} and {@link ScanDetail} associated with the network 142 */ 143 private Pair<PasspointProvider, ScanDetail> findBestNetwork( 144 List<Pair<ScanDetail, Pair<PasspointProvider, PasspointMatch>>> networkList, 145 String currentNetworkSsid) { 146 ScanDetail bestScanDetail = null; 147 PasspointProvider bestProvider = null; 148 int bestScore = Integer.MIN_VALUE; 149 for (Pair<ScanDetail, Pair<PasspointProvider, PasspointMatch>> candidate : networkList) { 150 ScanDetail scanDetail = candidate.first; 151 PasspointProvider provider = candidate.second.first; 152 PasspointMatch match = candidate.second.second; 153 154 boolean isActiveNetwork = TextUtils.equals(currentNetworkSsid, 155 ScanResultUtil.createQuotedSSID(scanDetail.getSSID())); 156 int score = PasspointNetworkScore.calculateScore(match == PasspointMatch.HomeProvider, 157 scanDetail, mPasspointManager.getANQPElements(scanDetail.getScanResult()), 158 isActiveNetwork); 159 160 if (score > bestScore) { 161 bestScanDetail = scanDetail; 162 bestProvider = provider; 163 bestScore = score; 164 } 165 } 166 return Pair.create(bestProvider, bestScanDetail); 167 } 168 169 private void localLog(String log) { 170 if (mLocalLog != null) { 171 mLocalLog.log(log); 172 } 173 } 174} 175