blob: 52d7d18449ebd08b151045ba5d79f631d757a059 [file] [log] [blame]
/*
* 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;
}
}