[WIFICOND] Formalize the wificond AIDL interface

The wificond daemon provides an interface for the framework to interact
with the operating system when managing Wi-Fi. Since wificond is outside
the mainline module, the AIDL interface has to be formalized as an API
surface.

Bug: 140062898
Test: atest android.net.wifi
Test: atest com.android.server.wifi.aware
Test: (CTS) atest android.net.wifi.cts
Test: scan, association, SoftAP operations manually tested, kill wificond
Change-Id: Iee0fef6a454fdd84b1d0c59516d4746ddc2a4ce5
This commit is contained in:
Etan Cohen
2019-12-18 10:54:28 -08:00
parent 0ee8fe5c09
commit 5abc6d980d
14 changed files with 998 additions and 386 deletions

View File

@@ -6208,6 +6208,130 @@ package android.net.wifi.rtt {
}
package android.net.wifi.wificond {
public final class NativeScanResult implements android.os.Parcelable {
method public int describeContents();
method @NonNull public byte[] getBssid();
method @NonNull public java.util.BitSet getCapabilities();
method public int getFrequencyMhz();
method @NonNull public byte[] getInformationElements();
method @NonNull public java.util.List<android.net.wifi.wificond.RadioChainInfo> getRadioChainInfos();
method public int getSignalMbm();
method @NonNull public byte[] getSsid();
method public long getTsf();
method public boolean isAssociated();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.NativeScanResult> CREATOR;
}
public final class NativeWifiClient implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.NativeWifiClient> CREATOR;
field @NonNull public final byte[] macAddress;
}
public final class PnoNetwork implements android.os.Parcelable {
ctor public PnoNetwork();
method public int describeContents();
method @NonNull public int[] getFrequenciesMhz();
method @NonNull public byte[] getSsid();
method public boolean isHidden();
method public void setFrequenciesMhz(@NonNull int[]);
method public void setHidden(boolean);
method public void setSsid(@NonNull byte[]);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.PnoNetwork> CREATOR;
}
public final class PnoSettings implements android.os.Parcelable {
ctor public PnoSettings();
method public int describeContents();
method public int getIntervalMillis();
method public int getMin2gRssiDbm();
method public int getMin5gRssiDbm();
method public int getMin6gRssiDbm();
method @NonNull public java.util.List<android.net.wifi.wificond.PnoNetwork> getPnoNetworks();
method public void setIntervalMillis(int);
method public void setMin2gRssiDbm(int);
method public void setMin5gRssiDbm(int);
method public void setMin6gRssiDbm(int);
method public void setPnoNetworks(@NonNull java.util.List<android.net.wifi.wificond.PnoNetwork>);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.PnoSettings> CREATOR;
}
public final class RadioChainInfo implements android.os.Parcelable {
method public int describeContents();
method public int getChainId();
method public int getLevelDbm();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.RadioChainInfo> CREATOR;
}
public class WifiCondManager {
method public void abortScan(@NonNull String);
method public void enableVerboseLogging(boolean);
method @NonNull public int[] getChannelsMhzForBand(int);
method @NonNull public java.util.List<android.net.wifi.wificond.NativeScanResult> getScanResults(@NonNull String, int);
method @Nullable public android.net.wifi.wificond.WifiCondManager.TxPacketCounters getTxPacketCounters(@NonNull String);
method public boolean initialize(@NonNull Runnable);
method public boolean registerApCallback(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiCondManager.SoftApCallback);
method public void sendMgmtFrame(@NonNull String, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiCondManager.SendMgmtFrameCallback);
method public boolean setupInterfaceForClientMode(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiCondManager.ScanEventCallback, @NonNull android.net.wifi.wificond.WifiCondManager.ScanEventCallback);
method public boolean setupInterfaceForSoftApMode(@NonNull String);
method @Nullable public android.net.wifi.wificond.WifiCondManager.SignalPollResult signalPoll(@NonNull String);
method public boolean startPnoScan(@NonNull String, @NonNull android.net.wifi.wificond.PnoSettings, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiCondManager.PnoScanRequestCallback);
method public boolean startScan(@NonNull String, int, @Nullable java.util.Set<java.lang.Integer>, @Nullable java.util.List<byte[]>);
method public boolean stopPnoScan(@NonNull String);
method public boolean tearDownClientInterface(@NonNull String);
method public boolean tearDownInterfaces();
method public boolean tearDownSoftApInterface(@NonNull String);
field public static final int SCAN_TYPE_PNO_SCAN = 1; // 0x1
field public static final int SCAN_TYPE_SINGLE_SCAN = 0; // 0x0
field public static final int SEND_MGMT_FRAME_ERROR_ALREADY_STARTED = 5; // 0x5
field public static final int SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED = 2; // 0x2
field public static final int SEND_MGMT_FRAME_ERROR_NO_ACK = 3; // 0x3
field public static final int SEND_MGMT_FRAME_ERROR_TIMEOUT = 4; // 0x4
field public static final int SEND_MGMT_FRAME_ERROR_UNKNOWN = 1; // 0x1
}
public static interface WifiCondManager.PnoScanRequestCallback {
method public void onPnoRequestFailed();
method public void onPnoRequestSucceeded();
}
public static interface WifiCondManager.ScanEventCallback {
method public void onScanFailed();
method public void onScanResultReady();
}
public static interface WifiCondManager.SendMgmtFrameCallback {
method public void onAck(int);
method public void onFailure(int);
}
public static class WifiCondManager.SignalPollResult {
field public final int associationFrequencyMHz;
field public final int currentRssiDbm;
field public final int rxBitrateMbps;
field public final int txBitrateMbps;
}
public static interface WifiCondManager.SoftApCallback {
method public void onConnectedClientsChanged(@NonNull android.net.wifi.wificond.NativeWifiClient, boolean);
method public void onFailure();
method public void onSoftApChannelSwitched(int, int);
}
public static class WifiCondManager.TxPacketCounters {
field public final int txPacketFailed;
field public final int txPacketSucceeded;
}
}
package android.nfc {
public final class NfcAdapter {

View File

@@ -24,6 +24,11 @@ ExecutorRegistration: android.net.wifi.p2p.WifiP2pManager#setWfdInfo(android.net
ExecutorRegistration: android.net.wifi.p2p.WifiP2pManager#setWifiP2pChannels(android.net.wifi.p2p.WifiP2pManager.Channel, int, int, android.net.wifi.p2p.WifiP2pManager.ActionListener):
Registration methods should have overload that accepts delivery Executor: `setWifiP2pChannels`
HeavyBitSet: android.net.wifi.wificond.NativeScanResult#getCapabilities():
Type must not be heavy BitSet (method android.net.wifi.wificond.NativeScanResult.getCapabilities())
PairedRegistration: android.net.wifi.wificond.WifiCondManager#registerApCallback(String, java.util.concurrent.Executor, android.net.wifi.wificond.WifiCondManager.SoftApCallback):
Found registerApCallback but not unregisterApCallback in android.net.wifi.wificond.WifiCondManager
GenericException: android.app.prediction.AppPredictor#finalize():

View File

@@ -120,8 +120,8 @@ import android.net.lowpan.ILowpanManager;
import android.net.lowpan.LowpanManager;
import android.net.nsd.INsdManager;
import android.net.nsd.NsdManager;
import android.net.wifi.WifiCondManager;
import android.net.wifi.WifiFrameworkInitializer;
import android.net.wifi.wificond.WifiCondManager;
import android.nfc.NfcManager;
import android.os.BatteryManager;
import android.os.BatteryStats;

View File

@@ -32,7 +32,6 @@ filegroup {
// framework-wifi.jar. This is not a good idea, should move WifiNetworkScoreCache
// to a separate package.
"java/android/net/wifi/WifiNetworkScoreCache.java",
"java/android/net/wifi/WifiCondManager.java",
"java/android/net/wifi/wificond/*.java",
":libwificond_ipc_aidl",
],

View File

@@ -16,15 +16,12 @@
package android.net.wifi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
@@ -85,26 +82,12 @@ public final class SoftApInfo implements Parcelable {
*/
public static final int CHANNEL_WIDTH_160MHZ = 6;
/**
* @hide
*/
@IntDef(prefix = { "CHANNEL_WIDTH_" }, value = {
CHANNEL_WIDTH_INVALID,
CHANNEL_WIDTH_20MHZ_NOHT,
CHANNEL_WIDTH_20MHZ,
CHANNEL_WIDTH_40MHZ,
CHANNEL_WIDTH_80MHZ,
CHANNEL_WIDTH_80MHZ_PLUS_MHZ,
CHANNEL_WIDTH_160MHZ,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Bandwidth {}
/** The frequency which AP resides on. */
private int mFrequency = 0;
@Bandwidth
@WifiAnnotations.Bandwidth
private int mBandwidth = CHANNEL_WIDTH_INVALID;
/**
@@ -127,9 +110,9 @@ public final class SoftApInfo implements Parcelable {
*
* @return One of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ},
* {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ},
* {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ} or {@link #CHANNEL_WIDTH_UNKNOWN}.
* {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ} or {@link #CHANNEL_WIDTH_INVALID}.
*/
@Bandwidth
@WifiAnnotations.Bandwidth
public int getBandwidth() {
return mBandwidth;
}
@@ -138,7 +121,7 @@ public final class SoftApInfo implements Parcelable {
* Set AP Channel bandwidth.
* @hide
*/
public void setBandwidth(@Bandwidth int bandwidth) {
public void setBandwidth(@WifiAnnotations.Bandwidth int bandwidth) {
mBandwidth = bandwidth;
}

View File

@@ -48,4 +48,16 @@ public final class WifiAnnotations {
WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY,
WifiScanner.WIFI_BAND_6_GHZ})
public @interface WifiBandBasic {}
@IntDef(prefix = { "CHANNEL_WIDTH_" }, value = {
SoftApInfo.CHANNEL_WIDTH_INVALID,
SoftApInfo.CHANNEL_WIDTH_20MHZ_NOHT,
SoftApInfo.CHANNEL_WIDTH_20MHZ,
SoftApInfo.CHANNEL_WIDTH_40MHZ,
SoftApInfo.CHANNEL_WIDTH_80MHZ,
SoftApInfo.CHANNEL_WIDTH_80MHZ_PLUS_MHZ,
SoftApInfo.CHANNEL_WIDTH_160MHZ,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Bandwidth {}
}

View File

@@ -16,46 +16,163 @@
package android.net.wifi.wificond;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
/**
* ScanResult from wificond
* Raw scan result data from the wificond daemon.
*
* @hide
*/
public class NativeScanResult implements Parcelable {
@SystemApi
public final class NativeScanResult implements Parcelable {
private static final int CAPABILITY_SIZE = 16;
/** @hide */
@VisibleForTesting
public byte[] ssid;
/** @hide */
@VisibleForTesting
public byte[] bssid;
/** @hide */
@VisibleForTesting
public byte[] infoElement;
/** @hide */
@VisibleForTesting
public int frequency;
/** @hide */
@VisibleForTesting
public int signalMbm;
/** @hide */
@VisibleForTesting
public long tsf;
/** @hide */
@VisibleForTesting
public BitSet capability;
/** @hide */
@VisibleForTesting
public boolean associated;
/** @hide */
@VisibleForTesting
public List<RadioChainInfo> radioChainInfos;
/** public constructor */
public NativeScanResult() { }
/** copy constructor */
public NativeScanResult(NativeScanResult source) {
ssid = source.ssid.clone();
bssid = source.bssid.clone();
infoElement = source.infoElement.clone();
frequency = source.frequency;
signalMbm = source.signalMbm;
tsf = source.tsf;
capability = (BitSet) source.capability.clone();
associated = source.associated;
/**
* Returns the SSID raw byte array of the AP represented by this scan result.
*
* @return A byte array.
*/
@NonNull public byte[] getSsid() {
return ssid;
}
/**
* Returns raw bytes representing the MAC address (BSSID) of the AP represented by this scan
* result.
*
* @return a byte array, possibly null or containing the incorrect number of bytes for a MAC
* address.
*/
@NonNull public byte[] getBssid() {
return bssid;
}
/**
* Returns the raw bytes of the information element advertised by the AP represented by this
* scan result.
*
* @return A byte array, possibly null or containing an invalid TLV configuration.
*/
@NonNull public byte[] getInformationElements() {
return infoElement;
}
/**
* Returns the frequency (in MHz) on which the AP represented by this scan result was observed.
*
* @return The frequency in MHz.
*/
public int getFrequencyMhz() {
return frequency;
}
/**
* Return the signal strength of probe response/beacon in (100 * dBm).
*
* @return Signal strenght in (100 * dBm).
*/
public int getSignalMbm() {
return signalMbm;
}
/**
* Return the TSF (Timing Synchronization Function) of the received probe response/beacon.
* @return
*/
public long getTsf() {
return tsf;
}
/**
* Return a boolean indicating whether or not we're associated to the AP represented by this
* scan result.
*
* @return A boolean indicating association.
*/
public boolean isAssociated() {
return associated;
}
/**
* Returns the capabilities of the AP repseresented by this scan result as advertised in the
* received probe response or beacon.
*
* This is a bit mask describing the capabilities of a BSS. See IEEE Std 802.11: 8.4.1.4:
* Bit 0 - ESS
* Bit 1 - IBSS
* Bit 2 - CF Pollable
* Bit 3 - CF-Poll Request
* Bit 4 - Privacy
* Bit 5 - Short Preamble
* Bit 6 - PBCC
* Bit 7 - Channel Agility
* Bit 8 - Spectrum Mgmt
* Bit 9 - QoS
* Bit 10 - Short Slot Time
* Bit 11 - APSD
* Bit 12 - Radio Measurement
* Bit 13 - DSSS-OFDM
* Bit 14 - Delayed Block Ack
* Bit 15 - Immediate Block Ack
*
* @return a bit mask of capabilities.
*/
@NonNull public BitSet getCapabilities() {
return capability;
}
/**
* Returns details of the signal received on each radio chain for the AP represented by this
* scan result in a list of {@link RadioChainInfo} elements.
*
* @return A list of {@link RadioChainInfo} - possibly empty in case of error.
*/
@NonNull public List<RadioChainInfo> getRadioChainInfos() {
return radioChainInfos;
}
/**
* @hide
*/
public NativeScanResult() { }
/** implement Parcelable interface */
@Override
public int describeContents() {
@@ -64,7 +181,7 @@ public class NativeScanResult implements Parcelable {
/** implement Parcelable interface */
@Override
public void writeToParcel(Parcel out, int flags) {
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeByteArray(ssid);
out.writeByteArray(bssid);
out.writeByteArray(infoElement);
@@ -83,14 +200,23 @@ public class NativeScanResult implements Parcelable {
}
/** implement Parcelable interface */
public static final Parcelable.Creator<NativeScanResult> CREATOR =
@NonNull public static final Parcelable.Creator<NativeScanResult> CREATOR =
new Parcelable.Creator<NativeScanResult>() {
@Override
public NativeScanResult createFromParcel(Parcel in) {
NativeScanResult result = new NativeScanResult();
result.ssid = in.createByteArray();
if (result.ssid == null) {
result.ssid = new byte[0];
}
result.bssid = in.createByteArray();
if (result.bssid == null) {
result.bssid = new byte[0];
}
result.infoElement = in.createByteArray();
if (result.infoElement == null) {
result.infoElement = new byte[0];
}
result.frequency = in.readInt();
result.signalMbm = in.readInt();
result.tsf = in.readLong();

View File

@@ -16,21 +16,32 @@
package android.net.wifi.wificond;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Arrays;
/**
* NativeWifiClient for wificond
* Structure providing information about clients (STAs) associated with a SoftAp.
*
* @hide
*/
public class NativeWifiClient implements Parcelable {
public byte[] macAddress;
@SystemApi
public final class NativeWifiClient implements Parcelable {
/**
* The raw bytes of the MAC address of the client (STA) represented by this object.
*/
@NonNull public final byte[] macAddress;
/** public constructor */
public NativeWifiClient() { }
/**
* public constructor
* @hide
*/
public NativeWifiClient(@NonNull byte[] macAddress) {
this.macAddress = macAddress;
}
/** override comparator */
@Override
@@ -60,18 +71,20 @@ public class NativeWifiClient implements Parcelable {
* |flag| is ignored.
*/
@Override
public void writeToParcel(Parcel out, int flags) {
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeByteArray(macAddress);
}
/** implement Parcelable interface */
public static final Parcelable.Creator<NativeWifiClient> CREATOR =
@NonNull public static final Parcelable.Creator<NativeWifiClient> CREATOR =
new Parcelable.Creator<NativeWifiClient>() {
@Override
public NativeWifiClient createFromParcel(Parcel in) {
NativeWifiClient result = new NativeWifiClient();
result.macAddress = in.createByteArray();
return result;
byte[] macAddress = in.createByteArray();
if (macAddress == null) {
macAddress = new byte[0];
}
return new NativeWifiClient(macAddress);
}
@Override

View File

@@ -16,6 +16,8 @@
package android.net.wifi.wificond;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -23,17 +25,85 @@ import java.util.Arrays;
import java.util.Objects;
/**
* PnoNetwork for wificond
* Configuration for a PNO (preferred network offload) network used in {@link PnoSettings}. A PNO
* network allows configuration of a specific network to search for.
*
* @hide
*/
public class PnoNetwork implements Parcelable {
@SystemApi
public final class PnoNetwork implements Parcelable {
private boolean mIsHidden;
private byte[] mSsid;
private int[] mFrequencies;
public boolean isHidden;
public byte[] ssid;
public int[] frequencies;
/**
* Indicates whether the PNO network configuration is for a hidden SSID - i.e. a network which
* does not broadcast its SSID and must be queried explicitly.
*
* @return True if the configuration is for a hidden network, false otherwise.
*/
public boolean isHidden() {
return mIsHidden;
}
/** public constructor */
/**
* Configure whether the PNO network configuration is for a hidden SSID - i.e. a network which
* does not broadcast its SSID and must be queried explicitly.
*
* @param isHidden True if the configuration is for a hidden network, false otherwise.
*/
public void setHidden(boolean isHidden) {
mIsHidden = isHidden;
}
/**
* Get the raw bytes for the SSID of the PNO network being scanned for.
*
* @return A byte array.
*/
@NonNull public byte[] getSsid() {
return mSsid;
}
/**
* Set the raw bytes for the SSID of the PNO network being scanned for.
*
* @param ssid A byte array.
*/
public void setSsid(@NonNull byte[] ssid) {
if (ssid == null) {
throw new IllegalArgumentException("null argument");
}
this.mSsid = ssid;
}
/**
* Get the frequencies (in MHz) on which to PNO scan for the current network is being searched
* for. A null return (i.e. no frequencies configured) indicates that the network is search for
* on all supported frequencies.
*
* @return A array of frequencies (in MHz), a null indicates no configured frequencies.
*/
@NonNull public int[] getFrequenciesMhz() {
return mFrequencies;
}
/**
* Set the frequencies (in MHz) on which to PNO scan for the current network is being searched
* for. A null configuration (i.e. no frequencies configured) indicates that the network is
* search for on all supported frequencies.
*
* @param frequenciesMhz an array of frequencies (in MHz), null indicating no configured
* frequencies.
*/
public void setFrequenciesMhz(@NonNull int[] frequenciesMhz) {
if (frequenciesMhz == null) {
throw new IllegalArgumentException("null argument");
}
this.mFrequencies = frequenciesMhz;
}
/** Construct an uninitialized PnoNetwork object */
public PnoNetwork() { }
/** override comparator */
@@ -44,18 +114,18 @@ public class PnoNetwork implements Parcelable {
return false;
}
PnoNetwork network = (PnoNetwork) rhs;
return Arrays.equals(ssid, network.ssid)
&& Arrays.equals(frequencies, network.frequencies)
&& isHidden == network.isHidden;
return Arrays.equals(mSsid, network.mSsid)
&& Arrays.equals(mFrequencies, network.mFrequencies)
&& mIsHidden == network.mIsHidden;
}
/** override hash code */
@Override
public int hashCode() {
return Objects.hash(
isHidden,
Arrays.hashCode(ssid),
Arrays.hashCode(frequencies));
mIsHidden,
Arrays.hashCode(mSsid),
Arrays.hashCode(mFrequencies));
}
/** implement Parcelable interface */
@@ -69,21 +139,27 @@ public class PnoNetwork implements Parcelable {
* |flag| is ignored.
*/
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(isHidden ? 1 : 0);
out.writeByteArray(ssid);
out.writeIntArray(frequencies);
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeInt(mIsHidden ? 1 : 0);
out.writeByteArray(mSsid);
out.writeIntArray(mFrequencies);
}
/** implement Parcelable interface */
public static final Parcelable.Creator<PnoNetwork> CREATOR =
@NonNull public static final Parcelable.Creator<PnoNetwork> CREATOR =
new Parcelable.Creator<PnoNetwork>() {
@Override
public PnoNetwork createFromParcel(Parcel in) {
PnoNetwork result = new PnoNetwork();
result.isHidden = in.readInt() != 0 ? true : false;
result.ssid = in.createByteArray();
result.frequencies = in.createIntArray();
result.mIsHidden = in.readInt() != 0 ? true : false;
result.mSsid = in.createByteArray();
if (result.mSsid == null) {
result.mSsid = new byte[0];
}
result.mFrequencies = in.createIntArray();
if (result.mFrequencies == null) {
result.mFrequencies = new int[0];
}
return result;
}

View File

@@ -16,27 +16,130 @@
package android.net.wifi.wificond;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* PnoSettings for wificond
* Configuration for a PNO (preferred network offload). A mechanism by which scans are offloaded
* from the host device to the Wi-Fi chip.
*
* @hide
*/
public class PnoSettings implements Parcelable {
public int intervalMs;
public int min2gRssi;
public int min5gRssi;
public int min6gRssi;
public ArrayList<PnoNetwork> pnoNetworks;
@SystemApi
public final class PnoSettings implements Parcelable {
private int mIntervalMs;
private int mMin2gRssi;
private int mMin5gRssi;
private int mMin6gRssi;
private List<PnoNetwork> mPnoNetworks;
/** public constructor */
/** Construct an uninitialized PnoSettings object */
public PnoSettings() { }
/**
* Get the requested PNO scan interval in milliseconds.
*
* @return An interval in milliseconds.
*/
public int getIntervalMillis() {
return mIntervalMs;
}
/**
* Set the requested PNO scan interval in milliseconds.
*
* @param intervalMs An interval in milliseconds.
*/
public void setIntervalMillis(int intervalMs) {
this.mIntervalMs = intervalMs;
}
/**
* Get the requested minimum RSSI threshold (in dBm) for APs to report in scan results in the
* 2.4GHz band.
*
* @return An RSSI value in dBm.
*/
public int getMin2gRssiDbm() {
return mMin2gRssi;
}
/**
* Set the requested minimum RSSI threshold (in dBm) for APs to report in scan scan results in
* the 2.4GHz band.
*
* @param min2gRssiDbm An RSSI value in dBm.
*/
public void setMin2gRssiDbm(int min2gRssiDbm) {
this.mMin2gRssi = min2gRssiDbm;
}
/**
* Get the requested minimum RSSI threshold (in dBm) for APs to report in scan results in the
* 5GHz band.
*
* @return An RSSI value in dBm.
*/
public int getMin5gRssiDbm() {
return mMin5gRssi;
}
/**
* Set the requested minimum RSSI threshold (in dBm) for APs to report in scan scan results in
* the 5GHz band.
*
* @param min5gRssiDbm An RSSI value in dBm.
*/
public void setMin5gRssiDbm(int min5gRssiDbm) {
this.mMin5gRssi = min5gRssiDbm;
}
/**
* Get the requested minimum RSSI threshold (in dBm) for APs to report in scan results in the
* 6GHz band.
*
* @return An RSSI value in dBm.
*/
public int getMin6gRssiDbm() {
return mMin6gRssi;
}
/**
* Set the requested minimum RSSI threshold (in dBm) for APs to report in scan scan results in
* the 6GHz band.
*
* @param min6gRssiDbm An RSSI value in dBm.
*/
public void setMin6gRssiDbm(int min6gRssiDbm) {
this.mMin6gRssi = min6gRssiDbm;
}
/**
* Return the configured list of specific networks to search for in a PNO scan.
*
* @return A list of {@link PnoNetwork} objects, possibly empty if non configured.
*/
@NonNull public List<PnoNetwork> getPnoNetworks() {
return mPnoNetworks;
}
/**
* Set the list of specified networks to scan for in a PNO scan. The networks (APs) are
* specified using {@link PnoNetwork}s. An empty list indicates that all networks are scanned
* for.
*
* @param pnoNetworks A (possibly empty) list of {@link PnoNetwork} objects.
*/
public void setPnoNetworks(@NonNull List<PnoNetwork> pnoNetworks) {
this.mPnoNetworks = pnoNetworks;
}
/** override comparator */
@Override
public boolean equals(Object rhs) {
@@ -48,17 +151,17 @@ public class PnoSettings implements Parcelable {
if (settings == null) {
return false;
}
return intervalMs == settings.intervalMs
&& min2gRssi == settings.min2gRssi
&& min5gRssi == settings.min5gRssi
&& min6gRssi == settings.min6gRssi
&& pnoNetworks.equals(settings.pnoNetworks);
return mIntervalMs == settings.mIntervalMs
&& mMin2gRssi == settings.mMin2gRssi
&& mMin5gRssi == settings.mMin5gRssi
&& mMin6gRssi == settings.mMin6gRssi
&& mPnoNetworks.equals(settings.mPnoNetworks);
}
/** override hash code */
@Override
public int hashCode() {
return Objects.hash(intervalMs, min2gRssi, min5gRssi, min6gRssi, pnoNetworks);
return Objects.hash(mIntervalMs, mMin2gRssi, mMin5gRssi, mMin6gRssi, mPnoNetworks);
}
/** implement Parcelable interface */
@@ -72,27 +175,27 @@ public class PnoSettings implements Parcelable {
* |flag| is ignored.
**/
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(intervalMs);
out.writeInt(min2gRssi);
out.writeInt(min5gRssi);
out.writeInt(min6gRssi);
out.writeTypedList(pnoNetworks);
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeInt(mIntervalMs);
out.writeInt(mMin2gRssi);
out.writeInt(mMin5gRssi);
out.writeInt(mMin6gRssi);
out.writeTypedList(mPnoNetworks);
}
/** implement Parcelable interface */
public static final Parcelable.Creator<PnoSettings> CREATOR =
@NonNull public static final Parcelable.Creator<PnoSettings> CREATOR =
new Parcelable.Creator<PnoSettings>() {
@Override
public PnoSettings createFromParcel(Parcel in) {
PnoSettings result = new PnoSettings();
result.intervalMs = in.readInt();
result.min2gRssi = in.readInt();
result.min5gRssi = in.readInt();
result.min6gRssi = in.readInt();
result.mIntervalMs = in.readInt();
result.mMin2gRssi = in.readInt();
result.mMin5gRssi = in.readInt();
result.mMin6gRssi = in.readInt();
result.pnoNetworks = new ArrayList<PnoNetwork>();
in.readTypedList(result.pnoNetworks, PnoNetwork.CREATOR);
result.mPnoNetworks = new ArrayList<>();
in.readTypedList(result.mPnoNetworks, PnoNetwork.CREATOR);
return result;
}

View File

@@ -16,26 +16,52 @@
package android.net.wifi.wificond;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
import java.util.Objects;
/**
* RadioChainInfo for wificond
* A class representing the radio chains of the Wi-Fi modems. Use to provide raw information about
* signals received on different radio chains.
*
* @hide
*/
public class RadioChainInfo implements Parcelable {
@SystemApi
public final class RadioChainInfo implements Parcelable {
private static final String TAG = "RadioChainInfo";
/** @hide */
@VisibleForTesting
public int chainId;
/** @hide */
@VisibleForTesting
public int level;
/**
* Return an identifier for this radio chain. This is an arbitrary ID which is consistent for
* the same device.
*
* @return The radio chain ID.
*/
public int getChainId() {
return chainId;
}
/** public constructor */
public RadioChainInfo() { }
/**
* Returns the detected signal level on this radio chain in dBm (aka RSSI).
*
* @return A signal level in dBm.
*/
public int getLevelDbm() {
return level;
}
/** @hide */
public RadioChainInfo(int chainId, int level) {
this.chainId = chainId;
this.level = level;
@@ -73,23 +99,20 @@ public class RadioChainInfo implements Parcelable {
* |flags| is ignored.
*/
@Override
public void writeToParcel(Parcel out, int flags) {
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeInt(chainId);
out.writeInt(level);
}
/** implement Parcelable interface */
public static final Parcelable.Creator<RadioChainInfo> CREATOR =
@NonNull public static final Parcelable.Creator<RadioChainInfo> CREATOR =
new Parcelable.Creator<RadioChainInfo>() {
/**
* Caller is responsible for providing a valid parcel.
*/
@Override
public RadioChainInfo createFromParcel(Parcel in) {
RadioChainInfo result = new RadioChainInfo();
result.chainId = in.readInt();
result.level = in.readInt();
return result;
return new RadioChainInfo(in.readInt(), in.readInt());
}
@Override

View File

@@ -14,18 +14,27 @@
* limitations under the License.
*/
package android.net.wifi;
package android.net.wifi.wificond;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.AlarmManager;
import android.content.Context;
import android.net.wifi.wificond.ChannelSettings;
import android.net.wifi.wificond.HiddenNetwork;
import android.net.wifi.wificond.NativeScanResult;
import android.net.wifi.wificond.NativeWifiClient;
import android.net.wifi.wificond.PnoSettings;
import android.net.wifi.wificond.SingleScanSettings;
import android.net.wifi.IApInterface;
import android.net.wifi.IApInterfaceEventCallback;
import android.net.wifi.IClientInterface;
import android.net.wifi.IPnoScanEvent;
import android.net.wifi.IScanEvent;
import android.net.wifi.ISendMgmtFrameEvent;
import android.net.wifi.IWifiScannerImpl;
import android.net.wifi.IWificond;
import android.net.wifi.SoftApInfo;
import android.net.wifi.WifiAnnotations;
import android.net.wifi.WifiScanner;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -44,37 +53,48 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* This class provides methods for WifiNative to send control commands to wificond.
* NOTE: This class should only be used from WifiNative.
* This class encapsulates the interface the wificond daemon presents to the Wi-Fi framework. The
* interface is only for use by the Wi-Fi framework and access is protected by SELinux permissions.
*
* @hide
*/
public class WifiCondManager implements IBinder.DeathRecipient {
@SystemApi
@SystemService(Context.WIFI_COND_SERVICE)
public class WifiCondManager {
private static final String TAG = "WifiCondManager";
private boolean mVerboseLoggingEnabled = false;
/**
* The {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()}
* The {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}
* timeout, in milliseconds, after which
* {@link SendMgmtFrameCallback#onFailure(int)} will be called with reason
* {@link #SEND_MGMT_FRAME_ERROR_TIMEOUT}.
*/
public static final int SEND_MGMT_FRAME_TIMEOUT_MS = 1000;
private static final int SEND_MGMT_FRAME_TIMEOUT_MS = 1000;
private static final String TIMEOUT_ALARM_TAG = TAG + " Send Management Frame Timeout";
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"SCAN_TYPE_"},
value = {SCAN_TYPE_SINGLE_SCAN,
SCAN_TYPE_PNO_SCAN})
public @interface ScanResultType {}
/** Get scan results for a single scan */
/**
* Specifies a scan type: single scan initiated by the framework. Can be used in
* {@link #getScanResults(String, int)} to specify the type of scan result to fetch.
*/
public static final int SCAN_TYPE_SINGLE_SCAN = 0;
/** Get scan results for Pno Scan */
/**
* Specifies a scan type: PNO scan. Can be used in {@link #getScanResults(String, int)} to
* specify the type of scan result to fetch.
*/
public static final int SCAN_TYPE_PNO_SCAN = 1;
private AlarmManager mAlarmManager;
@@ -95,11 +115,12 @@ public class WifiCondManager implements IBinder.DeathRecipient {
private AtomicBoolean mSendMgmtFrameInProgress = new AtomicBoolean(false);
/**
* Interface for a callback to be used to handle scan results.
* Interface used when waiting for scans to be completed (with results).
*/
public interface ScanEventCallback {
/**
* Called when scan results are available.
* Called when scan results are available. Scans results should then be obtained from
* {@link #getScanResults(String, int)}.
*/
void onScanResultReady();
@@ -110,11 +131,14 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
/**
* Interface for a callback to provide information about PNO scan request.
* Interface for a callback to provide information about PNO scan request requested with
* {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}. Note that the
* callback are for the status of the request - not the scan itself. The results of the scan
* are returned with {@link ScanEventCallback}.
*/
public interface PnoScanRequestCallback {
/**
* Called when the PNO scan is requested.
* Called when a PNO scan request has been successfully submitted.
*/
void onPnoRequestSucceeded();
@@ -125,73 +149,116 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
private class ScanEventHandler extends IScanEvent.Stub {
private Executor mExecutor;
private ScanEventCallback mCallback;
ScanEventHandler(@NonNull ScanEventCallback callback) {
ScanEventHandler(@NonNull Executor executor, @NonNull ScanEventCallback callback) {
mExecutor = executor;
mCallback = callback;
}
@Override
public void OnScanResultReady() {
Log.d(TAG, "Scan result ready event");
mCallback.onScanResultReady();
Binder.clearCallingIdentity();
mExecutor.execute(() -> mCallback.onScanResultReady());
}
@Override
public void OnScanFailed() {
Log.d(TAG, "Scan failed event");
mCallback.onScanFailed();
Binder.clearCallingIdentity();
mExecutor.execute(() -> mCallback.onScanFailed());
}
}
/**
* Result of a signal poll.
* Result of a signal poll requested using {@link #signalPoll(String)}.
*/
public static class SignalPollResult {
// RSSI value in dBM.
public int currentRssi;
//Transmission bit rate in Mbps.
public int txBitrate;
// Association frequency in MHz.
public int associationFrequency;
//Last received packet bit rate in Mbps.
public int rxBitrate;
/** @hide */
public SignalPollResult(int currentRssiDbm, int txBitrateMbps, int rxBitrateMbps,
int associationFrequencyMHz) {
this.currentRssiDbm = currentRssiDbm;
this.txBitrateMbps = txBitrateMbps;
this.rxBitrateMbps = rxBitrateMbps;
this.associationFrequencyMHz = associationFrequencyMHz;
}
/**
* RSSI value in dBM.
*/
public final int currentRssiDbm;
/**
* Transmission bit rate in Mbps.
*/
public final int txBitrateMbps;
/**
* Last received packet bit rate in Mbps.
*/
public final int rxBitrateMbps;
/**
* Association frequency in MHz.
*/
public final int associationFrequencyMHz;
}
/**
* WiFi interface transimission counters.
* Transmission counters obtained using {@link #getTxPacketCounters(String)}.
*/
public static class TxPacketCounters {
// Number of successfully transmitted packets.
public int txSucceeded;
// Number of tramsmission failures.
public int txFailed;
/** @hide */
public TxPacketCounters(int txPacketSucceeded, int txPacketFailed) {
this.txPacketSucceeded = txPacketSucceeded;
this.txPacketFailed = txPacketFailed;
}
/**
* Number of successfully transmitted packets.
*/
public final int txPacketSucceeded;
/**
* Number of packet transmission failures.
*/
public final int txPacketFailed;
}
/**
* Callbacks for SoftAp interface.
* Callbacks for SoftAp interface registered using
* {@link #registerApCallback(String, Executor, SoftApCallback)}.
*/
public interface SoftApListener {
public interface SoftApCallback {
/**
* Invoked when there is some fatal failure in the lower layers.
* Invoked when there is a fatal failure and the SoftAp is shutdown.
*/
void onFailure();
/**
* Invoked when the associated stations changes.
* Invoked when there is a change in the associated station (STA).
* @param client Information about the client whose status has changed.
* @param isConnected Indication as to whether the client is connected (true), or
* disconnected (false).
*/
void onConnectedClientsChanged(NativeWifiClient client, boolean isConnected);
void onConnectedClientsChanged(@NonNull NativeWifiClient client, boolean isConnected);
/**
* Invoked when the channel switch event happens.
* Invoked when a channel switch event happens - i.e. the SoftAp is moved to a different
* channel. Also called on initial registration.
* @param frequencyMhz The new frequency of the SoftAp. A value of 0 is invalid and is an
* indication that the SoftAp is not enabled.
* @param bandwidth The new bandwidth of the SoftAp.
*/
void onSoftApChannelSwitched(int frequency, int bandwidth);
void onSoftApChannelSwitched(int frequencyMhz, @WifiAnnotations.Bandwidth int bandwidth);
}
/**
* Callback to notify the results of a
* {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()} call.
* Note: no callbacks will be triggered if the iface dies while sending a frame.
* {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)} call.
* Note: no callbacks will be triggered if the interface dies while sending a frame.
*/
public interface SendMgmtFrameCallback {
/**
@@ -211,6 +278,7 @@ public class WifiCondManager implements IBinder.DeathRecipient {
void onFailure(@SendMgmtFrameError int reason);
}
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"SEND_MGMT_FRAME_ERROR_"},
value = {SEND_MGMT_FRAME_ERROR_UNKNOWN,
@@ -224,43 +292,44 @@ public class WifiCondManager implements IBinder.DeathRecipient {
/**
* Unknown error occurred during call to
* {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()}.
* {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}.
*/
public static final int SEND_MGMT_FRAME_ERROR_UNKNOWN = 1;
/**
* Specifying the MCS rate in
* {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()} is not
* {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)} is not
* supported by this device.
*/
public static final int SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED = 2;
/**
* Driver reported that no ACK was received for the frame transmitted using
* {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()}.
* {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}.
*/
public static final int SEND_MGMT_FRAME_ERROR_NO_ACK = 3;
/**
* Error code for when the driver fails to report on the status of the frame sent by
* {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()}
* {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}
* after {@link #SEND_MGMT_FRAME_TIMEOUT_MS} milliseconds.
*/
public static final int SEND_MGMT_FRAME_ERROR_TIMEOUT = 4;
/**
* An existing call to
* {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()}
* {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}
* is in progress. Another frame cannot be sent until the first call completes.
*/
public static final int SEND_MGMT_FRAME_ERROR_ALREADY_STARTED = 5;
/** @hide */
public WifiCondManager(Context context) {
mAlarmManager = (AlarmManager) context.getSystemService(AlarmManager.class);
mAlarmManager = context.getSystemService(AlarmManager.class);
mEventHandler = new Handler(context.getMainLooper());
}
/** @hide */
@VisibleForTesting
public WifiCondManager(Context context, IWificond wificond) {
this(context);
@@ -268,22 +337,26 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
private class PnoScanEventHandler extends IPnoScanEvent.Stub {
private Executor mExecutor;
private ScanEventCallback mCallback;
PnoScanEventHandler(@NonNull ScanEventCallback callback) {
PnoScanEventHandler(@NonNull Executor executor, @NonNull ScanEventCallback callback) {
mExecutor = executor;
mCallback = callback;
}
@Override
public void OnPnoNetworkFound() {
Log.d(TAG, "Pno scan result event");
mCallback.onScanResultReady();
Binder.clearCallingIdentity();
mExecutor.execute(() -> mCallback.onScanResultReady());
}
@Override
public void OnPnoScanFailed() {
Log.d(TAG, "Pno Scan failed event");
mCallback.onScanFailed();
Binder.clearCallingIdentity();
mExecutor.execute(() -> mCallback.onScanFailed());
}
}
@@ -291,9 +364,11 @@ public class WifiCondManager implements IBinder.DeathRecipient {
* Listener for AP Interface events.
*/
private class ApInterfaceEventCallback extends IApInterfaceEventCallback.Stub {
private SoftApListener mSoftApListener;
private Executor mExecutor;
private SoftApCallback mSoftApListener;
ApInterfaceEventCallback(SoftApListener listener) {
ApInterfaceEventCallback(Executor executor, SoftApCallback listener) {
mExecutor = executor;
mSoftApListener = listener;
}
@@ -304,12 +379,36 @@ public class WifiCondManager implements IBinder.DeathRecipient {
+ client.macAddress + " isConnected: " + isConnected);
}
mSoftApListener.onConnectedClientsChanged(client, isConnected);
Binder.clearCallingIdentity();
mExecutor.execute(() -> mSoftApListener.onConnectedClientsChanged(client, isConnected));
}
@Override
public void onSoftApChannelSwitched(int frequency, int bandwidth) {
mSoftApListener.onSoftApChannelSwitched(frequency, bandwidth);
Binder.clearCallingIdentity();
mExecutor.execute(() -> mSoftApListener.onSoftApChannelSwitched(frequency,
toFrameworkBandwidth(bandwidth)));
}
private @WifiAnnotations.Bandwidth int toFrameworkBandwidth(int bandwidth) {
switch(bandwidth) {
case IApInterfaceEventCallback.BANDWIDTH_INVALID:
return SoftApInfo.CHANNEL_WIDTH_INVALID;
case IApInterfaceEventCallback.BANDWIDTH_20_NOHT:
return SoftApInfo.CHANNEL_WIDTH_20MHZ_NOHT;
case IApInterfaceEventCallback.BANDWIDTH_20:
return SoftApInfo.CHANNEL_WIDTH_20MHZ;
case IApInterfaceEventCallback.BANDWIDTH_40:
return SoftApInfo.CHANNEL_WIDTH_40MHZ;
case IApInterfaceEventCallback.BANDWIDTH_80:
return SoftApInfo.CHANNEL_WIDTH_80MHZ;
case IApInterfaceEventCallback.BANDWIDTH_80P80:
return SoftApInfo.CHANNEL_WIDTH_80MHZ_PLUS_MHZ;
case IApInterfaceEventCallback.BANDWIDTH_160:
return SoftApInfo.CHANNEL_WIDTH_160MHZ;
default:
return SoftApInfo.CHANNEL_WIDTH_INVALID;
}
}
}
@@ -317,6 +416,7 @@ public class WifiCondManager implements IBinder.DeathRecipient {
* Callback triggered by wificond.
*/
private class SendMgmtFrameEvent extends ISendMgmtFrameEvent.Stub {
private Executor mExecutor;
private SendMgmtFrameCallback mCallback;
private AlarmManager.OnAlarmListener mTimeoutCallback;
/**
@@ -332,14 +432,16 @@ public class WifiCondManager implements IBinder.DeathRecipient {
r.run();
}
SendMgmtFrameEvent(@NonNull SendMgmtFrameCallback callback) {
SendMgmtFrameEvent(@NonNull Executor executor, @NonNull SendMgmtFrameCallback callback) {
mExecutor = executor;
mCallback = callback;
// called in main thread
mTimeoutCallback = () -> runIfFirstCall(() -> {
if (mVerboseLoggingEnabled) {
Log.e(TAG, "Timed out waiting for ACK");
}
mCallback.onFailure(SEND_MGMT_FRAME_ERROR_TIMEOUT);
Binder.clearCallingIdentity();
mExecutor.execute(() -> mCallback.onFailure(SEND_MGMT_FRAME_ERROR_TIMEOUT));
});
mWasCalled = false;
@@ -354,7 +456,8 @@ public class WifiCondManager implements IBinder.DeathRecipient {
// post to main thread
mEventHandler.post(() -> runIfFirstCall(() -> {
mAlarmManager.cancel(mTimeoutCallback);
mCallback.onAck(elapsedTimeMs);
Binder.clearCallingIdentity();
mExecutor.execute(() -> mCallback.onAck(elapsedTimeMs));
}));
}
@@ -364,7 +467,8 @@ public class WifiCondManager implements IBinder.DeathRecipient {
// post to main thread
mEventHandler.post(() -> runIfFirstCall(() -> {
mAlarmManager.cancel(mTimeoutCallback);
mCallback.onFailure(reason);
Binder.clearCallingIdentity();
mExecutor.execute(() -> mCallback.onFailure(reason));
}));
}
}
@@ -372,8 +476,9 @@ public class WifiCondManager implements IBinder.DeathRecipient {
/**
* Called by the binder subsystem upon remote object death.
* Invoke all the register death handlers and clear state.
* @hide
*/
@Override
@VisibleForTesting
public void binderDied() {
mEventHandler.post(() -> {
Log.e(TAG, "Wificond died!");
@@ -387,17 +492,22 @@ public class WifiCondManager implements IBinder.DeathRecipient {
});
}
/** Enable or disable verbose logging of WificondControl.
* @param enable True to enable verbose logging. False to disable verbose logging.
/**
* Enable or disable verbose logging of the WifiCondManager module.
* @param enable True to enable verbose logging. False to disable verbose logging.
*/
public void enableVerboseLogging(boolean enable) {
mVerboseLoggingEnabled = enable;
}
/**
* Initializes wificond & registers a death notification for wificond.
* This method clears any existing state in wificond daemon.
* Initializes WifiCondManager & registers a death notification for the WifiCondManager which
* acts as a proxy for the wificond daemon (i.e. the death listener will be called when and if
* the wificond daemon dies).
*
* Note: This method clears any existing state in wificond daemon.
*
* @param deathEventHandler A {@link Runnable} to be called whenever the wificond daemon dies.
* @return Returns true on success.
*/
public boolean initialize(@NonNull Runnable deathEventHandler) {
@@ -428,7 +538,7 @@ public class WifiCondManager implements IBinder.DeathRecipient {
return false;
}
try {
mWificond.asBinder().linkToDeath(this, 0);
mWificond.asBinder().linkToDeath(() -> binderDied(), 0);
} catch (RemoteException e) {
Log.e(TAG, "Failed to register death notification for wificond");
// The remote has already died.
@@ -438,16 +548,27 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
/**
* Setup interface for client mode via wificond.
* @return true on success.
*/
* Set up an interface for client (STA) mode.
*
* @param ifaceName Name of the interface to configure.
* @param executor The Executor on which to execute the callbacks.
* @param scanCallback A callback for framework initiated scans.
* @param pnoScanCallback A callback for PNO (offloaded) scans.
* @return true on success.
*/
public boolean setupInterfaceForClientMode(@NonNull String ifaceName,
@NonNull @CallbackExecutor Executor executor,
@NonNull ScanEventCallback scanCallback, @NonNull ScanEventCallback pnoScanCallback) {
Log.d(TAG, "Setting up interface for client mode");
if (!retrieveWificondAndRegisterForDeath()) {
return false;
}
if (scanCallback == null || pnoScanCallback == null || executor == null) {
Log.e(TAG, "setupInterfaceForClientMode invoked with null callbacks");
return false;
}
IClientInterface clientInterface = null;
try {
clientInterface = mWificond.createClientInterface(ifaceName);
@@ -472,10 +593,11 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
mWificondScanners.put(ifaceName, wificondScanner);
Binder.allowBlocking(wificondScanner.asBinder());
ScanEventHandler scanEventHandler = new ScanEventHandler(scanCallback);
ScanEventHandler scanEventHandler = new ScanEventHandler(executor, scanCallback);
mScanEventHandlers.put(ifaceName, scanEventHandler);
wificondScanner.subscribeScanEvents(scanEventHandler);
PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(pnoScanCallback);
PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(executor,
pnoScanCallback);
mPnoScanEventHandlers.put(ifaceName, pnoScanEventHandler);
wificondScanner.subscribePnoScanEvents(pnoScanEventHandler);
} catch (RemoteException e) {
@@ -486,8 +608,10 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
/**
* Teardown a specific STA interface configured in wificond.
* Tear down a specific client (STA) interface, initially configured using
* {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}.
*
* @param ifaceName Name of the interface to tear down.
* @return Returns true on success.
*/
public boolean tearDownClientInterface(@NonNull String ifaceName) {
@@ -531,9 +655,11 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
/**
* Setup interface for softAp mode via wificond.
* @return true on success.
*/
* Set up interface as a Soft AP.
*
* @param ifaceName Name of the interface to configure.
* @return true on success.
*/
public boolean setupInterfaceForSoftApMode(@NonNull String ifaceName) {
Log.d(TAG, "Setting up interface for soft ap mode");
if (!retrieveWificondAndRegisterForDeath()) {
@@ -560,8 +686,10 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
/**
* Teardown a specific AP interface configured in wificond.
* Tear down a Soft AP interface initially configured using
* {@link #setupInterfaceForSoftApMode(String)}.
*
* @param ifaceName Name of the interface to tear down.
* @return Returns true on success.
*/
public boolean tearDownSoftApInterface(@NonNull String ifaceName) {
@@ -592,7 +720,8 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
/**
* Teardown all interfaces configured in wificond.
* Tear down all interfaces, whether clients (STA) or Soft AP.
*
* @return Returns true on success.
*/
public boolean tearDownInterfaces() {
@@ -624,12 +753,13 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
/**
* Request signal polling to wificond.
* @param ifaceName Name of the interface.
* Returns an SignalPollResult object.
* Returns null on failure.
* Request signal polling.
*
* @param ifaceName Name of the interface on which to poll.
* @return A {@link SignalPollResult} object containing interface statistics, or a null on
* error.
*/
public SignalPollResult signalPoll(@NonNull String ifaceName) {
@Nullable public SignalPollResult signalPoll(@NonNull String ifaceName) {
IClientInterface iface = getClientInterface(ifaceName);
if (iface == null) {
Log.e(TAG, "No valid wificond client interface handler");
@@ -647,21 +777,16 @@ public class WifiCondManager implements IBinder.DeathRecipient {
Log.e(TAG, "Failed to do signal polling due to remote exception");
return null;
}
SignalPollResult pollResult = new SignalPollResult();
pollResult.currentRssi = resultArray[0];
pollResult.txBitrate = resultArray[1];
pollResult.associationFrequency = resultArray[2];
pollResult.rxBitrate = resultArray[3];
return pollResult;
return new SignalPollResult(resultArray[0], resultArray[1], resultArray[3], resultArray[2]);
}
/**
* Fetch TX packet counters on current connection from wificond.
* Get current transmit (Tx) packet counters of the specified interface.
*
* @param ifaceName Name of the interface.
* Returns an TxPacketCounters object.
* Returns null on failure.
* @return {@link TxPacketCounters} of the current interface or null on error.
*/
public TxPacketCounters getTxPacketCounters(@NonNull String ifaceName) {
@Nullable public TxPacketCounters getTxPacketCounters(@NonNull String ifaceName) {
IClientInterface iface = getClientInterface(ifaceName);
if (iface == null) {
Log.e(TAG, "No valid wificond client interface handler");
@@ -679,10 +804,7 @@ public class WifiCondManager implements IBinder.DeathRecipient {
Log.e(TAG, "Failed to do signal polling due to remote exception");
return null;
}
TxPacketCounters counters = new TxPacketCounters();
counters.txSucceeded = resultArray[0];
counters.txFailed = resultArray[1];
return counters;
return new TxPacketCounters(resultArray[0], resultArray[1]);
}
/** Helper function to look up the scanner impl handle using name */
@@ -691,10 +813,16 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
/**
* Fetch the latest scan result from kernel via wificond.
* @param ifaceName Name of the interface.
* @return Returns an array of native scan results or an empty array on failure.
*/
* Fetch the latest scan results of the indicated type for the specified interface. Note that
* this method fetches the latest results - it does not initiate a scan. Initiating a scan can
* be done using {@link #startScan(String, int, Set, List)} or
* {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}.
*
* @param ifaceName Name of the interface.
* @param scanType The type of scan result to be returned, can be
* {@link #SCAN_TYPE_SINGLE_SCAN} or {@link #SCAN_TYPE_PNO_SCAN}.
* @return Returns an array of {@link NativeScanResult} or an empty array on failure.
*/
@NonNull public List<NativeScanResult> getScanResults(@NonNull String ifaceName,
@ScanResultType int scanType) {
IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
@@ -739,15 +867,23 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
/**
* Start a scan using wificond for the given parameters.
* @param ifaceName Name of the interface.
* @param scanType Type of scan to perform.
* Start a scan using the specified parameters. A scan is an asynchronous operation. The
* result of the operation is returned in the {@link ScanEventCallback} registered when
* setting up an interface using
* {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}.
* The latest scans can be obtained using {@link #getScanResults(String, int)} and using a
* {@link #SCAN_TYPE_SINGLE_SCAN} for the {@code scanType}.
*
* @param ifaceName Name of the interface on which to initiate the scan.
* @param scanType Type of scan to perform, can be any of
* {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}, {@link WifiScanner#SCAN_TYPE_LOW_POWER}, or
* {@link WifiScanner#SCAN_TYPE_LOW_LATENCY}.
* @param freqs list of frequencies to scan for, if null scan all supported channels.
* @param hiddenNetworkSSIDs List of hidden networks to be scanned for.
* @return Returns true on success.
*/
public boolean scan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType,
Set<Integer> freqs, List<byte[]> hiddenNetworkSSIDs) {
public boolean startScan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType,
@Nullable Set<Integer> freqs, @Nullable List<byte[]> hiddenNetworkSSIDs) {
IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
if (scannerImpl == null) {
Log.e(TAG, "No valid wificond scanner interface handler");
@@ -792,25 +928,40 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
/**
* Start PNO scan.
* @param ifaceName Name of the interface.
* @param pnoSettings Pno scan configuration.
* Request a PNO (Preferred Network Offload). The offload request and the scans are asynchronous
* operations. The result of the request are returned in the {@code callback} parameter which
* is an {@link PnoScanRequestCallback}. The scan results are are return in the
* {@link ScanEventCallback} which is registered when setting up an interface using
* {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}.
* The latest PNO scans can be obtained using {@link #getScanResults(String, int)} with the
* {@code scanType} set to {@link #SCAN_TYPE_PNO_SCAN}.
*
* @param ifaceName Name of the interface on which to request a PNO.
* @param pnoSettings PNO scan configuration.
* @param executor The Executor on which to execute the callback.
* @param callback Callback for the results of the offload request.
* @return true on success.
*/
public boolean startPnoScan(@NonNull String ifaceName, PnoSettings pnoSettings,
PnoScanRequestCallback callback) {
public boolean startPnoScan(@NonNull String ifaceName, @NonNull PnoSettings pnoSettings,
@NonNull @CallbackExecutor Executor executor,
@NonNull PnoScanRequestCallback callback) {
IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
if (scannerImpl == null) {
Log.e(TAG, "No valid wificond scanner interface handler");
return false;
}
if (callback == null || executor == null) {
Log.e(TAG, "startPnoScan called with a null callback");
return false;
}
try {
boolean success = scannerImpl.startPnoScan(pnoSettings);
if (success) {
callback.onPnoRequestSucceeded();
executor.execute(callback::onPnoRequestSucceeded);
} else {
callback.onPnoRequestFailed();
executor.execute(callback::onPnoRequestFailed);
}
return success;
} catch (RemoteException e1) {
@@ -820,8 +971,10 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
/**
* Stop PNO scan.
* @param ifaceName Name of the interface.
* Stop PNO scan configured with
* {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}.
*
* @param ifaceName Name of the interface on which the PNO scan was configured.
* @return true on success.
*/
public boolean stopPnoScan(@NonNull String ifaceName) {
@@ -839,8 +992,9 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
/**
* Abort ongoing single scan.
* @param ifaceName Name of the interface.
* Abort ongoing single scan started with {@link #startScan(String, int, Set, List)}.
*
* @param ifaceName Name of the interface on which the scan was started.
*/
public void abortScan(@NonNull String ifaceName) {
IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
@@ -856,7 +1010,7 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
/**
* Query the list of valid frequencies for the provided band.
* Query the list of valid frequencies (in MHz) for the provided band.
* The result depends on the on the country code that has been set.
*
* @param band as specified by one of the WifiScanner.WIFI_BAND_* constants.
@@ -865,31 +1019,39 @@ public class WifiCondManager implements IBinder.DeathRecipient {
* WifiScanner.WIFI_BAND_5_GHZ
* WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY
* WifiScanner.WIFI_BAND_6_GHZ
* @return frequencies vector of valid frequencies (MHz), or null for error.
* @return frequencies vector of valid frequencies (MHz), or an empty array for error.
* @throws IllegalArgumentException if band is not recognized.
*/
public int [] getChannelsForBand(@WifiAnnotations.WifiBandBasic int band) {
public @NonNull int[] getChannelsMhzForBand(@WifiAnnotations.WifiBandBasic int band) {
if (mWificond == null) {
Log.e(TAG, "No valid wificond scanner interface handler");
return null;
return new int[0];
}
int[] result = null;
try {
switch (band) {
case WifiScanner.WIFI_BAND_24_GHZ:
return mWificond.getAvailable2gChannels();
result = mWificond.getAvailable2gChannels();
break;
case WifiScanner.WIFI_BAND_5_GHZ:
return mWificond.getAvailable5gNonDFSChannels();
result = mWificond.getAvailable5gNonDFSChannels();
break;
case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY:
return mWificond.getAvailableDFSChannels();
result = mWificond.getAvailableDFSChannels();
break;
case WifiScanner.WIFI_BAND_6_GHZ:
return mWificond.getAvailable6gChannels();
result = mWificond.getAvailable6gChannels();
break;
default:
throw new IllegalArgumentException("unsupported band " + band);
}
} catch (RemoteException e1) {
Log.e(TAG, "Failed to request getChannelsForBand due to remote exception");
}
return null;
if (result == null) {
result = new int[0];
}
return result;
}
/** Helper function to look up the interface handle using name */
@@ -898,22 +1060,33 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
/**
* Register the provided listener for SoftAp events.
* Register the provided callback handler for SoftAp events. Note that the Soft AP itself is
* configured using {@link #setupInterfaceForSoftApMode(String)}.
*
* @param ifaceName Name of the interface.
* @param listener Callback for AP events.
* @param ifaceName Name of the interface on which to register the callback.
* @param executor The Executor on which to execute the callbacks.
* @param callback Callback for AP events.
* @return true on success, false otherwise.
*/
public boolean registerApListener(@NonNull String ifaceName, SoftApListener listener) {
public boolean registerApCallback(@NonNull String ifaceName,
@NonNull @CallbackExecutor Executor executor,
@NonNull SoftApCallback callback) {
IApInterface iface = getApInterface(ifaceName);
if (iface == null) {
Log.e(TAG, "No valid ap interface handler");
return false;
}
if (callback == null || executor == null) {
Log.e(TAG, "registerApCallback called with a null callback");
return false;
}
try {
IApInterfaceEventCallback callback = new ApInterfaceEventCallback(listener);
mApInterfaceListeners.put(ifaceName, callback);
boolean success = iface.registerCallback(callback);
IApInterfaceEventCallback wificondCallback = new ApInterfaceEventCallback(executor,
callback);
mApInterfaceListeners.put(ifaceName, wificondCallback);
boolean success = iface.registerCallback(wificondCallback);
if (!success) {
Log.e(TAG, "Failed to register ap callback.");
return false;
@@ -926,19 +1099,28 @@ public class WifiCondManager implements IBinder.DeathRecipient {
}
/**
* See {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int)}
* Send a management frame on the specified interface at the specified rate. Useful for probing
* the link with arbitrary frames.
*
* @param ifaceName The interface on which to send the frame.
* @param frame The raw byte array of the management frame to tramit.
* @param mcs The MCS (modulation and coding scheme), i.e. rate, at which to transmit the
* frame. Specified per IEEE 802.11.
* @param executor The Executor on which to execute the callbacks.
* @param callback A {@link SendMgmtFrameCallback} callback for results of the operation.
*/
public void sendMgmtFrame(@NonNull String ifaceName, @NonNull byte[] frame,
@NonNull SendMgmtFrameCallback callback, int mcs) {
public void sendMgmtFrame(@NonNull String ifaceName, @NonNull byte[] frame, int mcs,
@NonNull @CallbackExecutor Executor executor,
@NonNull SendMgmtFrameCallback callback) {
if (callback == null) {
if (callback == null || executor == null) {
Log.e(TAG, "callback cannot be null!");
return;
}
if (frame == null) {
Log.e(TAG, "frame cannot be null!");
callback.onFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN);
executor.execute(() -> callback.onFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN));
return;
}
@@ -946,17 +1128,17 @@ public class WifiCondManager implements IBinder.DeathRecipient {
IClientInterface clientInterface = getClientInterface(ifaceName);
if (clientInterface == null) {
Log.e(TAG, "No valid wificond client interface handler");
callback.onFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN);
executor.execute(() -> callback.onFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN));
return;
}
if (!mSendMgmtFrameInProgress.compareAndSet(false, true)) {
Log.e(TAG, "An existing management frame transmission is in progress!");
callback.onFailure(SEND_MGMT_FRAME_ERROR_ALREADY_STARTED);
executor.execute(() -> callback.onFailure(SEND_MGMT_FRAME_ERROR_ALREADY_STARTED));
return;
}
SendMgmtFrameEvent sendMgmtFrameEvent = new SendMgmtFrameEvent(callback);
SendMgmtFrameEvent sendMgmtFrameEvent = new SendMgmtFrameEvent(executor, callback);
try {
clientInterface.SendMgmtFrame(frame, sendMgmtFrameEvent, mcs);
} catch (RemoteException e) {

View File

@@ -30,7 +30,7 @@ import java.util.Arrays;
import java.util.HashMap;
/**
* Unit tests for {@link android.net.wifi.wificond.PnoSettingsResult}.
* Unit tests for {@link android.net.wifi.wificond.PnoSettings}.
*/
@SmallTest
public class PnoSettingsTest {
@@ -52,14 +52,14 @@ public class PnoSettingsTest {
@Before
public void setUp() {
mPnoNetwork1 = new PnoNetwork();
mPnoNetwork1.ssid = TEST_SSID_1;
mPnoNetwork1.isHidden = true;
mPnoNetwork1.frequencies = TEST_FREQUENCIES_1;
mPnoNetwork1.setSsid(TEST_SSID_1);
mPnoNetwork1.setHidden(true);
mPnoNetwork1.setFrequenciesMhz(TEST_FREQUENCIES_1);
mPnoNetwork2 = new PnoNetwork();
mPnoNetwork2.ssid = TEST_SSID_2;
mPnoNetwork2.isHidden = false;
mPnoNetwork2.frequencies = TEST_FREQUENCIES_2;
mPnoNetwork2.setSsid(TEST_SSID_2);
mPnoNetwork2.setHidden(false);
mPnoNetwork2.setFrequenciesMhz(TEST_FREQUENCIES_2);
}
/**
@@ -69,10 +69,10 @@ public class PnoSettingsTest {
@Test
public void canSerializeAndDeserialize() {
PnoSettings pnoSettings = new PnoSettings();
pnoSettings.intervalMs = TEST_INTERVAL_MS;
pnoSettings.min2gRssi = TEST_MIN_2G_RSSI;
pnoSettings.min5gRssi = TEST_MIN_5G_RSSI;
pnoSettings.pnoNetworks = new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2));
pnoSettings.setIntervalMillis(TEST_INTERVAL_MS);
pnoSettings.setMin2gRssiDbm(TEST_MIN_2G_RSSI);
pnoSettings.setMin5gRssiDbm(TEST_MIN_5G_RSSI);
pnoSettings.setPnoNetworks(new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2)));
Parcel parcel = Parcel.obtain();
pnoSettings.writeToParcel(parcel, 0);
@@ -90,16 +90,16 @@ public class PnoSettingsTest {
@Test
public void testAsHashMapKey() {
PnoSettings pnoSettings1 = new PnoSettings();
pnoSettings1.intervalMs = TEST_INTERVAL_MS;
pnoSettings1.min2gRssi = TEST_MIN_2G_RSSI;
pnoSettings1.min5gRssi = TEST_MIN_5G_RSSI;
pnoSettings1.pnoNetworks = new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2));
pnoSettings1.setIntervalMillis(TEST_INTERVAL_MS);
pnoSettings1.setMin2gRssiDbm(TEST_MIN_2G_RSSI);
pnoSettings1.setMin5gRssiDbm(TEST_MIN_5G_RSSI);
pnoSettings1.setPnoNetworks(new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2)));
PnoSettings pnoSettings2 = new PnoSettings();
pnoSettings2.intervalMs = TEST_INTERVAL_MS;
pnoSettings2.min2gRssi = TEST_MIN_2G_RSSI;
pnoSettings2.min5gRssi = TEST_MIN_5G_RSSI;
pnoSettings2.pnoNetworks = new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2));
pnoSettings2.setIntervalMillis(TEST_INTERVAL_MS);
pnoSettings2.setMin2gRssiDbm(TEST_MIN_2G_RSSI);
pnoSettings2.setMin5gRssiDbm(TEST_MIN_5G_RSSI);
pnoSettings2.setPnoNetworks(new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2)));
assertEquals(pnoSettings1, pnoSettings2);
assertEquals(pnoSettings1.hashCode(), pnoSettings2.hashCode());

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package android.net.wifi;
package android.net.wifi.wificond;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -38,13 +38,18 @@ import static org.mockito.Mockito.when;
import android.app.AlarmManager;
import android.app.test.TestAlarmManager;
import android.content.Context;
import android.net.wifi.IApInterface;
import android.net.wifi.IApInterfaceEventCallback;
import android.net.wifi.IClientInterface;
import android.net.wifi.IPnoScanEvent;
import android.net.wifi.IScanEvent;
import android.net.wifi.ISendMgmtFrameEvent;
import android.net.wifi.IWifiScannerImpl;
import android.net.wifi.IWificond;
import android.net.wifi.SoftApInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiScanner;
import android.net.wifi.util.HexEncoding;
import android.net.wifi.wificond.ChannelSettings;
import android.net.wifi.wificond.HiddenNetwork;
import android.net.wifi.wificond.NativeWifiClient;
import android.net.wifi.wificond.PnoNetwork;
import android.net.wifi.wificond.PnoSettings;
import android.net.wifi.wificond.SingleScanSettings;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -67,7 +72,6 @@ import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -88,7 +92,7 @@ public class WifiCondManagerTest {
@Mock
private IApInterface mApInterface;
@Mock
private WifiCondManager.SoftApListener mSoftApListener;
private WifiCondManager.SoftApCallback mSoftApListener;
@Mock
private WifiCondManager.SendMgmtFrameCallback mSendMgmtFrameCallback;
@Mock
@@ -122,6 +126,7 @@ public class WifiCondManagerTest {
private static final String TEST_QUOTED_SSID_2 = "\"testSsid2\"";
private static final int[] TEST_FREQUENCIES_1 = {};
private static final int[] TEST_FREQUENCIES_2 = {2500, 5124};
private static final byte[] TEST_RAW_MAC_BYTES = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
private static final List<byte[]> SCAN_HIDDEN_NETWORK_SSID_LIST =
new ArrayList<byte[]>() {{
@@ -131,22 +136,23 @@ public class WifiCondManagerTest {
LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_2)));
}};
private static final PnoSettings TEST_PNO_SETTINGS =
new PnoSettings() {{
intervalMs = 6000;
pnoNetworks = new ArrayList<>();
PnoNetwork network = new PnoNetwork();
network.ssid = LocalNativeUtil.byteArrayFromArrayList(
LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_1));
network.isHidden = true;
network.frequencies = TEST_FREQUENCIES_1;
pnoNetworks.add(network);
network.ssid = LocalNativeUtil.byteArrayFromArrayList(
LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_2));
network.isHidden = false;
network.frequencies = TEST_FREQUENCIES_2;
pnoNetworks.add(network);
}};
private static final PnoSettings TEST_PNO_SETTINGS = new PnoSettings();
static {
TEST_PNO_SETTINGS.setIntervalMillis(6000);
List<PnoNetwork> initPnoNetworks = new ArrayList<>();
PnoNetwork network = new PnoNetwork();
network.setSsid(LocalNativeUtil.byteArrayFromArrayList(
LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_1)));
network.setHidden(true);
network.setFrequenciesMhz(TEST_FREQUENCIES_1);
initPnoNetworks.add(network);
network.setSsid(LocalNativeUtil.byteArrayFromArrayList(
LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_2)));
network.setHidden(false);
network.setFrequenciesMhz(TEST_FREQUENCIES_2);
initPnoNetworks.add(network);
TEST_PNO_SETTINGS.setPnoNetworks(initPnoNetworks);
}
private static final int TEST_MCS_RATE = 5;
private static final int TEST_SEND_MGMT_FRAME_ELAPSED_TIME_MS = 100;
@@ -180,8 +186,9 @@ public class WifiCondManagerTest {
when(mClientInterface.getWifiScannerImpl()).thenReturn(mWifiScannerImpl);
when(mClientInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
mWificondControl = new WifiCondManager(mContext, mWificond);
assertEquals(true, mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME,
mNormalScanCallback, mPnoScanCallback));
assertEquals(true,
mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, Runnable::run,
mNormalScanCallback, mPnoScanCallback));
}
/**
@@ -264,7 +271,7 @@ public class WifiCondManagerTest {
assertNull(mWificondControl.signalPoll(TEST_INTERFACE_NAME));
verify(mClientInterface, never()).signalPoll();
assertFalse(mWificondControl.scan(
assertFalse(mWificondControl.startScan(
TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_LATENCY,
SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
verify(mWifiScannerImpl, never()).scan(any());
@@ -348,8 +355,8 @@ public class WifiCondManagerTest {
public void testTeardownSoftApInterfaceClearsHandles() throws Exception {
testTeardownSoftApInterface();
assertFalse(mWificondControl.registerApListener(
TEST_INTERFACE_NAME, mSoftApListener));
assertFalse(mWificondControl.registerApCallback(
TEST_INTERFACE_NAME, Runnable::run, mSoftApListener));
verify(mApInterface, never()).registerCallback(any());
}
@@ -417,8 +424,8 @@ public class WifiCondManagerTest {
public void testSignalPoll() throws Exception {
when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, mNormalScanCallback,
mPnoScanCallback);
mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, Runnable::run,
mNormalScanCallback, mPnoScanCallback);
mWificondControl.signalPoll(TEST_INTERFACE_NAME);
verify(mClientInterface).signalPoll();
}
@@ -432,7 +439,7 @@ public class WifiCondManagerTest {
// Configure client interface.
assertEquals(true, mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME,
mNormalScanCallback, mPnoScanCallback));
Runnable::run, mNormalScanCallback, mPnoScanCallback));
// Tear down interfaces.
assertTrue(mWificondControl.tearDownInterfaces());
@@ -448,8 +455,8 @@ public class WifiCondManagerTest {
public void testGetTxPacketCounters() throws Exception {
when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, mNormalScanCallback,
mPnoScanCallback);
mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, Runnable::run,
mNormalScanCallback, mPnoScanCallback);
mWificondControl.getTxPacketCounters(TEST_INTERFACE_NAME);
verify(mClientInterface).getPacketCounters();
}
@@ -464,7 +471,7 @@ public class WifiCondManagerTest {
// Configure client interface.
assertEquals(true, mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME,
mNormalScanCallback, mPnoScanCallback));
Runnable::run, mNormalScanCallback, mPnoScanCallback));
// Tear down interfaces.
assertTrue(mWificondControl.tearDownInterfaces());
@@ -483,7 +490,7 @@ public class WifiCondManagerTest {
// Configure client interface.
assertEquals(true, mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME,
mNormalScanCallback, mPnoScanCallback));
Runnable::run, mNormalScanCallback, mPnoScanCallback));
// Tear down interfaces.
assertTrue(mWificondControl.tearDownInterfaces());
@@ -500,7 +507,7 @@ public class WifiCondManagerTest {
@Test
public void testScan() throws Exception {
when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
assertTrue(mWificondControl.scan(
assertTrue(mWificondControl.startScan(
TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_POWER,
SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
@@ -520,7 +527,7 @@ public class WifiCondManagerTest {
assertEquals(hiddenSsidWithDup.get(0),
hiddenSsidWithDup.get(hiddenSsidWithDup.size() - 1));
// Pass the List with duplicate elements into scan()
assertTrue(mWificondControl.scan(
assertTrue(mWificondControl.startScan(
TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_POWER,
SCAN_FREQ_SET, hiddenSsidWithDup));
// But the argument passed down should have the duplicate removed.
@@ -535,7 +542,7 @@ public class WifiCondManagerTest {
@Test
public void testScanNullParameters() throws Exception {
when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
assertTrue(mWificondControl.scan(
assertTrue(mWificondControl.startScan(
TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_HIGH_ACCURACY, null, null));
verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY, null, null)));
@@ -547,7 +554,7 @@ public class WifiCondManagerTest {
@Test
public void testScanFailure() throws Exception {
when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(false);
assertFalse(mWificondControl.scan(
assertFalse(mWificondControl.startScan(
TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_LATENCY,
SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
verify(mWifiScannerImpl).scan(any(SingleScanSettings.class));
@@ -558,7 +565,7 @@ public class WifiCondManagerTest {
*/
@Test
public void testScanFailureDueToInvalidType() throws Exception {
assertFalse(mWificondControl.scan(
assertFalse(mWificondControl.startScan(
TEST_INTERFACE_NAME, 100,
SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
verify(mWifiScannerImpl, never()).scan(any(SingleScanSettings.class));
@@ -570,9 +577,10 @@ public class WifiCondManagerTest {
@Test
public void testStartPnoScan() throws Exception {
when(mWifiScannerImpl.startPnoScan(any(PnoSettings.class))).thenReturn(true);
assertTrue(mWificondControl.startPnoScan(TEST_INTERFACE_NAME, TEST_PNO_SETTINGS,
mPnoScanRequestCallback));
verify(mWifiScannerImpl).startPnoScan(argThat(new PnoScanMatcher(TEST_PNO_SETTINGS)));
assertTrue(
mWificondControl.startPnoScan(TEST_INTERFACE_NAME, TEST_PNO_SETTINGS, Runnable::run,
mPnoScanRequestCallback));
verify(mWifiScannerImpl).startPnoScan(eq(TEST_PNO_SETTINGS));
verify(mPnoScanRequestCallback).onPnoRequestSucceeded();
}
@@ -665,8 +673,9 @@ public class WifiCondManagerTest {
public void testStartPnoScanForMetrics() throws Exception {
when(mWifiScannerImpl.startPnoScan(any(PnoSettings.class))).thenReturn(false);
assertFalse(mWificondControl.startPnoScan(TEST_INTERFACE_NAME, TEST_PNO_SETTINGS,
mPnoScanRequestCallback));
assertFalse(
mWificondControl.startPnoScan(TEST_INTERFACE_NAME, TEST_PNO_SETTINGS, Runnable::run,
mPnoScanRequestCallback));
verify(mPnoScanRequestCallback).onPnoRequestFailed();
}
@@ -695,11 +704,11 @@ public class WifiCondManagerTest {
final ArgumentCaptor<IApInterfaceEventCallback> apInterfaceCallbackCaptor =
ArgumentCaptor.forClass(IApInterfaceEventCallback.class);
assertTrue(mWificondControl.registerApListener(
TEST_INTERFACE_NAME, mSoftApListener));
assertTrue(mWificondControl.registerApCallback(
TEST_INTERFACE_NAME, Runnable::run, mSoftApListener));
verify(mApInterface).registerCallback(apInterfaceCallbackCaptor.capture());
final NativeWifiClient testClient = new NativeWifiClient();
final NativeWifiClient testClient = new NativeWifiClient(TEST_RAW_MAC_BYTES);
apInterfaceCallbackCaptor.getValue().onConnectedClientsChanged(testClient, true);
verify(mSoftApListener).onConnectedClientsChanged(eq(testClient), eq(true));
@@ -707,7 +716,8 @@ public class WifiCondManagerTest {
int channelBandwidth = IApInterfaceEventCallback.BANDWIDTH_20;
apInterfaceCallbackCaptor.getValue().onSoftApChannelSwitched(channelFrequency,
channelBandwidth);
verify(mSoftApListener).onSoftApChannelSwitched(eq(channelFrequency), eq(channelBandwidth));
verify(mSoftApListener).onSoftApChannelSwitched(eq(channelFrequency),
eq(SoftApInfo.CHANNEL_WIDTH_20MHZ));
}
/**
@@ -739,7 +749,7 @@ public class WifiCondManagerTest {
verify(deathHandler).run();
// The handles should be cleared after death.
assertNull(mWificondControl.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ));
assertEquals(0, mWificondControl.getChannelsMhzForBand(WifiScanner.WIFI_BAND_5_GHZ).length);
verify(mWificond, never()).getAvailable5gNonDFSChannels();
}
@@ -748,7 +758,8 @@ public class WifiCondManagerTest {
*/
@Test
public void testSendMgmtFrameNullCallback() throws Exception {
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, null, TEST_MCS_RATE);
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
Runnable::run, null);
verify(mClientInterface, never()).SendMgmtFrame(any(), any(), anyInt());
}
@@ -758,8 +769,8 @@ public class WifiCondManagerTest {
*/
@Test
public void testSendMgmtFrameNullFrame() throws Exception {
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, null,
mSendMgmtFrameCallback, TEST_MCS_RATE);
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, null, TEST_MCS_RATE, Runnable::run,
mSendMgmtFrameCallback);
verify(mClientInterface, never()).SendMgmtFrame(any(), any(), anyInt());
verify(mSendMgmtFrameCallback).onFailure(anyInt());
@@ -770,8 +781,8 @@ public class WifiCondManagerTest {
*/
@Test
public void testSendMgmtFrameInvalidInterfaceName() throws Exception {
mWificondControl.sendMgmtFrame(TEST_INVALID_INTERFACE_NAME, TEST_PROBE_FRAME,
mSendMgmtFrameCallback, TEST_MCS_RATE);
mWificondControl.sendMgmtFrame(TEST_INVALID_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
Runnable::run, mSendMgmtFrameCallback);
verify(mClientInterface, never()).SendMgmtFrame(any(), any(), anyInt());
verify(mSendMgmtFrameCallback).onFailure(anyInt());
@@ -787,13 +798,15 @@ public class WifiCondManagerTest {
WifiCondManager.SendMgmtFrameCallback cb2 = mock(
WifiCondManager.SendMgmtFrameCallback.class);
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, cb1, TEST_MCS_RATE);
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
Runnable::run, cb1);
verify(cb1, never()).onFailure(anyInt());
verify(mClientInterface, times(1))
.SendMgmtFrame(AdditionalMatchers.aryEq(TEST_PROBE_FRAME),
any(), eq(TEST_MCS_RATE));
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, cb2, TEST_MCS_RATE);
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
Runnable::run, cb2);
verify(cb2).onFailure(WifiCondManager.SEND_MGMT_FRAME_ERROR_ALREADY_STARTED);
// verify SendMgmtFrame() still was only called once i.e. not called again
verify(mClientInterface, times(1))
@@ -820,8 +833,8 @@ public class WifiCondManagerTest {
doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
alarmListenerCaptor.capture(), handlerCaptor.capture());
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME,
cb, TEST_MCS_RATE);
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
Runnable::run, cb);
mLooper.dispatchAll();
verify(cb).onFailure(anyInt());
@@ -854,7 +867,8 @@ public class WifiCondManagerTest {
final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
alarmListenerCaptor.capture(), handlerCaptor.capture());
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, cb, TEST_MCS_RATE);
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
Runnable::run, cb);
sendMgmtFrameEventCaptor.getValue().OnAck(TEST_SEND_MGMT_FRAME_ELAPSED_TIME_MS);
mLooper.dispatchAll();
@@ -887,7 +901,8 @@ public class WifiCondManagerTest {
final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
alarmListenerCaptor.capture(), handlerCaptor.capture());
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, cb, TEST_MCS_RATE);
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
Runnable::run, cb);
sendMgmtFrameEventCaptor.getValue().OnFailure(
WifiCondManager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
@@ -921,7 +936,8 @@ public class WifiCondManagerTest {
final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
alarmListenerCaptor.capture(), handlerCaptor.capture());
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, cb, TEST_MCS_RATE);
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
Runnable::run, cb);
handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
mLooper.dispatchAll();
@@ -987,8 +1003,8 @@ public class WifiCondManagerTest {
final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
alarmListenerCaptor.capture(), handlerCaptor.capture());
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME,
mSendMgmtFrameCallback, TEST_MCS_RATE);
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
Runnable::run, mSendMgmtFrameCallback);
// AlarmManager should post the onAlarm() callback onto the handler, but since we are
// triggering onAlarm() ourselves during the test, manually post onto handler
@@ -1015,8 +1031,8 @@ public class WifiCondManagerTest {
final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
alarmListenerCaptor.capture(), handlerCaptor.capture());
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME,
mSendMgmtFrameCallback, TEST_MCS_RATE);
mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
Runnable::run, mSendMgmtFrameCallback);
// AlarmManager should post the onAlarm() callback onto the handler, but since we are
// triggering onAlarm() ourselves during the test, manually post onto handler
@@ -1086,56 +1102,6 @@ public class WifiCondManagerTest {
}
}
// Create a ArgumentMatcher which captures a PnoSettings parameter and checks if it
// matches the WifiNative.PnoSettings;
private class PnoScanMatcher implements ArgumentMatcher<PnoSettings> {
private final PnoSettings mExpectedPnoSettings;
PnoScanMatcher(PnoSettings expectedPnoSettings) {
this.mExpectedPnoSettings = expectedPnoSettings;
}
@Override
public boolean matches(PnoSettings settings) {
if (mExpectedPnoSettings == null) {
return false;
}
if (settings.intervalMs != mExpectedPnoSettings.intervalMs
|| settings.min2gRssi != mExpectedPnoSettings.min2gRssi
|| settings.min5gRssi != mExpectedPnoSettings.min5gRssi
|| settings.min6gRssi != mExpectedPnoSettings.min6gRssi) {
return false;
}
if (settings.pnoNetworks == null || mExpectedPnoSettings.pnoNetworks == null) {
return false;
}
if (settings.pnoNetworks.size() != mExpectedPnoSettings.pnoNetworks.size()) {
return false;
}
for (int i = 0; i < settings.pnoNetworks.size(); i++) {
if (!Arrays.equals(settings.pnoNetworks.get(i).ssid,
mExpectedPnoSettings.pnoNetworks.get(i).ssid)) {
return false;
}
if (settings.pnoNetworks.get(i).isHidden != mExpectedPnoSettings.pnoNetworks.get(
i).isHidden) {
return false;
}
if (!Arrays.equals(settings.pnoNetworks.get(i).frequencies,
mExpectedPnoSettings.pnoNetworks.get(i).frequencies)) {
return false;
}
}
return true;
}
@Override
public String toString() {
return "PnoScanMatcher{" + "mExpectedPnoSettings=" + mExpectedPnoSettings + '}';
}
}
private static class LocalNativeUtil {
private static final int SSID_BYTES_MAX_LEN = 32;