/*
|
* Copyright (C) 2018 The Android Open Source Project
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
|
package com.android.server.wifi;
|
|
import android.net.wifi.ScanResult;
|
import android.net.wifi.WifiConfiguration;
|
import android.net.wifi.WifiEnterpriseConfig;
|
import android.os.Process;
|
import android.telephony.TelephonyManager;
|
import android.util.LocalLog;
|
|
import com.android.server.wifi.WifiNetworkSelector.NetworkEvaluator;
|
import com.android.server.wifi.util.ScanResultUtil;
|
import com.android.server.wifi.util.TelephonyUtil;
|
|
import java.util.List;
|
|
import javax.annotation.concurrent.NotThreadSafe;
|
|
/**
|
* Evaluator to select a Carrier Wi-Fi network which can be connected to. The evaluator performs
|
* two functions:
|
*
|
* 1. Filtering: figure out which of the networks is a Carrier Wi-Fi network (using the
|
* {@link CarrierNetworkConfig} APIs).
|
* 2. Evaluation: current evaluator API has 2 outputs (effectively):
|
* - Connectable networks: all networks which match #1 will be fed to this API
|
* - Selected network: a single network 'selected' by the evaluator. A simple max(RSSI) will be
|
* used to pick one network from among the connectable networks.
|
*
|
* Note: This class is not thread safe and meant to be used only from {@link WifiNetworkSelector}.
|
*/
|
@NotThreadSafe
|
public class CarrierNetworkEvaluator implements NetworkEvaluator {
|
private static final String TAG = "CarrierNetworkEvaluator";
|
|
private final WifiConfigManager mWifiConfigManager;
|
private final CarrierNetworkConfig mCarrierNetworkConfig;
|
private final LocalLog mLocalLog;
|
private final WifiInjector mWifiInjector;
|
private TelephonyManager mTelephonyManager;
|
|
public CarrierNetworkEvaluator(WifiConfigManager wifiConfigManager,
|
CarrierNetworkConfig carrierNetworkConfig, LocalLog localLog,
|
WifiInjector wifiInjector) {
|
mWifiConfigManager = wifiConfigManager;
|
mCarrierNetworkConfig = carrierNetworkConfig;
|
mLocalLog = localLog;
|
mWifiInjector = wifiInjector;
|
}
|
|
private TelephonyManager getTelephonyManager() {
|
if (mTelephonyManager == null) {
|
mTelephonyManager = mWifiInjector.makeTelephonyManager();
|
}
|
return mTelephonyManager;
|
}
|
|
@Override
|
public @EvaluatorId int getId() {
|
return EVALUATOR_ID_CARRIER;
|
}
|
|
@Override
|
public String getName() {
|
return TAG;
|
}
|
|
@Override
|
public void update(List<ScanDetail> scanDetails) {
|
// nothing to be done
|
}
|
|
@Override
|
public WifiConfiguration evaluateNetworks(List<ScanDetail> scanDetails,
|
WifiConfiguration currentNetwork, String currentBssid, boolean connected,
|
boolean untrustedNetworkAllowed, OnConnectableListener onConnectableListener) {
|
if (!mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()) {
|
return null;
|
}
|
|
int currentMaxRssi = Integer.MIN_VALUE;
|
WifiConfiguration configWithMaxRssi = null;
|
for (ScanDetail scanDetail : scanDetails) {
|
ScanResult scanResult = scanDetail.getScanResult();
|
|
if (!ScanResultUtil.isScanResultForEapNetwork(scanResult)
|
|| !mCarrierNetworkConfig.isCarrierNetwork(scanResult.SSID)) {
|
continue;
|
}
|
int eapType = mCarrierNetworkConfig.getNetworkEapType(scanResult.SSID);
|
if (!TelephonyUtil.isSimEapMethod(eapType)) {
|
mLocalLog.log(TAG + ": eapType is not a carrier eap method: " + eapType);
|
continue;
|
}
|
// If the user previously forgot this network, don't select it.
|
if (mWifiConfigManager.wasEphemeralNetworkDeleted(
|
ScanResultUtil.createQuotedSSID(scanResult.SSID))) {
|
mLocalLog.log(TAG + ": Ignoring disabled ephemeral SSID: "
|
+ WifiNetworkSelector.toScanId(scanResult));
|
continue;
|
}
|
|
WifiConfiguration config = ScanResultUtil.createNetworkFromScanResult(scanResult);
|
config.ephemeral = true;
|
if (config.enterpriseConfig == null) {
|
config.enterpriseConfig = new WifiEnterpriseConfig();
|
}
|
config.enterpriseConfig.setEapMethod(eapType);
|
|
// Check if we already have a network with the same credentials in WifiConfigManager
|
// database. If yes, we should check if the network is currently blacklisted.
|
WifiConfiguration existingNetwork =
|
mWifiConfigManager.getConfiguredNetwork(config.configKey());
|
if (existingNetwork != null
|
&& !existingNetwork.getNetworkSelectionStatus().isNetworkEnabled()
|
&& !mWifiConfigManager.tryEnableNetwork(existingNetwork.networkId)) {
|
mLocalLog.log(TAG + ": Ignoring blacklisted network: "
|
+ WifiNetworkSelector.toNetworkString(existingNetwork));
|
continue;
|
}
|
|
// Add the newly created WifiConfiguration to WifiConfigManager.
|
NetworkUpdateResult result = mWifiConfigManager.addOrUpdateNetwork(config,
|
Process.WIFI_UID);
|
if (!result.isSuccess()) {
|
mLocalLog.log(TAG + ": Failed to add carrier network: " + config);
|
continue;
|
}
|
if (!mWifiConfigManager.enableNetwork(result.getNetworkId(), false, Process.WIFI_UID)) {
|
mLocalLog.log(TAG + ": Failed to enable carrier network: " + config);
|
continue;
|
}
|
if (!mWifiConfigManager.setNetworkCandidateScanResult(result.getNetworkId(), scanResult,
|
0)) {
|
mLocalLog.log(
|
TAG + ": Failed to set network candidate for carrier network: " + config);
|
|
continue;
|
}
|
|
config = mWifiConfigManager.getConfiguredNetwork(result.getNetworkId());
|
|
WifiConfiguration.NetworkSelectionStatus nss = null;
|
if (config != null) {
|
nss = config.getNetworkSelectionStatus();
|
}
|
if (nss == null) {
|
mLocalLog.log(TAG + ": null network selection status for: " + config);
|
continue;
|
}
|
if (nss.getCandidate() != null && nss.getCandidate().level < scanResult.level) {
|
mWifiConfigManager.updateScanDetailForNetwork(result.getNetworkId(), scanDetail);
|
}
|
|
onConnectableListener.onConnectable(scanDetail, config, 0);
|
if (scanResult.level > currentMaxRssi) {
|
configWithMaxRssi = config;
|
currentMaxRssi = scanResult.level;
|
}
|
}
|
|
return configWithMaxRssi;
|
}
|
}
|