packages/modules/Wifi/service/java/com/android/server/wifi/WifiHelper.java

456 lines
21 KiB
Java
Executable File

package com.android.server.wifi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.net.DhcpInfo;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.MacAddress;
import android.net.KeepalivePacketData;
import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
import android.net.wifi.ScanResult;
import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiSsid;
import android.net.Uri;
import android.os.Binder;
import android.os.Process;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import com.android.modules.utils.ParceledListSlice;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
import java.net.UnknownHostException;
import java.time.Duration;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public final class WifiHelper {
private static final String TAG = "WifiHelper";
private static final String DEFAULT_SSID = "mywifi";
private static final String DEFAULT_BSSID = "02:00:00:00:00:00";
private static final String DEFAULT_MAC = "02:00:00:00:00:00"; //WifiInfo.DEFAULT_MAC_ADDRESS;
private static final String DEFAULT_IP = "192.168.100.15";
private static final String DEFAULT_IPV6 = "fe80::cd7f:1cb2:3d5c:65ed";
private static final String DEFAULT_GATEWAY = "192.168.100.1";
private static final String DEFAULT_DNS1 = "8.8.8.8";
private static final String DEFAULT_DNS2 = "8.8.4.4";
private static final int DEFAULT_HESSID = 0;
private static final int DEFAULT_ANQP_DOMAIN_ID = 0;
private static final String DEFAULT_CAPABILITIES = ""; //[WAP2-PSK-CCMP][RSN-PSK-CCMP]
private static final int DEFAULT_LEVEL = 0;
private static final int DEFAULT_FREQUENCY = 2413;
private static final int DEFAULT_DISTANCE = -1;
private static final int DEFAULT_DISTANCESD = -1;
private static final int DEFAULT_CHANNEL_WIDTH = 0;
private static final int DEFAULT_CENTER_FREQ0 = -1;
private static final int DEFAULT_CENTER_FREQ1 = -1;
private static final boolean DEFAULT_IS_80211_MCRTTRESPONDER = true;
private static final int DEFAULT_CARRIER_AP_EAP_TYPE = -1;
private static final int DEFAULT_RSSI = -50;
private static final int DEFAULT_LINKSPEED = 400;
private static final int DEFAULT_TXLINKSPEED = 400;
private static final int DEFAULT_RXLINKSPEED = 400;
private static final boolean DEFAULT_HINT = false;
private static final boolean DEFAULT_EPHEMERAL = false;
private static final boolean DEFAULT_TRUSTED = false;
private static final boolean DEFAULT_OSUAP = false;
private static final String DEFAULT_FQDN = "null";
private static final int DEFAULT_TX_BAD = 0;
private static final int DEFAULT_TX_RETRIES = 0;
private static final int DEFAULT_TX_SUCCESS = 0;
private static final int DEFAULT_RX_SUCCESS = 0;
private static final int DEFAULT_TX_BADRATE = 0;
private static final int DEFAULT_TX_RETRIES_RATE = 0;
private static final int DEFAULT_TX_SUCCESS_RATE = 0;
private static final int DEFAULT_RX_SUCCESS_RATE = 0;
private static final int DEFAULT_SCORE = 90;
private static final int DEFAULT_NET_ID = 0;
private static final String DEFAULT_SCANRESULTS =
"[{"
+ "\"SSID\":\"" + DEFAULT_SSID + "\""
+ ",\"BSSID\":\"" + DEFAULT_BSSID + "\""
+ ",\"IP\":\"" + DEFAULT_IP + "\""
+ ",\"hessid\": " + DEFAULT_HESSID
+ ",\"anqpDomainId\": " + DEFAULT_ANQP_DOMAIN_ID
+ ",\"capabilities\":\" " + DEFAULT_CAPABILITIES + "\""
+ ",\"level\":" + DEFAULT_LEVEL
+ ",\"linkSpeed\":" + DEFAULT_LINKSPEED
+ ",\"txLinkSpeed\":" + DEFAULT_TXLINKSPEED
+ ",\"rxLinkSpeed\":" + DEFAULT_RXLINKSPEED
+ ",\"frequency\":" + DEFAULT_FREQUENCY
+ ",\"distance\":" + DEFAULT_DISTANCE
+ ",\"distanceSd\":" + DEFAULT_DISTANCESD
+ ",\"channelWidth\":" + DEFAULT_CHANNEL_WIDTH
+ ",\"centerFreq0\":" + DEFAULT_CENTER_FREQ0
+ ",\"centerFreq1\":" + DEFAULT_CENTER_FREQ1
+ ",\"is80211McRTTResponder\":" + DEFAULT_IS_80211_MCRTTRESPONDER
+ "}]";
private Context mContext;
private String mLastMAC;
private String mLastSSID;
private String mLastBSSID;
private String mIpAddress;
private String mDNS1;
private String mDNS2;
private String mGateway;
private int mLastNetworkId = DEFAULT_NET_ID;
private boolean dbg = (SystemProperties.getInt("persist.sys.cloud.debug.wifi", 0) == 1);
private final WifiConfigManager mWifiConfigManager;
public WifiHelper(Context context, WifiConfigManager wifiConfigManager) {
mContext = context;
mWifiConfigManager = wifiConfigManager;
mWifiConfigManager.enableVerboseLogging(dbg);
}
private int ipToInt(String ipAddress) {
try {
InetAddress inetAddress = InetAddress.getByName(ipAddress);
byte[] addressBytes = inetAddress.getAddress();
return (addressBytes[0] & 0xFF) << 24 |
(addressBytes[1] & 0xFF) << 16 |
(addressBytes[2] & 0xFF) << 8 |
(addressBytes[3] & 0xFF);
} catch (UnknownHostException e) {
e.printStackTrace();
return 0;
}
}
private Inet4Address convertToInet4Address(String ipAddress) {
try {
int result = ipToInt(ipAddress);
byte[] ipAddressBytes = new byte[]{
(byte) ((result >> 24) & 0xFF),
(byte) ((result >> 16) & 0xFF),
(byte) ((result >> 8) & 0xFF),
(byte) (result & 0xFF)
};
InetAddress inetAddress = InetAddress.getByAddress(ipAddressBytes);
if (inetAddress instanceof Inet4Address) {
return (Inet4Address) inetAddress;
} else {
System.out.println("Not an IPv4 address");
return null;
}
} catch (UnknownHostException e) {
e.printStackTrace();
return null;
}
}
public WifiInfo getConnectionInfoFromVCloud(String callingPackage) {
String jsonString = android.provider.VCloudSettings.Global.getString(mContext.getContentResolver(), "wifi.scanresults");
if (TextUtils.isEmpty(jsonString)) {
jsonString = DEFAULT_SCANRESULTS;
}
try {
WifiInfo wifiInfo = new WifiInfo();
wifiInfo.setRequestingPackageName(callingPackage);
JSONArray jsonArray = new JSONArray(jsonString);
JSONObject jsonObject = jsonArray.getJSONObject(0);
mLastSSID = jsonObject.optString("SSID", DEFAULT_SSID);
String mock_ssid = SystemProperties.get("persist.sys.cloud.wifi.ssid");
if (null != mock_ssid && !mock_ssid.isEmpty()) {
mLastSSID = mock_ssid;
}
wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(mLastSSID));
mLastBSSID = jsonObject.optString("BSSID", DEFAULT_BSSID);
wifiInfo.setBSSID(mLastBSSID);
mLastMAC = jsonObject.optString("MAC", DEFAULT_MAC);
wifiInfo.setMacAddress(mLastMAC);
mIpAddress = jsonObject.optString("IP", DEFAULT_IP);
String mock_ipv4 = SystemProperties.get("persist.sys.cloud.wifi.ip");
if (null != mock_ipv4 && !mock_ipv4.isEmpty()) {
mIpAddress = mock_ipv4;
}
try {
wifiInfo.setInetAddress(InetAddress.getByName(mIpAddress));
} catch (UnknownHostException e) {
}
mDNS1 = jsonObject.optString("DNS1", DEFAULT_DNS1);
mDNS2 = jsonObject.optString("DNS2", DEFAULT_DNS2);
String mockDns1 = SystemProperties.get("persist.sys.cloud.wifi.dns1");
if (null != mockDns1 && !mockDns1.isEmpty()) {
mDNS1 = mockDns1;
mDNS2 = SystemProperties.get("persist.sys.cloud.wifi.dns2");
}
mGateway = jsonObject.optString("gateway", DEFAULT_GATEWAY);
String mock_gateway = SystemProperties.get("persist.sys.cloud.wifi.gateway");
if (null != mock_gateway && !mock_gateway.isEmpty()) {
mGateway = mock_gateway;
}
wifiInfo.setRssi(jsonObject.optInt("rssi", DEFAULT_RSSI));
wifiInfo.setLinkSpeed(jsonObject.optInt("linkSpeed", DEFAULT_LINKSPEED));
wifiInfo.setTxLinkSpeedMbps(jsonObject.optInt("txLinkSpeed", DEFAULT_TXLINKSPEED));
wifiInfo.setRxLinkSpeedMbps(jsonObject.optInt("rxLinkSpeed", DEFAULT_RXLINKSPEED));
wifiInfo.setMaxSupportedTxLinkSpeedMbps(jsonObject.optInt("txLinkSpeedMax", DEFAULT_TXLINKSPEED));
wifiInfo.setMaxSupportedRxLinkSpeedMbps(jsonObject.optInt("rxLinkSpeedMax", DEFAULT_RXLINKSPEED));
wifiInfo.setFrequency(jsonObject.optInt("frequency", DEFAULT_FREQUENCY));
wifiInfo.setMeteredHint(jsonObject.optBoolean("hint", DEFAULT_HINT));
wifiInfo.setEphemeral(jsonObject.optBoolean("ephemeral", DEFAULT_EPHEMERAL));
wifiInfo.setTrusted(jsonObject.optBoolean("trusted", DEFAULT_TRUSTED));
wifiInfo.setOsuAp(jsonObject.optBoolean("osuAp", DEFAULT_OSUAP));
wifiInfo.setFQDN(jsonObject.optString("fqdn", DEFAULT_FQDN));
wifiInfo.setCurrentSecurityType(WifiConfiguration.SECURITY_TYPE_OPEN);
wifiInfo.setNetworkId(mLastNetworkId);
return wifiInfo;
} catch (JSONException e){
Log.e(TAG, "update wifiInfo failed:" + e);
return null;
}
}
public List<ScanResult> ScanResultsFromVCloud() {
String jsonString = android.provider.VCloudSettings.Global.getString(mContext.getContentResolver(), "wifi.scanresults");
if (TextUtils.isEmpty(jsonString)) {
jsonString = DEFAULT_SCANRESULTS;
}
List<ScanResult> scanResults = new ArrayList<>();
try {
JSONArray jsonArray = new JSONArray(jsonString);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
ScanResult scanResult = new ScanResult();
String ssid = jsonObject.optString("SSID", DEFAULT_SSID);
String mock_ssid = SystemProperties.get("persist.sys.cloud.wifi.ssid");
if (null != mock_ssid && !mock_ssid.isEmpty()) {
ssid = mock_ssid;
}
scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(ssid);
scanResult.SSID = ssid;
scanResult.BSSID = jsonObject.optString("BSSID", DEFAULT_BSSID);
scanResult.hessid = jsonObject.optInt("hessid", DEFAULT_HESSID);
scanResult.anqpDomainId = jsonObject.optInt("anqpDomainId", DEFAULT_ANQP_DOMAIN_ID);
byte[] osuProviders = null;
scanResult.capabilities = jsonObject.optString("capabilities", DEFAULT_CAPABILITIES);
scanResult.level = jsonObject.optInt("level", DEFAULT_LEVEL);
scanResult.frequency = jsonObject.optInt("frequency", DEFAULT_FREQUENCY);
scanResult.timestamp = SystemClock.elapsedRealtimeNanos()/1000;
scanResult.distanceCm = jsonObject.optInt("distance", DEFAULT_DISTANCE);
scanResult.distanceSdCm = jsonObject.optInt("distanceSd", DEFAULT_DISTANCESD);
scanResult.channelWidth = jsonObject.optInt("channelWidth", DEFAULT_CHANNEL_WIDTH);
scanResult.centerFreq0 = jsonObject.optInt("centerFreq0", DEFAULT_CENTER_FREQ0);
scanResult.centerFreq1 = jsonObject.optInt("centerFreq1", DEFAULT_CENTER_FREQ1);
scanResult.is80211McRTTResponder = jsonObject.optBoolean("is80211McRTTResponder", DEFAULT_IS_80211_MCRTTRESPONDER);
//scanResult.carrierApEapType = jsonObject.optInt("carrierApEapType", DEFAULT_CARRIER_AP_EAP_TYPE);
if (scanResult.is80211McRTTResponder) {
scanResult.setFlag(ScanResult.FLAG_80211mc_RESPONDER);
} else {
scanResult.clearFlag(ScanResult.FLAG_80211mc_RESPONDER);
}
boolean passpoint = jsonObject.optBoolean("passpoint", false);
if (passpoint) {
scanResult.setFlag(ScanResult.FLAG_PASSPOINT_NETWORK);
} else {
scanResult.clearFlag(ScanResult.FLAG_PASSPOINT_NETWORK);
}
scanResults.add(scanResult);
break;
}
} catch (JSONException e){
Log.e(TAG, "update WifiInfo failed:" + e);
}
updateWifiConfigs(scanResults);
return scanResults;
}
public boolean startScan(String packageName, String featureId) {
if (dbg) Log.d(TAG, "startScan(" + packageName + "," + featureId + ")");
long callingIdentity = Binder.clearCallingIdentity();
Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, true);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
return true;
}
public List<ScanResult> getScanResults(String callingPackage, String callingFeatureId) {
if (dbg) Log.d(TAG, "getScanResults(" + callingPackage + "," + callingFeatureId + "), stack:" + Arrays.toString(Thread.currentThread().getStackTrace()));
List<ScanResult> results = ScanResultsFromVCloud();
if (dbg) Log.d(TAG, "ScanResults:" + results);
return results;
}
public WifiInfo getConnectionInfo(@NonNull String callingPackage, @Nullable String callingFeatureId) {
if (dbg) Log.d(TAG, "getConnectionInfo(" + callingPackage + "," + callingFeatureId + "), stack:" + Arrays.toString(Thread.currentThread().getStackTrace()));
WifiInfo wifiInfo = getConnectionInfoFromVCloud(callingPackage);
if (dbg) Log.d(TAG, "ConnectionInfo:" + wifiInfo);
return wifiInfo;
}
public ParceledListSlice<WifiConfiguration> getConfiguredNetworks(String packageName, String featureId) {
long ident = Binder.clearCallingIdentity();
try {
if (dbg) Log.d(TAG, "getConfiguredNetworks(" + packageName + "," + featureId + "), stack:" + Arrays.toString(Thread.currentThread().getStackTrace()));
List<ScanResult> scanResults = ScanResultsFromVCloud();
List<WifiConfiguration> configs = mWifiConfigManager.getSavedNetworks(Process.WIFI_UID);
if (configs.size() > 0) {
configs.get(0).networkId = mLastNetworkId;
}
if (dbg) Log.d(TAG, "configuredNetworks:" + configs);
return new ParceledListSlice<>(WifiConfigurationUtil.convertMultiTypeConfigsToLegacyConfigs(configs));
} finally {
Binder.restoreCallingIdentity(ident);
}
}
public List<PasspointConfiguration> getPasspointConfigurations(String packageName) {
if (dbg) Log.d(TAG, "getPasspointConfigurations(" + packageName + ")");
List<PasspointConfiguration> configs = new ArrayList<>();
return configs;
}
private static int ipToInteger(String ipAddress) {
if (null == ipAddress || ipAddress.isEmpty()) {
return 0;
}
String[] ipAddressArray = ipAddress.split("\\.");
if (ipAddressArray.length != 4) {
throw new IllegalArgumentException("Invalid IP address format");
}
int rs = 0;
for (int i = 0; i < 4; i++) {
int octet = Integer.parseInt(ipAddressArray[i]) << 8 * i;
rs = rs | octet;
// ipInteger = (ipInteger << 8) | octet;
}
return rs;
}
public DhcpInfo getDhcpInfo(@NonNull String packageName) {
if (dbg) Log.d(TAG, "getDhcpInfo:" + packageName);
DhcpInfo dhcpInfo = new DhcpInfo();
dhcpInfo.serverAddress = ipToInteger(mGateway);
dhcpInfo.ipAddress = ipToInteger(mIpAddress);
dhcpInfo.gateway = ipToInteger(mGateway);
dhcpInfo.dns1 = ipToInteger(mDNS1);
dhcpInfo.dns2 = ipToInteger(mDNS2);
if (dbg) Log.d(TAG, "dhcpInfo:" + dhcpInfo);
return dhcpInfo;
}
public Network getCurrentNetwork() {
if (dbg) Log.d(TAG, "getCurrentNetwork()");
Network network = new Network(mLastNetworkId, false);
if (dbg) Log.d(TAG, "network:" + network);
return network;
}
private void updateWifiConfigs(List<ScanResult> scanResults) {
List<WifiConfiguration> configs = mWifiConfigManager.getSavedNetworks(Process.WIFI_UID);
if (dbg) {
for(WifiConfiguration config: configs) {
Log.e(TAG, "updateWifiConfigs WifiConfiguration config.SSID:" + config.SSID + ", config.BSSID:" + config.BSSID);
}
for (ScanResult scanResult: scanResults) {
Log.e(TAG, "updateWifiConfigs ScanResult scanResult.SSID:" + scanResult.SSID + ", scanResult.BSSID:" + scanResult.BSSID);
}
}
if (configs.size() > 1) {
for(WifiConfiguration config: configs) {
mWifiConfigManager.removeNetwork(config.networkId, Process.WIFI_UID, "Android");
}
} else {
for(WifiConfiguration config: configs) {
boolean found = false;
for (ScanResult scanResult: scanResults) {
if (null != config.BSSID && config.BSSID.equals(scanResult.BSSID)){
found = true;
break;
}
}
if (found) {
continue;
}
mWifiConfigManager.removeNetwork(config.networkId, Process.WIFI_UID, "Android");
}
}
boolean updateFailed = false;
for (ScanResult scanResult: scanResults) {
boolean found = false;
for(WifiConfiguration config: configs) {
if (config.BSSID.equals(scanResult.BSSID)){
found = true;
break;
}
}
if (found) {
continue;
}
WifiConfiguration config = generateWifiConfig(mLastNetworkId, Process.WIFI_UID, "\"" + scanResult.SSID + "\"", true, true, null, null);
config.BSSID = scanResult.BSSID;
config.numAssociation = 2;
NetworkUpdateResult result = mWifiConfigManager.addOrUpdateNetwork(config, Process.WIFI_UID);
if (!result.isSuccess()) {
Log.e(TAG, "CONNECT_NETWORK adding/updating failed");
updateFailed = true;
continue;
}
int netId = result.getNetworkId();
mWifiConfigManager.updateNetworkSelectionStatus(netId, NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
}
}
private static WifiConfiguration generateWifiConfig(int networkId, int uid, String ssid,
boolean shared, boolean enabled, String fqdn, String providerFriendlyName) {
final WifiConfiguration config = new WifiConfiguration();
config.SSID = ssid;
config.networkId = networkId;
config.creatorUid = uid;
config.shared = shared;
config.status = enabled ? WifiConfiguration.Status.ENABLED
: WifiConfiguration.Status.DISABLED;
config.FQDN = fqdn;
config.providerFriendlyName = providerFriendlyName;
if (config.FQDN != null) {
int uniqueId = config.FQDN.hashCode() + config.networkId + config.creatorUid;
// Generate a Passpoint unique id locally for the test
config.setPasspointUniqueId(config.FQDN + "_" + uniqueId);
}
config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN);
return config;
}
}