150f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu/*
250f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu * Copyright (C) 2016 The Android Open Source Project
350f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu *
450f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu * Licensed under the Apache License, Version 2.0 (the "License");
550f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu * you may not use this file except in compliance with the License.
650f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu * You may obtain a copy of the License at
750f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu *
850f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu *      http://www.apache.org/licenses/LICENSE-2.0
950f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu *
1050f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu * Unless required by applicable law or agreed to in writing, software
1150f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu * distributed under the License is distributed on an "AS IS" BASIS,
1250f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1350f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu * See the License for the specific language governing permissions and
1450f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu * limitations under the License.
1550f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu */
1650f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
1750f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiupackage com.android.server.wifi.hotspot2;
1850f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
1950f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiuimport android.net.wifi.WifiConfiguration;
2050f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiuimport android.os.Process;
2150f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiuimport android.text.TextUtils;
2250f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiuimport android.util.LocalLog;
2350f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiuimport android.util.Pair;
2450f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
2550f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiuimport com.android.server.wifi.NetworkUpdateResult;
2650f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiuimport com.android.server.wifi.ScanDetail;
2750f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiuimport com.android.server.wifi.WifiConfigManager;
2850f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiuimport com.android.server.wifi.WifiNetworkSelector;
2950f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiuimport com.android.server.wifi.util.ScanResultUtil;
3050f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
3150f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiuimport java.util.ArrayList;
3250f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiuimport java.util.List;
3350f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
3450f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu/**
3550f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu * This class is the WifiNetworkSelector.NetworkEvaluator implementation for
3650f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu * Passpoint networks.
3750f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu */
3850f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiupublic class PasspointNetworkEvaluator implements WifiNetworkSelector.NetworkEvaluator {
3950f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    private static final String NAME = "PasspointNetworkEvaluator";
4050f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
4150f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    private final PasspointManager mPasspointManager;
4250f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    private final WifiConfigManager mWifiConfigManager;
4350f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    private final LocalLog mLocalLog;
4450f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
45d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu    /**
46d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu     * Contained information for a Passpoint network candidate.
47d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu     */
48d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu    private class PasspointNetworkCandidate {
49d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        PasspointNetworkCandidate(PasspointProvider provider, PasspointMatch matchStatus,
50d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu                ScanDetail scanDetail) {
51d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu            mProvider = provider;
52d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu            mMatchStatus = matchStatus;
53d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu            mScanDetail = scanDetail;
54d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        }
55d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        PasspointProvider mProvider;
56d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        PasspointMatch mMatchStatus;
57d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        ScanDetail mScanDetail;
58d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu    }
59d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu
6050f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    public PasspointNetworkEvaluator(PasspointManager passpointManager,
6150f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu            WifiConfigManager wifiConfigManager, LocalLog localLog) {
6250f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        mPasspointManager = passpointManager;
6350f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        mWifiConfigManager = wifiConfigManager;
6450f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        mLocalLog = localLog;
6550f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    }
6650f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
6750f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    @Override
6850f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    public String getName() {
6950f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        return NAME;
7050f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    }
7150f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
7250f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    @Override
7350f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    public void update(List<ScanDetail> scanDetails) {}
7450f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
7550f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    @Override
7650f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    public WifiConfiguration evaluateNetworks(List<ScanDetail> scanDetails,
7750f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu                    WifiConfiguration currentNetwork, String currentBssid,
7850f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu                    boolean connected, boolean untrustedNetworkAllowed,
7950f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu                    List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks) {
80ec28f863c5e46c0a75e8bdb92283304b875ee0f2Peter Qiu        // Sweep the ANQP cache to remove any expired ANQP entries.
81ec28f863c5e46c0a75e8bdb92283304b875ee0f2Peter Qiu        mPasspointManager.sweepCache();
82ec28f863c5e46c0a75e8bdb92283304b875ee0f2Peter Qiu
8350f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        // Go through each ScanDetail and find the best provider for each ScanDetail.
84d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        List<PasspointNetworkCandidate> candidateList = new ArrayList<>();
8550f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        for (ScanDetail scanDetail : scanDetails) {
8650f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu            // Skip non-Passpoint APs.
8750f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu            if (!scanDetail.getNetworkDetail().isInterworking()) {
8850f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu                continue;
8950f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu            }
9050f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
9150f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu            // Find the best provider for this ScanDetail.
9250f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu            Pair<PasspointProvider, PasspointMatch> bestProvider =
93b54f07e01c9daef8883c85e09f61436f2c06cc72Peter Qiu                    mPasspointManager.matchProvider(scanDetail.getScanResult());
9450f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu            if (bestProvider != null) {
95d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu                candidateList.add(new PasspointNetworkCandidate(
96d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu                        bestProvider.first, bestProvider.second, scanDetail));
9750f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu            }
9850f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        }
9950f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
100d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        // Done if no candidate is found.
101d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        if (candidateList.isEmpty()) {
10250bc1e851d073d4a986f5b32072f94bbaba86a95Peter Qiu            localLog("No suitable Passpoint network found");
10350f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu            return null;
10450f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        }
10550f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
106d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        // Find the best Passpoint network among all candidates.
107d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        PasspointNetworkCandidate bestNetwork =
108d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu                findBestNetwork(candidateList, currentNetwork == null ? null : currentNetwork.SSID);
10950f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
11050f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        // Return the configuration for the current connected network if it is the best network.
11150f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        if (currentNetwork != null && TextUtils.equals(currentNetwork.SSID,
112d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu                ScanResultUtil.createQuotedSSID(bestNetwork.mScanDetail.getSSID()))) {
11350bc1e851d073d4a986f5b32072f94bbaba86a95Peter Qiu            localLog("Staying with current Passpoint network " + currentNetwork.SSID);
114d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu            connectableNetworks.add(Pair.create(bestNetwork.mScanDetail, currentNetwork));
11550f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu            return currentNetwork;
11650f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        }
11750f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
118d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        WifiConfiguration config = createWifiConfigForProvider(bestNetwork);
119d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        connectableNetworks.add(Pair.create(bestNetwork.mScanDetail, config));
12050bc1e851d073d4a986f5b32072f94bbaba86a95Peter Qiu        localLog("Passpoint network to connect to: " + config.SSID);
12150f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        return config;
12250f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    }
12350f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
12450f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    /**
12550f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu     * Create and return a WifiConfiguration for the given ScanDetail and PasspointProvider.
12650f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu     * The newly created WifiConfiguration will also be added to WifiConfigManager.
12750f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu     *
128d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu     * @param networkInfo Contained information for the Passpoint network to connect to
12950f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu     * @return {@link WifiConfiguration}
13050f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu     */
131d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu    private WifiConfiguration createWifiConfigForProvider(PasspointNetworkCandidate networkInfo) {
132d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        WifiConfiguration config = networkInfo.mProvider.getWifiConfig();
133d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        config.SSID = ScanResultUtil.createQuotedSSID(networkInfo.mScanDetail.getSSID());
134d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        if (networkInfo.mMatchStatus == PasspointMatch.HomeProvider) {
135d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu            config.isHomeProviderNetwork = true;
136d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        }
13750f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
13850f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        // Add the newly created WifiConfiguration to WifiConfigManager.
13950f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        NetworkUpdateResult result =
14050f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu                mWifiConfigManager.addOrUpdateNetwork(config, Process.WIFI_UID);
14150f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        if (!result.isSuccess()) {
14250f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu            localLog("Failed to add passpoint network");
14350f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu            return null;
14450f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        }
14567a4541372684c5d0a3f834f8be76bd8d29ca7acPeter Qiu        mWifiConfigManager.enableNetwork(result.getNetworkId(), false, Process.WIFI_UID);
14650f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        mWifiConfigManager.setNetworkCandidateScanResult(result.getNetworkId(),
147d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu                networkInfo.mScanDetail.getScanResult(), 0);
148d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        mWifiConfigManager.updateScanDetailForNetwork(
149d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu                result.getNetworkId(), networkInfo.mScanDetail);
15050f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        return mWifiConfigManager.getConfiguredNetwork(result.getNetworkId());
15150f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    }
15250f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
15350f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    /**
15450f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu     * Given a list of Passpoint networks (with both provider and scan info), find and return
15550f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu     * the one with highest score.  The score is calculated using
15650f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu     * {@link PasspointNetworkScore#calculateScore}.
15750f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu     *
15850f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu     * @param networkList List of Passpoint networks
15950f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu     * @param currentNetworkSsid The SSID of the currently connected network, null if not connected
160d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu     * @return {@link PasspointNetworkCandidate}
16150f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu     */
162d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu    private PasspointNetworkCandidate findBestNetwork(
163d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu            List<PasspointNetworkCandidate> networkList, String currentNetworkSsid) {
164d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        PasspointNetworkCandidate bestCandidate = null;
16550f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        int bestScore = Integer.MIN_VALUE;
166d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        for (PasspointNetworkCandidate candidate : networkList) {
167d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu            ScanDetail scanDetail = candidate.mScanDetail;
168d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu            PasspointMatch match = candidate.mMatchStatus;
16950f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
17050f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu            boolean isActiveNetwork = TextUtils.equals(currentNetworkSsid,
17150f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu                    ScanResultUtil.createQuotedSSID(scanDetail.getSSID()));
17250f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu            int score = PasspointNetworkScore.calculateScore(match == PasspointMatch.HomeProvider,
173ec28f863c5e46c0a75e8bdb92283304b875ee0f2Peter Qiu                    scanDetail, mPasspointManager.getANQPElements(scanDetail.getScanResult()),
174ec28f863c5e46c0a75e8bdb92283304b875ee0f2Peter Qiu                    isActiveNetwork);
17550f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
17650f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu            if (score > bestScore) {
177d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu                bestCandidate = candidate;
17850f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu                bestScore = score;
17950f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu            }
18050f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu        }
181d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        localLog("Best Passpoint network " + bestCandidate.mScanDetail.getSSID() + " provided by "
182d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu                + bestCandidate.mProvider.getConfig().getHomeSp().getFqdn());
183d6ba42b153a41a19c9ce4fb8e63abbe859ad67e9Peter Qiu        return bestCandidate;
18450f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    }
18550f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu
18650f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    private void localLog(String log) {
18717c2a7b30e5680b11fc0073ce322ee7bc14ef2c5Randy Pan        mLocalLog.log(log);
18850f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu    }
18950f36ec6fe906445db996bf3918e5cb3f170bc79Peter Qiu}
190