diff --git a/api/system-current.txt b/api/system-current.txt index d67305da00d2e..4454f6f86c65f 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -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 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 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 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 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 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); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator 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 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 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, @Nullable java.util.List); + 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 { diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt index 9a6357572d36e..da0aae0f14ad9 100644 --- a/api/system-lint-baseline.txt +++ b/api/system-lint-baseline.txt @@ -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(): diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index ce21db3356157..98337c9cce9ea 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -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; diff --git a/wifi/Android.bp b/wifi/Android.bp index 08115ecb6b2b4..fb1f8661370bd 100644 --- a/wifi/Android.bp +++ b/wifi/Android.bp @@ -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", ], diff --git a/wifi/java/android/net/wifi/SoftApInfo.java b/wifi/java/android/net/wifi/SoftApInfo.java index 375a9774f570e..24ed8effe471a 100644 --- a/wifi/java/android/net/wifi/SoftApInfo.java +++ b/wifi/java/android/net/wifi/SoftApInfo.java @@ -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; } diff --git a/wifi/java/android/net/wifi/WifiAnnotations.java b/wifi/java/android/net/wifi/WifiAnnotations.java index 4a7dee138971e..9223d28836b6b 100644 --- a/wifi/java/android/net/wifi/WifiAnnotations.java +++ b/wifi/java/android/net/wifi/WifiAnnotations.java @@ -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 {} } diff --git a/wifi/java/android/net/wifi/wificond/NativeScanResult.java b/wifi/java/android/net/wifi/wificond/NativeScanResult.java index ff8e935da8c04..6ed17081bdb56 100644 --- a/wifi/java/android/net/wifi/wificond/NativeScanResult.java +++ b/wifi/java/android/net/wifi/wificond/NativeScanResult.java @@ -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 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 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 CREATOR = + @NonNull public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @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(); diff --git a/wifi/java/android/net/wifi/wificond/NativeWifiClient.java b/wifi/java/android/net/wifi/wificond/NativeWifiClient.java index 4994ebd332167..554f9295ef0db 100644 --- a/wifi/java/android/net/wifi/wificond/NativeWifiClient.java +++ b/wifi/java/android/net/wifi/wificond/NativeWifiClient.java @@ -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 CREATOR = + @NonNull public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @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 diff --git a/wifi/java/android/net/wifi/wificond/PnoNetwork.java b/wifi/java/android/net/wifi/wificond/PnoNetwork.java index f923fd384a90a..ca0b1cfb62235 100644 --- a/wifi/java/android/net/wifi/wificond/PnoNetwork.java +++ b/wifi/java/android/net/wifi/wificond/PnoNetwork.java @@ -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 CREATOR = + @NonNull public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @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; } diff --git a/wifi/java/android/net/wifi/wificond/PnoSettings.java b/wifi/java/android/net/wifi/wificond/PnoSettings.java index 96cf24fdfb81e..57c9ca5fd3024 100644 --- a/wifi/java/android/net/wifi/wificond/PnoSettings.java +++ b/wifi/java/android/net/wifi/wificond/PnoSettings.java @@ -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 pnoNetworks; +@SystemApi +public final class PnoSettings implements Parcelable { + private int mIntervalMs; + private int mMin2gRssi; + private int mMin5gRssi; + private int mMin6gRssi; + private List 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 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 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 CREATOR = + @NonNull public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @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(); - in.readTypedList(result.pnoNetworks, PnoNetwork.CREATOR); + result.mPnoNetworks = new ArrayList<>(); + in.readTypedList(result.mPnoNetworks, PnoNetwork.CREATOR); return result; } diff --git a/wifi/java/android/net/wifi/wificond/RadioChainInfo.java b/wifi/java/android/net/wifi/wificond/RadioChainInfo.java index 2b03450b13572..64102dde94c06 100644 --- a/wifi/java/android/net/wifi/wificond/RadioChainInfo.java +++ b/wifi/java/android/net/wifi/wificond/RadioChainInfo.java @@ -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 CREATOR = + @NonNull public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { /** * 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 diff --git a/wifi/java/android/net/wifi/WifiCondManager.java b/wifi/java/android/net/wifi/wificond/WifiCondManager.java similarity index 61% rename from wifi/java/android/net/wifi/WifiCondManager.java rename to wifi/java/android/net/wifi/wificond/WifiCondManager.java index c05ba347ab5cc..94f1212da0a0c 100644 --- a/wifi/java/android/net/wifi/WifiCondManager.java +++ b/wifi/java/android/net/wifi/wificond/WifiCondManager.java @@ -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 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 freqs, List hiddenNetworkSSIDs) { + public boolean startScan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType, + @Nullable Set freqs, @Nullable List 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) { diff --git a/wifi/tests/src/android/net/wifi/wificond/PnoSettingsTest.java b/wifi/tests/src/android/net/wifi/wificond/PnoSettingsTest.java index 775acc70d1342..9439c796e1a51 100644 --- a/wifi/tests/src/android/net/wifi/wificond/PnoSettingsTest.java +++ b/wifi/tests/src/android/net/wifi/wificond/PnoSettingsTest.java @@ -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()); diff --git a/wifi/tests/src/android/net/wifi/WifiCondManagerTest.java b/wifi/tests/src/android/net/wifi/wificond/WifiCondManagerTest.java similarity index 90% rename from wifi/tests/src/android/net/wifi/WifiCondManagerTest.java rename to wifi/tests/src/android/net/wifi/wificond/WifiCondManagerTest.java index 48a9afa1d961f..68e53362100dd 100644 --- a/wifi/tests/src/android/net/wifi/WifiCondManagerTest.java +++ b/wifi/tests/src/android/net/wifi/wificond/WifiCondManagerTest.java @@ -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 SCAN_HIDDEN_NETWORK_SSID_LIST = new ArrayList() {{ @@ -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 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 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 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 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 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 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 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 { - 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;