blob: 6aee0af50de78fce15d5ffe0ed5a186f6110b37c [file] [log] [blame]
/*
* Copyright (C) 2023 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.tradefed.device;
import com.android.tradefed.log.LogUtil.CLog;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** A utility class that can parse wifi command outputs. */
public class WifiCommandUtil {
public static final Pattern SSID_PATTERN =
Pattern.compile(".*WifiInfo:.*SSID:\\s*\"([^,]*)\".*");
public static final Pattern BSSID_PATTERN = Pattern.compile(".*WifiInfo:.*BSSID:\\s*([^,]*).*");
public static final Pattern LINK_SPEED_PATTERN =
Pattern.compile(
".*WifiInfo:.*(?<!\\bTx\\s\\b|\\bRx\\s\\b)Link speed:\\s*([^,]*)Mbps.*");
public static final Pattern RSSI_PATTERN = Pattern.compile(".*WifiInfo:.*RSSI:\\s*([^,]*).*");
public static final Pattern MAC_ADDRESS_PATTERN =
Pattern.compile(".*WifiInfo:.*MAC:\\s*([^,]*).*");
/** Represents a wifi network containing its related info. */
public static class ScanResult {
private Map<String, String> scanInfo = new LinkedHashMap<>();
/** Adds an info related to the current wifi network. */
private void addInfo(String key, String value) {
scanInfo.put(key, value);
}
/** Returns the wifi network information related to the key */
public String getInfo(String infoKey) {
return scanInfo.get(infoKey);
}
@Override
public String toString() {
return scanInfo.toString();
}
}
/**
* Parse the `wifi list-scan-results` command output and returns a list of {@link ScanResult}s.
*
* @param input Output of the list-scan-results command to parse.
* @return List of {@link ScanResult}s.
*/
public static List<ScanResult> parseScanResults(String input) {
// EXAMPLE INPUT:
// BSSID Frequency RSSI Age(sec) SSID Flags
// 20:9c:b4:16:09:f2 5580 -70(0:-70/1:-79) 4.731 GoogleGuest-2 [ESS]
// 20:9c:b4:16:09:f0 5580 -69(0:-70/1:-78) 4.732 Google-A [WPA2-PSK-CCMP][ESS]
// 20:9c:b4:16:09:f1 5580 -69(0:-69/1:-78) 4.731 GoogleGuest [ESS]
if (input == null || input.isEmpty()) {
return new LinkedList<>();
}
List<ScanResult> results = new LinkedList<>();
// Figure out the column names from the first line of the output
String[] scanResultLines = input.split("\n");
String[] columnNames = scanResultLines[0].split("\\s+");
// All lines after that should be related to wifi networks
for (int i = 1; i < scanResultLines.length; i++) {
if (scanResultLines[i].trim().isEmpty()) {
continue;
}
String[] columnValues = scanResultLines[i].split("\\s+");
if (columnValues.length != columnNames.length) {
CLog.d(
"Skipping scan result since one or more of its value is undetermined:\n%s",
scanResultLines[i]);
} else {
ScanResult scanResult = new ScanResult();
for (int j = 0; j < columnNames.length; j++) {
scanResult.addInfo(columnNames[j], columnValues[j]);
}
results.add(scanResult);
}
}
return results;
}
/** Resolves the network type given the flags returned from list-scan-result cmd. */
public static String resolveNetworkType(String flags) {
if (flags.contains("WEP")) {
return "wep";
} else if (flags.contains("OWE")) {
return "owe";
} else if (flags.contains("WPA2")) {
return "wpa2";
} else if (flags.contains("SAE")) {
return "wpa3";
} else {
return "open";
}
}
/**
* Parse the 'wifi status' output and returns a map of info about connected wifi network.
*
* @param input Output of the 'wifi status' command to parse.
* @return a map of info about the connected network.
*/
public static Map<String, String> parseWifiInfo(String input) {
Map<String, String> wifiInfo = new LinkedHashMap<>();
Matcher ssidMatcher = SSID_PATTERN.matcher(input);
if (ssidMatcher.find()) {
wifiInfo.put("ssid", ssidMatcher.group(1));
}
Matcher bssidMatcher = BSSID_PATTERN.matcher(input);
if (bssidMatcher.find()) {
wifiInfo.put("bssid", bssidMatcher.group(1));
}
// TODO: also gather ip address, which is not availabled in the 'wifi status" output
Matcher linkSpeedMatcher = LINK_SPEED_PATTERN.matcher(input);
if (linkSpeedMatcher.find()) {
wifiInfo.put("linkSpeed", linkSpeedMatcher.group(1));
}
Matcher rssiMatcher = RSSI_PATTERN.matcher(input);
if (rssiMatcher.find()) {
wifiInfo.put("rssi", rssiMatcher.group(1));
}
Matcher macAddressMatcher = MAC_ADDRESS_PATTERN.matcher(input);
if (macAddressMatcher.find()) {
wifiInfo.put("macAddress", macAddressMatcher.group(1));
}
return wifiInfo;
}
}